Follow these recommendations to build a reliable and secure Card Present integration.
Idempotency#
Always send a unique client_transaction_id (UUID v4) for each transaction. If a request times out or fails due to a network issue, retry it with the same client_transaction_id — Kushki will return the original result instead of creating a duplicate charge.{
"client_transaction_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
}
Never reuse a client_transaction_id for a different transaction. This would return the original transaction result instead of processing a new one.
Persist transaction_reference#
Every approved charge, authorization, and capture response includes a transaction_reference. Store this value immediately — it is required to perform voids, refunds, captures, and reauthorizations on that transaction.{
"transaction_reference": "f2f29080-0214-42c0-95a5-77ecf3434cd7"
}
If the reference is lost, recovery requires querying the Query Transactions endpoint using the original client_transaction_id.
Handle timeouts with reversals#
If a charge request times out and you are unsure whether the transaction was processed:1.
Wait at least 1 minute after the original request.
2.
Send a reversal using the same client_transaction_id to safely cancel the uncertain transaction.
3.
Reversals are only valid on the same day and before 22:00 México local time.
{
"transaction_type": "charge",
"transaction_mode": "Reverse",
"client_transaction_id": "<same-id-as-original>",
"amount": { "currency": "MXN", "subtotal_iva": 0, "subtotal_iva0": 500, "iva": 0 }
}
Void before the cutoff#
Voids in Mexico are valid until 22:00 México local time on the same day as the transaction. After that cutoff, use a refund instead.Do not attempt a void after 22:00 local time — the request will be rejected. Use POST /pos/v1/refund for same-day transactions past the cutoff or for transactions from previous days.
Use cardless operations for back-office flows#
Cardless operations (omit_card: true) are in Beta phase in México. When available, use them for:Captures after the customer has left the terminal
Reauthorizations from a back-office system
Bulk voids or refunds processed at end of day
Any operation where re-reading the card is not practical
{
"transaction_type": "capture",
"transaction_mode": "Authorization",
"omit_card": true,
"transaction_reference": "f2f29080-0214-42c0-95a5-77ecf3434cd7",
"amount": { "currency": "MXN", "subtotal_iva": 0, "subtotal_iva0": 500, "iva": 0 }
}
Always check MSI options before installments#
Before initiating a deferred charge (MSI — Meses Sin Intereses), call the BIN lookup and MSI options endpoints to verify the card supports installments and retrieve the valid months.1. POST /pos/v1/bin → check if card supports MSI
2. GET /deferred/v2/bin/{bin} → get available months and credit_type
3. POST /pos/v1/transaction → charge with is_deferred: true
Never hard-code installment months — they vary by card BIN and may change.MSI requires a minimum transaction amount. Contact Kushki or check the MSI minimum amounts table before sending a deferred charge.
MXN amounts support two decimal places#
The Mexican Peso supports two decimal places. Amounts are expressed in pesos (e.g., 500.00 = $500 MXN)."amount": {
"currency": "MXN",
"subtotal_iva": 0,
"subtotal_iva0": 500,
"iva": 0
}
Include terminal location#
Send pos_details.location with the terminal's GPS coordinates whenever available. This data improves fraud detection and may be required for certain merchant categories."pos_details": {
"terminal_id": "PB04209860189",
"brand": "SUNMI",
"model": "P2-EU",
"has_print": true,
"location": {
"latitude": 19.4326,
"longitude": -99.1332
}
}
Webhook best practices#
Return HTTP 200 as soon as you receive a webhook notification, before running any business logic. If your endpoint takes too long, Kushki may retry the delivery.Design for idempotency#
Kushki stores notifications on multiple servers for high availability. On rare occasions, you may receive the same notification more than once. Your webhook handler must be idempotent — processing the same notification twice should not produce duplicate side effects.Validate webhook signatures#
Always verify the webhook signature before processing the payload to ensure it originated from Kushki.
Retry policy#
If a request fails with a 5xx error, retry with exponential backoff:| Attempt | Wait before retry |
|---|
| 1st retry | 1 second |
| 2nd retry | 2 seconds |
| 3rd retry | 4 seconds |
| 4th retry | 8 seconds |
Do not retry 4xx errors (e.g., 400, 401, 403) — these indicate a problem with the request itself that retrying will not fix.
Got a suggestion on this documentation? Contact us.