Quickstart
Take your first test payment with Hosted Checkout in four steps, without building a card form.
Hosted Checkout is the fastest way to get paid: Tonder hosts the payment page, so card data never touches your servers (no PCI scope). This quickstart takes you from zero to a verified test payment in four steps.
Before you begin
- A Tonder account — sign in at dashboard.tonder.io (Production) or dashboard-stage.tonder.io (Sandbox).
- Your test API key from Developers → API Keys. Authenticate every request with your
public key:
Authorization: Token YOUR_TEST_API_KEY.
Amounts are in decimal format: 150.00 = MXN 150.00. Set external_id to your order
reference — it's the key you'll reconcile payments by.
Steps
Create a checkout session
From your server, create a session with your public key. The response returns a url to send the
customer to.
curl -X POST 'https://api-stage.tonder.io/checkout/v1/sessions' \
-H 'Authorization: Token YOUR_TEST_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"customer": {
"first_name": "Vicente",
"last_name": "Quintero",
"email": "vquintero@testuser.com"
},
"amount_total": 150.00,
"currency": "MXN",
"line_items": [
{
"name": "Deposit",
"quantity": 1,
"unit_price": 150.00,
"product_id": "your internal product id"
}
],
"payment_method_types": [
"card",
"mercadopago",
"oxxopay",
"spei",
"safetypayCash",
"safetypayTransfer",
"neosurf"
],
"return_url": "https://tonder.io",
"external_id": "ORD-12345-4",
"metadata": { "external_id": "ORD-12345-4" }
}'curl -X POST 'https://api.tonder.io/checkout/v1/sessions' \
-H 'Authorization: Token YOUR_LIVE_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"customer": {
"first_name": "Vicente",
"last_name": "Quintero",
"email": "vquintero@testuser.com"
},
"amount_total": 150.00,
"currency": "MXN",
"line_items": [
{
"name": "Deposit",
"quantity": 1,
"unit_price": 150.00,
"product_id": "your internal product id"
}
],
"payment_method_types": [
"card",
"mercadopago",
"oxxopay",
"spei",
"safetypayCash",
"safetypayTransfer",
"neosurf"
],
"return_url": "https://tonder.io",
"external_id": "ORD-12345-4",
"metadata": { "external_id": "ORD-12345-4" }
}'The response (200 Created) includes the redirect url, the session id, and a pending status:
{
"id": "cs_97_41521_d11ba771527b4056c7f85786cfbb980b",
"url": "https://stage-payflow.tonder.io/checkout/cs_97_41521_d11ba771527b4056c7f85786cfbb980b",
"status": "pending",
"payment_id": 41521,
"amount_total": 150.00,
"currency": "MXN",
"external_id": "ORD-12345-4",
"transaction_status": "Pending"
}Redirect the customer
Send the customer to the url from the response — that's Tonder's hosted payment page.
res.redirect(session.url);Complete a test payment
On the hosted page, pay with a test card: 4000 0000 0000 0077 (approved), any future expiry
(e.g. 12/30), and any 3-digit CVC (e.g. 123). Find the full set of test cards under
Developers → Test Data in the dashboard.
When done, Tonder returns the customer to your return_url with the session id appended:
https://your-store.com/checkout/complete?session_id=cs_97_41521_….
Confirm the result
Always confirm server-side — don't assume the redirect means success.
- Webhook (recommended). Tonder sends a
session.completedevent to your endpoint (Developers → Webhooks). Match it to your order viametadata.external_idand respond200. - Status check. Or fetch the session and read
status:
curl -X GET 'https://api-stage.tonder.io/checkout/v1/sessions/cs_97_41521_d11ba771527b4056c7f85786cfbb980b' \
-H 'Authorization: Token YOUR_TEST_API_KEY'curl -X GET 'https://api.tonder.io/checkout/v1/sessions/cs_97_41521_d11ba771527b4056c7f85786cfbb980b' \
-H 'Authorization: Token YOUR_LIVE_API_KEY'A successful payment returns status: "completed" and transaction_status: "Success":
{
"id": "cs_97_41521_d11ba771527b4056c7f85786cfbb980b",
"status": "completed",
"transaction_status": "Success",
"amount_total": 150.00,
"currency": "MXN",
"external_id": "ORD-12345-4",
"paid_at": 1751478550234
}Webhooks are the most reliable way to confirm payments — prefer them over polling. Acknowledge
each event with a 200 and reconcile using metadata.external_id.
