Withdrawals
Send money to a beneficiary via SPEI or debit card, and track the status through to settlement.
Withdrawals (payouts) to beneficiaries are processed through the same unified /process/ endpoint
as payments, using operation_type: "withdrawal".
Availability. Withdrawals via API Direct are currently only available for beneficiaries in Mexico.
Available transfer methods
| Aspect | SPEI | Debit Card |
|---|---|---|
| Processing time | Instant (seconds) | Instant (seconds) |
| Availability | Banking hours only | 24/7 |
| Account type | 18-digit CLABE | 16-digit card number |
| Best for | Beneficiaries with a CLABE, larger amounts | Beneficiaries who only have a card |
Geolocation required for Mexico. The metadata.latitude and metadata.longitude fields are
mandatory for processing withdrawals in Mexico. Omitting them or sending erroneous coordinates
results in a failed transaction.
Step 1: make the withdrawal request
Send your request to the /process/ endpoint with operation_type set to "withdrawal":
| Field | Description |
|---|---|
operation_type | Always "withdrawal" for payout operations. |
amount | The withdrawal amount in the specified currency. |
currency | Currency code (currently only "MXN" is supported). |
client_reference | Your internal reference identifier for this withdrawal. |
transfer_method | Either "SPEI" or "DEBIT_CARD". |
beneficiary | Complete beneficiary information object. |
metadata | Additional required information (must include latitude and longitude). |
The beneficiary object specifies who receives the funds and how:
| Field | Description |
|---|---|
account | Destination account (18-digit CLABE for SPEI, or 16-digit card number for debit card). |
name | Beneficiary's full legal name, as it appears on their account or card. |
rfc | Beneficiary's RFC. |
curp | Beneficiary's CURP (18-character alphanumeric code). |
institution | Bank institution code. See Banking reference. |
email | Beneficiary's email for notifications and record-keeping. |
RFC/CURP requirement. You must provide either rfc or curp on every withdrawal request. If
you don't have one of the two available, send "ND" (Not Available) as the value for that field.
Institution codes for Stage testing. Use 97846 as the institution to simulate both SPEI
and debit card withdrawals in Stage. For production, use the real codes from the
Banking reference (for example, 40012 is already a real
production code — don't use it for testing).
Confirmed, working example — SPEI transfer:
{
"operation_type": "withdrawal",
"amount": 20.00,
"currency": "MXN",
"client_reference": "payout-001",
"transfer_method": "SPEI",
"description": "Commission payment",
"beneficiary": {
"account": "846180000400000001",
"name": "Ana María González",
"rfc": "GOAN850315AB2",
"institution": "97846",
"email": "ana.gonzalez@email.com"
},
"metadata": {
"latitude": "22.8870221",
"longitude": "-109.911775"
}
}curl -X POST https://stage.tonder.io/api/v1/process/ \
-H "Authorization: Token YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"operation_type": "withdrawal",
"amount": 20.00,
"currency": "MXN",
"client_reference": "payout-001",
"transfer_method": "SPEI",
"description": "Commission payment",
"beneficiary": {
"account": "846180000400000001",
"name": "Ana María González",
"rfc": "GOAN850315AB2",
"institution": "97846",
"email": "ana.gonzalez@email.com"
},
"metadata": {
"latitude": "22.8870221",
"longitude": "-109.911775"
}
}'Step 2: handle the response
On a successful request, the API returns an immediate acknowledgment:
{
"id": "550e8400-e29b-41d4-a716-446655440001",
"operation_type": "withdrawal",
"status": "Pending",
"amount": 20.00,
"currency": "MXN",
"client_reference": "payout-001",
"created_at": "2024-07-26T10:30:00Z",
"status_code": 201
}| Field | Description |
|---|---|
id | Unique transaction identifier — store it to monitor progress. |
operation_type | Confirms this is a withdrawal operation. |
status | Current transaction status (initially Pending). |
amount | Withdrawal amount as submitted. |
currency | Currency code. |
client_reference | Your internal reference identifier. |
created_at | ISO 8601 timestamp when the withdrawal was created. |
status_code | HTTP status code (201 for successful creation). |
Step 3: check the transaction status
Withdrawals are asynchronous operations. Use the id from the response to check the status at the
GET /api/v1/transactions/{id}/ endpoint, or monitor via webhooks.
As your withdrawal progresses, it moves through different statuses:
| Status | Type | Description | Previously |
|---|---|---|---|
Pending | Initial | The request was received and is queued or on hold. | PENDING, ON_HOLD |
Processing | Intermediate | The request was sent to the bank or payment provider. | SENT_TO_PROVIDER |
Success | Success | The transfer completed successfully. | PAID_FULL |
Declined | Terminal | The withdrawal was rejected (e.g., invalid account). | REJECTED |
Cancelled | Terminal | The withdrawal was cancelled. | CANCELED |
Failed | Terminal | The withdrawal failed. | FAILED |
Renamed statuses. Withdrawals now use the same status vocabulary as payments. If your
integration expected the previous names (PENDING, SENT_TO_PROVIDER, PAID_FULL, REJECTED,
CANCELED, FAILED), update it using the "Previously" column in the table.
Webhooks
API Direct withdrawal webhooks follow the same flat payload as payment webhooks, with these differences:
| Field | Difference |
|---|---|
operation_type | "withdrawal". |
transfer_method_type | Used instead of payment_method_type (SPEI or DEBIT_CARD). |
event_type | Uses the withdrawal_ prefix (e.g. withdrawal_Pending, withdrawal_Success). |
provider | "STP" — the banking rail that settles the withdrawal. |
Exactly two webhooks are generated per withdrawal: first a Pending notification, then one
terminal notification (Success, Declined, or Failed).
Pending
{
"id": "550e8400-e29b-41d4-a716-446655440001",
"operation_type": "withdrawal",
"amount": "20",
"currency": "MXN",
"client_reference": "payout-001",
"status": "Pending",
"provider": "STP",
"transfer_method_type": "SPEI",
"created": "2026-05-21T19:15:32.029134Z",
"metadata": {
"latitude": "22.8870221",
"longitude": "-109.911775",
"external_id": "payout-001"
},
"event_type": "withdrawal_Pending",
"action": "MODIFY"
}Success
{
"id": "550e8400-e29b-41d4-a716-446655440001",
"operation_type": "withdrawal",
"amount": "20",
"currency": "MXN",
"client_reference": "payout-001",
"status": "Success",
"provider": "STP",
"transfer_method_type": "SPEI",
"created": "2026-05-21T19:20:47.029134Z",
"metadata": {
"latitude": "22.8870221",
"longitude": "-109.911775",
"external_id": "payout-001"
},
"event_type": "withdrawal_Success",
"action": "MODIFY"
}Declined
{
"id": "c7b14546-84bd-4a81-89fb-3dc660f47011",
"operation_type": "withdrawal",
"amount": "60",
"currency": "MXN",
"client_reference": "card-payout-002",
"status": "Declined",
"provider": "STP",
"transfer_method_type": "SPEI",
"created": "2026-05-21T19:20:47.029134Z",
"metadata": {
"latitude": "22.8870221",
"longitude": "-109.911775",
"external_id": "card-payout-002"
},
"event_type": "withdrawal_Declined",
"action": "MODIFY"
}Failed
{
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"operation_type": "withdrawal",
"amount": "75",
"currency": "MXN",
"client_reference": "card-payout-003",
"status": "Failed",
"provider": "STP",
"transfer_method_type": "SPEI",
"created": "2026-05-21T19:20:47.029134Z",
"metadata": {
"latitude": "22.8870221",
"longitude": "-109.911775",
"external_id": "card-payout-003"
},
"event_type": "withdrawal_Failed",
"action": "MODIFY"
}Recommended monitoring: use webhooks to receive real-time status updates. Alternatively, you can poll the transaction status endpoint.
Check your balance
Before dispersing, check the available balance:
curl https://stage.tonder.io/api/v1/withdrawals/balance \
-H "Authorization: Token YOUR_API_KEY"curl https://app.tonder.io/api/v1/withdrawals/balance \
-H "Authorization: Token YOUR_API_KEY"{
"message": "Data retrieved successfully",
"current_balance": "32894.55"
}A withdrawal for more than the available balance is rejected. The endpoint's schema is in the API Reference.
