All Tonder API responses follow a consistent structure, providing standardized information regardless of the operation type (payment or withdrawal). This consistency simplifies integration and error handling across different transaction types.

Standard Response Structure

All successful requests return a consistent response format:
{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "operation_type": "payment",
  "status": "authorized",
  "amount": 150.00,
  "currency": "MXN",
  "client_reference": "order-789",
  "payment_id": 12345,
  "transaction_id": "txn_abc123",
  "provider": "stripe",
  "created_at": "2024-07-26T10:30:00Z",
  "status_code": 201
}
Where:
FieldTypeDescription
idstringUnique transaction identifier (UUID)
operation_typestring"payment" or "withdrawal"
statusstringCurrent transaction status
amountdecimalTransaction amount
currencystringCurrency code (e.g., "MXN", "USD")
client_referencestringYour reference identifier
created_atstringISO 8601 timestamp of creation
status_codeintegerHTTP status code

Transaction Status Values

The status field can have the following values:
StatusLabelDescriptionNext Steps
pendingPendingTransaction awaiting completionCheck status or wait for webhook
on_holdOn holdTransaction temporarily heldWait for review completion
processingProcessingTransaction being processedMonitor for completion
sent_to_providerSent to providerSent to payment providerMonitor for completion
successSuccessTransaction successfully completedTransaction complete
paid_fullPaid in fullPayment completed in fullTransaction complete
in_transitIn transitPayment in transit to destinationMonitor for completion
canceledCanceledTransaction was cancelledNo further action required
declinedDeclinedPayment declined by provider or issuerTry different payment method
rejectedRejectedTransaction was rejectedTry different payment method
failedFailedTransaction processing failedCheck error details and retry
UnknownUnknownStatus cannot be determinedContact support for clarification
expiredExpiredTransaction or authorization expiredCreate new transaction if needed
authorizedAuthorizedPayment authorized (cards only)Transaction complete

Payment Response Examples

Here are some examples of payment responses.

Next Action Handling

Some transactions require additional steps (3D Secure, redirects, iframe interactions). The next_action object will contain specific instructions for handling these scenarios. Here are some examples of responses that require additional action.

Payment Instructions Response

For cash payment methods (OXXO, SafetyPay), the response includes detailed payment instructions:
{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "operation_type": "payment",
  "status": "pending",
  "amount": 250.00,
  "currency": "MXN",
  "payment_instructions": {
    "reference_code": "99900012345678",
    "barcode": "||99900012345678||",
    "store_name": "OXXO",
    "expiration_date": "2024-07-29T23:59:59Z",
    "instructions": [
      "Acude a cualquier tienda OXXO",
      "Presenta este código de barras en caja",
      "Paga exactamente $250.00 MXN en efectivo"
    ]
  },
  "voucher_pdf": "https://api.tonder.io/vouchers/abc123.pdf",
  "created_at": "2024-07-26T10:30:00Z",
  "status_code": 201
}

Payment Instructions Fields

The following table lists the fields that are included in the payment_instructions object.
FieldTypeDescription
reference_codestringPayment reference for cash payment
barcodestringBarcode representation
store_namestringStore chain name (e.g., “OXXO”)
expiration_datestringPayment expiration timestamp
instructionsarrayStep-by-step payment instructions
voucher_pdfstringURL to downloadable payment voucher

HTTP Status Codes

The following tables lists the HTTP status codes that are returned by the API.

Success Codes

CodeDescriptionWhen Used
200OKStatus check successful
201CreatedTransaction created successfully
202AcceptedTransaction accepted, requires additional action

Client Error Codes

CodeDescriptionAction Required
400Bad RequestFix request format
401UnauthorizedCheck authentication
402Payment RequiredPayment declined
404Not FoundCheck transaction ID
422Validation ErrorFix request data
429Rate LimitedRetry with backoff

Server Error Codes

CodeDescriptionAction Required
500Internal Server ErrorRetry request
502Bad GatewayRetry request
503Service UnavailableRetry later

Response Headers

All responses include standard headers for debugging and rate limiting:
HTTP/1.1 201 Created
Content-Type: application/json
X-Request-ID: req_abc123
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 95
X-RateLimit-Reset: 1640995200
The following table provides a description of the headers that are included in the response.
HeaderDescription
X-Request-IDUnique request identifier for debugging
X-RateLimit-LimitRequest limit per window
X-RateLimit-RemainingRequests remaining in current window
X-RateLimit-ResetUnix timestamp when limit resets

Error Response Format

When requests fail, errors follow a consistent format:
{
  "error": {
    "code": "validation_error",
    "message": "Amount must be greater than 0",
    "type": "request_error",
    "details": {
      "field": "amount",
      "received_value": -10.00
    }
  },
  "request_id": "req_abc123"
}
Where:
FieldTypeDescription
error.codestringSpecific error code
error.messagestringHuman-readable error message
error.typestringError category
error.detailsobjectAdditional error context
request_idstringRequest identifier for support

Implementation Examples

Here are some examples of how to handle responses in different programming languages.
def handle_transaction_response(response):
    """Handle Tonder API response"""
    
    if response.status_code in [200, 201, 202]:
        data = response.json()
        
        # Check if additional action is required
        if 'next_action' in data:
            return handle_next_action(data)
        
        # Check for payment instructions
        if 'payment_instructions' in data:
            return handle_payment_instructions(data)
        
        # Standard successful response
        return {
            'success': True,
            'transaction_id': data['id'],
            'status': data['status'],
            'amount': data['amount']
        }
    
    else:
        # Handle error response
        error_data = response.json()
        return {
            'success': False,
            'error_code': error_data['error']['code'],
            'error_message': error_data['error']['message'],
            'request_id': error_data.get('request_id')
        }

def handle_next_action(response_data):
    """Handle responses requiring additional action"""
    
    next_action = response_data['next_action']
    
    if 'redirect_to_url' in next_action:
        # 3DS redirect required
        return {
            'success': True,
            'requires_action': True,
            'action_type': 'redirect',
            'redirect_url': next_action['redirect_to_url']['url'],
            'return_url': next_action['redirect_to_url']['return_url']
        }
    
    elif 'iframe_resources' in next_action:
        # Iframe authentication required
        return {
            'success': True,
            'requires_action': True,
            'action_type': 'iframe',
            'iframe_url': next_action['iframe_resources']['external_resource_url']
        }
    
    return {'success': False, 'error': 'Unknown next action'}

def handle_payment_instructions(response_data):
    """Handle cash payment instructions"""
    
    instructions = response_data['payment_instructions']
    
    return {
        'success': True,
        'requires_cash_payment': True,
        'reference_code': instructions['reference_code'],
        'store_name': instructions['store_name'],
        'expiration_date': instructions['expiration_date'],
        'voucher_pdf': response_data.get('voucher_pdf'),
        'instructions': instructions['instructions']
    }

Best Practices

Make sure to follow these best practices to handle responses properly.

Next Steps