Your First Transaction

This guide will walk you through making your first payment using Tonder’s Direct API in the sandbox (also referred as stage) environment.

Prerequisites

Before you begin, make sure you have the following:
  1. Tonder account credentials to sign in at app.tonder.io
  2. API key and secret from your developer dashboard
  3. Basic understanding of REST APIs and HTTP requests

Step 1: Set Up Your Environment

Use the sandbox environment for testing all features without processing real transactions. Use the base URL below when making requests.
Base URL
https://stage.tonder.io/api/v1/

Required Headers

When making requests, you must include these headers:
Authorization: Token <YOUR_SANDBOX_API_KEY>
X-Signature-Transaction: <CALCULATED_HMAC_SIGNATURE>
Content-Type: application/json

Step 2: Implement HMAC Signature

For secure API access, you must generate an HMAC signature for each request. The signature is a hash of the request payload, calculated using your secret key.

Step 3: Make Your First Payment

Make your first payment by sending a POST request to the process endpoint. You can use the following request body to test a card payment.

Test Different Payment Methods

After successfully completing the card payment, you can experiment with other payment methods. Below are the example request bodies for SPEI and OXXO cash payments.
{
  "operation_type": "payment",
  "amount": 500.00,
  "currency": "MXN",
  "customer": {
    "name": "Carlos Eduardo López",
    "email": "carlos.lopez@empresa.mx"
  },
  "payment_method": {
    "type": "SPEI"
  },
  "client_reference": "spei-test-001"
}

Test Data for Different Scenarios

The following tables provide test data for various scenarios and expected outcomes.

Test Cards

Card NumberScenarioExpected Result
4242424242424242Successful paymentauthorized status
4000000000000002Card declineddeclined status
4000000000009995Insufficient fundsdeclined status
40000000000001193D Secure requiredpending with redirect
4000000000000341Processing errorfailed status

Test Bank Accounts

CLABEScenarioExpected Result
646180157000000004Successful transferprocessing status
012345678901234567Invalid checksumValidation error
999999999999999999Non-existent bankinstitution_not_found error

Complete Test Flow Example

This is a complete test flow example of an implementation in Python.
import requests
import json

# Sandbox configuration
SANDBOX_URL = "https://stage.tonder.io/api/v1/"
API_KEY = "your_sandbox_api_key"

def test_successful_payment():
    """Test a successful card payment"""
    
    # Payment request
    payment_data = {
        "operation_type": "payment",
        "amount": 100.00,
        "currency": "MXN",
        "customer": {
            "name": "Test Customer",
            "email": "test@example.com"
        },
        "payment_method": {
            "type": "CARD",
            "card_number": "9230-0892-4469-1474",
            "cardholder_name": "c05d89b2-299c-4f93-b49a-42be00d3b64b",
            "cvv": "d31f0da3-0ed3-4ad8-8b68-14c2669a99a7",
            "expiration_month": "e401a32e-4174-424f-9688-727005f6a80e",
            "expiration_year": "bd9ccc23-3d00-4109-9626-fc6581389063"
        },
        "client_reference": "test-payment-001"
    }
    
    headers = {
        'Authorization': f'Token {API_KEY}',
        'Content-Type': 'application/json'
    }
    
    # Make payment request
    response = requests.post(
        f"{SANDBOX_URL}process/",
        headers=headers,
        json=payment_data
    )
    
    if response.status_code == 201:
        result = response.json()
        print(f"Payment successful! Transaction ID: {result['id']}")
        return result['id']
    else:
        print(f"Payment failed: {response.status_code}")
        return None

def check_transaction_status(transaction_id):
    """Check the status of a transaction"""
    
    headers = {
        'Authorization': f'Token {API_KEY}',
        'Content-Type': 'application/json'
    }
    
    response = requests.get(
        f"{SANDBOX_URL}transactions/{transaction_id}/",
        headers=headers
    )
    
    if response.status_code == 200:
        result = response.json()
        print(f"Transaction status: {result['status']}")
        return result
    else:
        print(f"Status check failed: {response.status_code}")
        return None

# Run the test
if __name__ == "__main__":
    # Test payment
    transaction_id = test_successful_payment()
    
    if transaction_id:
        # Check status
        check_transaction_status(transaction_id)

Common Testing Scenarios

Before going live, it’s a good idea to run through these typical test cases to make sure your integration is working as expected:

Troubleshooting

If you run into issues during testing, here are some common problems and how to resolve them:
IssueWhat to Do
401 Authentication ErrorDouble-check your API key – is it correct and in the right format?
422 Validation ErrorMake sure all required fields are present and data formats are valid
500 Server ErrorTry again, and if it keeps happening, contact support
Rate limit exceededAdd a delay and implement exponential backoff before retrying

What’s Next?