Card Payments
The two card flows — tokenized and raw data — and the PCI scope each one carries.
Tonder offers two paths for processing card payments through API Direct. The right choice depends on your PCI DSS compliance status and infrastructure.
- Tokenized flow — for most merchants. Tokenize card data first, then process payments using tokens. Minimizes your PCI scope.
- Raw card data — for PCI Level 1 certified merchants only. Process payments with raw card numbers directly. Requires full compliance infrastructure.
Comparison
| Aspect | Tokenized flow | Raw card data |
|---|---|---|
| PCI requirement | SAQ A or SAQ A-EP | Full PCI DSS Level 1 |
| Best for | Most merchants, startups, mid-market | Enterprise, processors, high-volume platforms |
| Steps | 3 (get token → tokenize → process) | 2 (get token → process) |
| Latency | Slightly higher (extra tokenization call) | Lower (direct processing) |
| Card data handling | Never touches your servers | Passes through your servers |
| Compliance cost | Lower | Significantly higher |
Raw card data processing requires proof of PCI DSS Level 1 certification. You must share your Attestation of Compliance (AOC) with Tonder before we activate production access to the raw card endpoints.
Endpoints
| Purpose | Endpoint |
|---|---|
| Get access token | GET https://stage.tonder.io/api/v1/tokenization/auth/ |
| Tokenize card data | POST https://token-sandbox.tonder.io/v1/gateway/inboundRoutes/{route_id}/token |
| Process payment (tokenized) | POST https://stage.tonder.io/api/v1/process/ |
| Process payment (raw data) | POST https://process-sandbox.tonder.io/raw-data |
| Purpose | Endpoint |
|---|---|
| Get access token | GET https://app.tonder.io/api/v1/tokenization/auth/ |
| Tokenize card data | POST https://token.tonder.io/v1/gateway/inboundRoutes/{route_id}/token |
| Process payment (tokenized) | POST https://app.tonder.io/api/v1/process/ |
| Process payment (raw data) | POST https://process.tonder.io/raw-data |
Your route_id is provided in your dashboard after onboarding. Contact support if you don't have
one.
Tokenized flow
Tonder tokenizes each card field individually (number, CVV, expiration month, etc.); you use each individual token in place of the original value when making the payment request.
Call GET /api/v1/tokenization/auth/ with your API key. It returns a JWT in access_token.
curl -X GET https://stage.tonder.io/api/v1/tokenization/auth/ \
-H "Authorization: Token <YOUR_TONDER_API_KEY>"{ "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." }Send the raw card data to the tokenization service, authorized with the access token from the
previous step (X-Skyflow-Authorization header). Required fields:
| Field | Type | Description |
|---|---|---|
card_number | string | The full card number. |
cardholder_name | string | The name on the card. |
cvv | string | Security code (3-4 digits). |
expiration_month | string | Future expiration month (e.g. "07"). |
expiration_year | string | Future expiration year (e.g. "26"). |
curl -X POST https://token.tonder.io/v1/gateway/inboundRoutes/{route_id}/token \
-H "X-Skyflow-Authorization: <YOUR_ACCESS_TOKEN_FROM_STEP_1>" \
-H "Content-Type: application/json" \
-d '{
"card_number": "4000000000000077",
"cardholder_name": "Ozzy Osbourne",
"cvv": "123",
"expiration_month": "07",
"expiration_year": "26"
}'The service responds with an individual token for each field. They are not interchangeable between fields.
Make a standard request to /process/. In payment_method, use the tokenized values instead of
the raw data:
{
"operation_type": "payment",
"amount": 150.00,
"currency": "MXN",
"customer": { "name": "John Doe", "email": "john.doe@email.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": "ORD-001"
}The request is authenticated with your API key, just like any other payment. Tonder detokenizes the values server-side.
Always validate both id (the unique transaction identifier — store it) and status (the current
payment state). Never rely on the HTTP status code alone.
3D Secure
3DS is handled within the card flow when the issuer requires it. See the 3DS Lifecycle.
API reference
Endpoints for the tokenized flow (the final payment is made via POST /process/, documented in the
Overview):
Authorization
Authorization Tu API key con prefijo Token , p. ej. Token <API_KEY>
In: header
Response Body
application/json
application/json
curl -X GET "https://example.com/tokenization/auth/"{
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}{
"error": {
"code": "string",
"message": "string",
"type": "request_error",
"details": {}
},
"request_id": "string"
}Authorization
TokenizationAuth Authorization Access token from /tokenization/auth/ endpoint
In: header
Tu API key con prefijo Token , p. ej. Token <API_KEY>
In: header
Request Body
application/json
TypeScript Definitions
Use the request body type in TypeScript.
Response Body
application/json
application/json
application/json
application/json
curl -X POST "https://example.com/token" \ -H "Content-Type: application/json" \ -d '{ "card_number": "4242424242424242", "cardholder_name": "John Doe", "cvv": "123", "expiration_month": "07", "expiration_year": "2025" }'{
"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"
}{
"error": {
"code": "string",
"message": "string",
"type": "request_error",
"details": {}
},
"request_id": "string"
}{
"error": {
"code": "string",
"message": "string",
"type": "request_error",
"details": {}
},
"request_id": "string"
}{
"error": {
"code": "string",
"message": "string",
"type": "request_error",
"details": {}
},
"request_id": "string"
}