Quickstart
Go from zero to your first payment with Tokeflow in seven steps — keys, customer, checkout session, browser collection, charge, and webhook.
This guide takes you from zero to a first payment with Tokeflow — the orchestration layer behind your platform. You will get your API keys, create a customer, open a checkout session, collect card data in the browser, charge it server-side, and confirm the result with a webhook.
Tokeflow standardizes payment operations across multiple providers under your own brand. Your connected payment providers do the processing and settlement; Tokeflow orchestrates routing, resilience, and a single normalized API.
All endpoints live under the base URL https://api.tokeflow.com and the /api/v1 version prefix. Money is always in integer minor units (cents): R$150.00 is 15000. Always send an ISO 4217 currency.
The flow at a glance
Step 1 — Get your API keys
API keys are issued in the Tokeflow Dashboard during onboarding. You provision merchants, register webhook URLs, and generate keys there — there is no public API for provisioning.
You will work with two kinds of keys:
| Key | Prefix | Where it runs | Use |
|---|---|---|---|
| Secret key | sk_live_… | Server-side only | Authenticate API calls (Authorization: Bearer) |
| Public key | pk_live_… | Browser-safe | Initialize the Bridge SDK for card collection |
Every key is scoped to exactly one entity. A Merchant key (sk_live_mer_…) infers its merchant automatically. An Organization key (sk_live_org_…) spans all merchants in the org, so merchant-scoped calls must name the target merchant via merchant_id. See Authentication for the full key anatomy and scopes.
Secret keys (sk_*) must never appear in browser code, mobile apps, or any client. Only public keys (pk_*) are safe to expose client-side.
Step 2 — Make your first authenticated request
Verify your secret key with a simple read. List customers:
curl https://api.tokeflow.com/api/v1/customers?limit=1 \
-H "Authorization: Bearer sk_live_mer_xxxxxxxxxxxxxxxx" \
-H "Accept: application/json"Every response is wrapped in the standard envelope. A list returns data as an array plus meta.pagination:
{
"success": true,
"data": [
{
"id": "cust_a1b2c3d4e5",
"merchant_id": "mrc_a1b2c3d4e5",
"email": "joao@example.com",
"name": "Joao da Silva",
"created_at": "2026-01-15T12:00:00.000Z"
}
],
"meta": {
"pagination": {
"page": 1,
"limit": 1,
"total": 42,
"total_pages": 42,
"has_next": true,
"has_prev": false
}
},
"request_id": "req_8f3c1a2b",
"timestamp": "2026-01-15T12:30:00.000Z"
}Using an Organization key? Add merchant_id to scope the read: ...customers?limit=1&merchant_id=mrc_a1b2c3d4e5.
If the key is wrong, you get the standard error envelope with HTTP 401:
{
"error": {
"type": "authentication_error",
"code": "INVALID_API_KEY",
"message": "The provided API key is invalid.",
"details": {},
"request_id": "req_9a0b1c2d",
"timestamp": "2026-01-15T12:30:00.000Z"
}
}Step 3 — Create a customer
Create the customer you are about to charge. This call is idempotent by email: if the email already exists, the existing record is returned with HTTP 200 instead of 201.
curl -X POST https://api.tokeflow.com/api/v1/customers \
-H "Authorization: Bearer sk_live_mer_xxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"email": "joao@example.com",
"name": "Joao da Silva",
"document_type": "cpf",
"document_number": "123.456.789-00"
}'A single resource omits meta:
{
"success": true,
"data": {
"id": "cust_a1b2c3d4e5",
"merchant_id": "mrc_a1b2c3d4e5",
"email": "joao@example.com",
"name": "Joao da Silva",
"created_at": "2026-01-15T12:00:00.000Z"
},
"request_id": "req_1f2e3d4c",
"timestamp": "2026-01-15T12:00:00.000Z"
}Step 4 — Create a checkout session
A checkout session captures what the customer is buying. Reference an offer (a sellable price configuration for a product) and Tokeflow derives the amount and currency from it — so you never hard-code prices into the charge.
curl -X POST https://api.tokeflow.com/api/v1/checkout-sessions \
-H "Authorization: Bearer sk_live_mer_xxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"offer_id": "ofr_a1b2c3d4e5",
"customer_id": "cust_a1b2c3d4e5",
"selected_currency": "BRL",
"items": [
{ "offer_id": "ofr_a1b2c3d4e5", "quantity": 1, "installments": 1 }
]
}'{
"success": true,
"data": {
"id": "cks_a1b2c3d4e5",
"merchant_id": "mrc_a1b2c3d4e5",
"offer_id": "ofr_a1b2c3d4e5",
"customer_id": "cust_a1b2c3d4e5",
"selected_currency": "BRL",
"status": "initiated",
"expires_at": null,
"completed_at": null,
"created_at": "2026-01-15T12:05:00.000Z",
"updated_at": "2026-01-15T12:05:00.000Z"
},
"request_id": "req_2c3d4e5f",
"timestamp": "2026-01-15T12:05:00.000Z"
}Hold onto cks_a1b2c3d4e5 — you will reference it when you charge in Step 6.
Prefer a direct charge? You can skip the session and pass amount + currency straight to POST /transactions. Checkout sessions are recommended because they bind the charge to your catalog, track buyer progress, and emit checkout events. See Checkout Sessions.
Step 5 — Collect payment in the browser
Card data must never touch your servers. The Bridge SDK runs Tokeflow's secure fields inside isolated, cross-origin iframes; card data is encrypted in the browser and exchanged for a single-use token. Initialize the SDK with your public key and the checkout session id:
import { TokeflowBridge } from "@tokeflow_com/bridge-js";
const tokeflow = new TokeflowBridge({
publicKey: "pk_live_mer_xxxxxxxxxxxxxxxx",
checkoutSessionId: "cks_a1b2c3d4e5",
});
await tokeflow.init();
// Create and mount a secure card element, then tokenize on submit:
const cardElement = tokeflow.createCardElement();
cardElement.mount("#card-element");
const token = await tokeflow.cards.tokenize({ card: cardElement });
// token.tokenId => "tok_a1b2c3d4e5" — send this to YOUR serverSend the resulting token.tokenId (tok_…) to your backend. It is single-use and short-lived.
Never send raw card numbers, CVCs, or expiry dates to your own backend. Only the SDK-produced tok_… should leave the browser. Full setup, payment methods, and saved-card flows are in the Bridge SDK guide.
Step 6 — Charge
Now charge server-side. Reference the checkout session (amount and currency come from it) and the SDK token. Send an Idempotency-Key so a retried request never double-charges.
curl -X POST https://api.tokeflow.com/api/v1/transactions \
-H "Authorization: Bearer sk_live_mer_xxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: ord_2026_0115_attempt_1" \
-d '{
"checkout_session_id": "cks_a1b2c3d4e5",
"customer_id": "cust_a1b2c3d4e5",
"payment_method": "credit_card",
"charge_type": "payment",
"country": "BR",
"capture": true,
"card_ciphertext_id": "tok_a1b2c3d4e5"
}'The first submission returns HTTP 201; replaying the same Idempotency-Key returns the original result with HTTP 200. Always read the status field — that is the source of truth for the outcome.
{
"success": true,
"data": {
"id": "tx_a1b2c3d4e5",
"organization_id": "org_a1b2c3d4e5",
"merchant_id": "mrc_a1b2c3d4e5",
"customer_id": "cust_a1b2c3d4e5",
"amount_authorized": 9900,
"amount_captured": 9900,
"currency": "BRL",
"payment_method": "credit_card",
"charge_type": "payment",
"country": "BR",
"status": "authorized",
"timeline": [
{
"attempt_number": 1,
"is_fallback": false,
"connector_id": "conn_a1b2c3",
"provider_slug": "acquirer_a",
"status": "success",
"started_at": "2026-01-15T12:10:00.000Z",
"finished_at": "2026-01-15T12:10:02.000Z"
}
],
"payment_instructions": null,
"metadata": {},
"created_at": "2026-01-15T12:10:00.000Z",
"updated_at": "2026-01-15T12:10:02.000Z"
},
"request_id": "req_3d4e5f6a",
"timestamp": "2026-01-15T12:10:02.000Z"
}The timeline shows each routing attempt, including any resilience fallback (cascade) across providers. Provider failures return HTTP 201 with status: "failed" — inspect the timeline to see what happened, then retry with a new idempotency key.
Transaction status values you may see: pending, pre_authorized, authorized, capture_pending, failed, canceled, voided, refund_pending, refunded, partially_refunded, charged_back, expired. For async methods like pix and boleto, the response includes payment_instructions (QR code or barcode) and the status starts at pending.
Step 7 — Receive a webhook
Polling is unnecessary. When the transaction settles into a terminal state, Tokeflow delivers a normalized webhook to the endpoint you registered during onboarding — for example transaction.authorized:
{
"id": "evt_4e5f6a7b8c9d",
"type": "transaction.authorized",
"created_at": "2026-01-15T12:10:02.000Z",
"data": {
"object": {
"id": "tx_a1b2c3d4e5",
"current_status": "authorized",
"amount_captured": 9900,
"currency": "BRL"
}
}
}Every delivery carries an X-Tokeflow-Signature header. Verify it against the raw request body before trusting the payload, and reject deliveries whose timestamp is outside your tolerance window. Full verification code and the event catalog are in Webhooks.
You did it
A single API surface, your providers behind it, your brand on top. From here:
- Authentication — key types, scopes, and the org-vs-merchant model in depth.
- Checkout Sessions — items, currency selection, and lifecycle events.
- Transactions — capture, void, refund, and reading the attempt timeline.
- Bridge SDK — secure fields, saved cards, wallets, and 3DS orchestration.
- Webhooks — signature verification and the full event list.