Transactions

Create, list, capture, and void payment transactions through Tokeflow's orchestration engine — with smart routing, fallback timelines, and idempotent creation.

A transaction is a single attempt to move money for an order through Tokeflow's orchestration engine. You describe the intent — amount, currency, payment method, country, and the card source — and Tokeflow routes the charge across the payment providers you have connected, applying your routing rules and cascading to a fallback provider when one declines or errors.

Tokeflow orchestrates the charge; it does not process or settle funds. Authorization, capture, and settlement are performed by the connected payment providers. Tokeflow normalizes their behavior behind one consistent transaction object so your integration stays the same no matter which provider handles the payment.

Every transaction records a timeline of routing attempts — which connector was tried, in what order, and how each responded. That timeline is your audit trail and your debugging tool. See The timeline.

How a transaction flows

A single API call can fan out to several providers behind the scenes. The request and response shapes are stable regardless of which provider ultimately authorizes the charge.

The transaction object

FieldTypeDescription
idstringTransaction ID, prefixed tx_.
organization_idstringOwning organization, prefixed org_.
merchant_idstringOwning merchant, prefixed mrc_.
order_idstring | nullOrder this charge belongs to, prefixed ord_. Tokeflow auto-creates an order for direct API charges.
subscription_idstring | nullSubscription created from this charge when the underlying offer is recurring, prefixed sub_. Null otherwise.
external_order_idstring | nullYour own order reference, echoed back for reconciliation.
customer_idstring | nullCustomer the charge is attributed to, prefixed cust_.
payment_instrument_idstring | nullSaved instrument used, prefixed pi_. Null for one-off card or async charges.
amount_authorizedintegerAmount authorized, in minor units.
amount_capturedintegerAmount captured, in minor units.
currencystringISO 4217 currency code.
payment_methodstringOne of credit_card, debit_card, pix, boleto, wallet.
charge_typestringpayment or setup_verification.
countrystringISO 3166-1 alpha-2 country code.
statusstringCurrent transaction status. See Status lifecycle.
applied_routing_rule_idstring | nullThe routing rule node that produced the successful attempt.
modestring | nulllive or test — whether the payment ran on live or test provider credentials, taken from the connector of the final attempt. Null when no attempt was made (the charge was refused before routing).
timelinearrayOrdered list of routing attempts. See The timeline.
payment_instructionsobject | nullCustomer-facing instructions for async methods (PIX, boleto). Null for synchronous card charges.
metadataobject | nullArbitrary key-value pairs you attached at creation.
created_atstringCreation timestamp (ISO 8601 UTC).
updated_atstringLast update timestamp (ISO 8601 UTC).

The timeline

The timeline is the ordered record of every provider attempt Tokeflow made for this transaction. It is how cascade and fallback become observable.

FieldTypeDescription
attempt_numberinteger1-based sequence number of the attempt.
is_fallbackbooleantrue if this attempt ran only because a previous attempt failed.
connector_idstringThe connector used for this attempt.
provider_slugstringNeutral slug for the provider behind the connector.
statusstringpending, success, failed, or error.
started_atstringWhen the attempt began (ISO 8601 UTC).
finished_atstring | nullWhen the attempt resolved (ISO 8601 UTC), or null if still pending.
error_categorystring | nullHigh-level error class when the attempt did not succeed.
error_codestring | nullNormalized error code when the attempt did not succeed.
decline_reasonstring | nullWhy the attempt failed, in Tokeflow's own words — the same value whichever provider answered. See Decline reasons. Null when no reason is known.

For a richer, per-attempt view — including 3DS status, normalized error messages, and gateway fees — call GET /transactions/:id/attempts.

Status lifecycle

The full status enum:

pending, pre_authorized, authorized, failed, canceled, voided, charged_back, refund_pending, capture_pending, refunded, partially_refunded, expired.

A failed charge is not an HTTP error. When a provider declines, Tokeflow still returns 201 Created with status: "failed" and a timeline explaining why. Always branch on the status field — never assume a 2xx response means the money was authorized.

When the provider gives no answer

A card charge can also come back pending. That happens when the provider was asked to move money but gave no verdict — a timeout, an unreadable response, or a server error on its side. The charge may or may not have landed, so Tokeflow does not treat it as a decline: it does not cascade to a fallback connector (that could charge the customer twice) and does not start dunning on a renewal. The transaction stays pending while Tokeflow establishes the outcome with the provider, then moves to its final status, which reaches you through the usual transaction webhooks. A checkout session paid by such a charge is settled at the same moment.

Do not retry a pending card charge with a new idempotency key. Wait for the final status, or read it back with GET /transactions/:id.

Decline reasons

Every failed attempt carries a decline_reason: Tokeflow's name for why it failed. Each provider's own decline codes are mapped onto this one vocabulary, so insufficient_funds means the same thing whichever connector answered. error_category and error_code stay the fields that drive retries; decline_reason is the one to show your support team, group in reports, or turn into a message for the customer.

GroupReasons
Issuerdo_not_honor, generic_decline, call_issuer, try_again_later, issuer_unavailable, invalid_transaction, transaction_not_permitted, do_not_retry
Funds and limitsinsufficient_funds, limit_exceeded, max_attempts
Card datainvalid_card_number, invalid_cvv, invalid_expiry, incorrect_pin, invalid_amount, invalid_installments
Card statuscard_expired, lost_or_stolen, pickup_card, card_restricted, card_inactive, account_closed, account_updated, authorization_revoked, card_not_supported, currency_not_supported, test_card_used
Fraud and riskfraud_suspected, risk_blocked, blocklisted
Authenticationauthentication_required, authentication_failed
Requestduplicate_transaction, invalid_request, invalid_token
Providerprocessing_error, provider_unavailable, timeout, rate_limited, invalid_credentials
Unmappedother — the provider gave a reason that has no Tokeflow name yet.

The list only grows: a reason is never renamed or removed, and new reasons are added over time. Store the value as a string and treat an unknown one like other.

The reason also decides how Tokeflow routes the decline, the same way for every provider:

  • On a customer-initiated charge, temporary issuer and funds declines (do_not_honor, generic_decline, try_again_later, issuer_unavailable, insufficient_funds) are retried once on the same connector and then cascade to your fallbacks. Every other decline reason stops the charge without a cascade — card data, card status, fraud and risk, and issuer answers such as call_issuer or transaction_not_permitted that another attempt right now would not change. The customer has to fix the card, contact their bank or use another one.
  • On a subscription renewal, nothing is retried within the request. A reason that says the card can never be charged again (lost_or_stolen, pickup_card, card_restricted, account_closed, account_updated, authorization_revoked, card_not_supported, currency_not_supported, test_card_used, do_not_retry, fraud_suspected, blocklisted) cancels the subscription. Every other decline — including expired cards, wrong card data and risk_blocked — sends it to dunning, so the customer can still update the card.

Charge type

ValueMeaning
paymentA real charge for goods or services. Uses amount.
setup_verificationA zero-or-nominal-amount verification used to validate and store a card for later charges, without billing the customer.

Card sources

Every card charge needs a card source. Pick the combination that matches your scenario:

ScenarioField to sendNotes
New cardcard_ciphertext_idThe single-use encrypted card reference (tok_…) returned by the Bridge SDK. Add save_payment_instrument: true to also save the card for later.
Saved card, customer re-types the CVVpayment_instrument_id + card_ciphertext_idA stored instrument, prefixed pi_, plus a fresh ciphertext for the same card.
Saved card, one clickpayment_instrument_id + credential_on_file: trueCharges the provider credential kept at enrollment. No card data, no CVV. See Stored-credential charges.
Checkoutcheckout_session_idCharge a completed checkout session, prefixed cks_.
Checkout, saved cardcheckout_session_id + payment_instrument_id + credential_on_file: truePay the session with the customer's saved card, no card re-entry. Requires the merchant's saved_card_checkout_enabled opt-in. See Saved-card checkout.

payment_instrument_id on its own is refused with 400. A saved card is charged either with credential_on_file: true or with a fresh card_ciphertext_id — one of the two must say how the card is presented.

Never send raw card data to this endpoint. Tokeflow's secure fields run inside isolated, cross-origin iframes; card data is encrypted in the browser and never touches your servers. The browser receives a single-use encrypted card reference (tok_…), which you pass as card_ciphertext_id. For PIX, boleto, and wallet methods, no card source is required.

Need a tok_… to test this endpoint? Use the hosted Bridge SDK tester at card.tokeflow.com: run it against your merchant with a public key, then copy the returned encrypted card reference and send it here as card_ciphertext_id. See Test the Bridge SDK without code.

Stored-credential charges (one-click)

Two boolean flags turn a plain charge into the two halves of a one-click flow — the pattern behind post-purchase upsells and downsells. The step-by-step guide is One-click upsells & downsells; this section is the field reference.

save_payment_instrument

Saves the card behind card_ciphertext_id as a payment instrument for customer_id before the charge runs, then charges the submitted ciphertext. When the provider approves, its reusable credential for the card is kept on that connector, so later credential_on_file charges can use it. The response carries the new payment_instrument_id.

RuleDetail
Requirescard_ciphertext_id minted with purpose=instrument_enrollment — from the Bridge SDK with purpose: 'instrument_enrollment' (standalone) or saveCard: true (inside a checkout session). customer_id. A card payment method.
Refused withcheckout_session_id (the session's save_card governs there), payment_instrument_id, credential_on_file.
one_time ciphertext400 validation_error — the token cannot be saved. Nothing is charged.
Existing cardIf the customer already has this card on file, the existing instrument is reused.

credential_on_file

Charges the saved payment_instrument_id with the provider credential kept at enrollment — no card data, no CVV. Meant for customer-present, unscheduled charges such as a one-click upsell; scheduled charges belong to subscriptions.

RuleDetail
Requirespayment_instrument_id (must belong to the customer and be active) and a card payment method. Without a checkout session, also customer_id.
Refused withcard_ciphertext_id, save_payment_instrument, capture: false.
With checkout_session_idPays the session with the saved card: the session supplies amount, currency, customer and installments. Requires the merchant's saved_card_checkout_enabled opt-in. See Saved-card checkout.
PrerequisiteThe instrument holds a credential from one successful cardholder-present charge or card verification on a connector whose provider supports stored-credential charges. Otherwise 400 validation_error.
RoutingPinned to the active connector holding the instrument's newest usable credential. Routing rules and cascade do not apply; if that connector cannot take the charge (currency, installments) the request is refused with 422.
CaptureAlways auth + capture.
OrderCreated with recurrence: "unscheduled".
Metadatastored_credential_usage: "customer_initiated" is merged into metadata.
AuthenticationA stored-credential charge cannot run a 3-D Secure challenge. An issuer that requires it declines with error_code: "AUTHENTICATION_REQUIRED" — fall back to a fresh ciphertext.

Saved-card checkout

A returning customer can pay a checkout session with a card they saved earlier, without typing it again. Your server charges the session with the saved instrument:

{
  "checkout_session_id": "cks_a1b2c3d4e5",
  "payment_instrument_id": "pi_123",
  "credential_on_file": true,
  "payment_method": "credit_card",
  "charge_type": "payment",
  "country": "BR"
}
RuleDetail
Opt-inThe merchant must have saved_card_checkout_enabled on. It is off by default. Enabling it states that you authenticate the customer before you identify them on the session — on a session, Tokeflow never sees the cardholder, so your server vouches for them.
What the opt-in coversAny use of a saved payment_instrument_id on a checkout session without a fresh card_ciphertext_id: the credential_on_file charge, and a zero-amount trial started from the saved card alone. A charge with a fresh ciphertext (re-typed card) needs no opt-in.
Amount and customerTaken from the session; any amount, currency or customer_id you send is not used.
ConnectorPinned to the connector that holds the card's stored credential, as for any credential_on_file charge. On a recurring offer, the subscription starts on that connector.
Opt-in off400 — collect the card again and charge the session with a fresh card_ciphertext_id. If the message says the feature is switched off by a Tokeflow setting, changing saved_card_checkout_enabled will not lift it; contact the Tokeflow team.

To decide whether to offer "pay with this saved card", read the checkout context in the browser: savedCardCheckoutEnabled and each saved instrument's reusable flag tell you which cards can be charged on this session. They are hints; the charge itself stays authoritative and can still be declined.


Endpoints

POST/api/v1/transactions

OrgMerchant

Auth: Organization key (with merchant_id) or Merchant key. Scope: transactions:write.

Creates and submits a payment transaction. Tokeflow evaluates your routing rules, attempts the charge (cascading to a fallback provider on failure), and auto-creates an order for the charge.

Request fields

FieldTypeRequiredDescription
payment_methodstringYesOne of credit_card, debit_card, pix, boleto, wallet.
charge_typestringYespayment or setup_verification.
countrystringYesISO 3166-1 alpha-2 country code. Used for routing and acquirer selection.
amountintegerConditionalAmount in minor units (e.g. R$150.00 = 15000). Use 0 for setup_verification. Required unless checkout_session_id is provided.
currencystringConditionalISO 4217 currency code. Required unless checkout_session_id is provided.
merchant_idstringConditionalTarget merchant. Required with an Organization key; inferred from a Merchant key.
card_ciphertext_idstringConditionalThe single-use encrypted card reference (tok_…) returned by the Bridge SDK when you tokenize a new card. Required for a new card, and for a saved card charged with a re-typed CVV.
payment_instrument_idstringConditionalSaved instrument to charge (pi_…). Send it with a fresh card_ciphertext_id or with credential_on_file: true — never alone.
credential_on_filebooleanNotrue charges payment_instrument_id with the provider credential kept at enrollment — no card data, no CVV. Customer-present, unscheduled charges only. Requires customer_id unless a checkout_session_id is sent; with a session it needs the merchant's saved_card_checkout_enabled opt-in. Not combined with card_ciphertext_id, save_payment_instrument or capture: false. Default false. See Stored-credential charges.
save_payment_instrumentbooleanNotrue saves the card behind card_ciphertext_id for customer_id before charging, so later credential_on_file charges can reuse it. The ciphertext must be minted with purpose=instrument_enrollment. Not used with checkout_session_id. Default false.
checkout_session_idstringConditionalCompleted checkout session to charge. When provided, amount and currency are derived from the session and any values sent are ignored.
wallet_typestringConditionalRequired when payment_method is wallet.
customer_idstringConditionalCustomer to attribute the charge to. Required with save_payment_instrument, and with credential_on_file outside a checkout session; recommended otherwise for saved-credential resolution.
payer_ipstringNoThe payer's IP address (IPv4 or IPv6) — where the customer is buying from, never your server's. Some providers require it on card charges. When omitted and the charge belongs to a checkout session, Tokeflow uses the IP the payer opened the Bridge SDK session from.
external_order_idstringNoYour order reference, stored for reconciliation.
capturebooleanNotrue (default) = auth + capture in one step. false = pre-authorize only; capture later.
risk_scoreintegerNoPre-auth fraud score from 0 to 100. Stored on the transaction.
installmentsobjectNoInstallment plan details, where supported.
payer_token_idstringNoPayer token (ptk_…) from the Bridge SDK's pix.tokenize() or boleto.tokenize(). Supplies the payer of a PIX or boleto charge, so your server never handles the CPF/CNPJ or address. Single use, bound to its payment method and checkout session. See PIX and boleto payers.
boletoobjectNoBoleto options, read only when payment_method is boleto. expires_in_days: days until the boleto is due, 1–30, default 3. A due date on a weekend moves to the next business day.
idempotency_keystringNoPrevents duplicate charges. Can also be sent as the Idempotency-Key header.
metadataobjectNoArbitrary key-value pairs stored on the transaction.

Always send an idempotency key on creation. Pass a unique value per charge attempt as the Idempotency-Key header (or idempotency_key in the body). If a network hiccup makes you retry, replaying the same key returns the original transaction (HTTP 200) instead of charging the customer twice. See Idempotency and rate limits.

Response codes

CodeWhen
201 CreatedFirst submission of this transaction. Inspect status for the result.
200 OKIdempotent replay — the same Idempotency-Key was seen before; the original transaction is returned.
400 Bad RequestInvalid parameters or missing required fields.
401 UnauthorizedMissing or invalid API key.
403 ForbiddenAuthenticated but missing the required scope.

Example request

curl -X POST https://api.tokeflow.com/api/v1/transactions \
  -H "Authorization: Bearer sk_live_mer_…" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: order_12345_attempt_1" \
  -d '{
    "payment_method": "credit_card",
    "charge_type": "payment",
    "country": "BR",
    "amount": 15000,
    "currency": "BRL",
    "customer_id": "cust_123",
    "external_order_id": "order_888",
    "card_ciphertext_id": "tok_8f3c2a1b9d4e",
    "capture": true,
    "metadata": { "campaign": "black_friday" }
  }'

Example response — 201 Created

{
  "success": true,
  "data": {
    "id": "tx_777",
    "organization_id": "org_123",
    "merchant_id": "mrc_123",
    "order_id": "ord_001",
    "subscription_id": null,
    "external_order_id": "order_888",
    "customer_id": "cust_123",
    "payment_instrument_id": null,
    "amount_authorized": 15000,
    "amount_captured": 15000,
    "currency": "BRL",
    "payment_method": "credit_card",
    "charge_type": "payment",
    "country": "BR",
    "status": "authorized",
    "applied_routing_rule_id": "node_2",
    "mode": "live",
    "timeline": [
      {
        "attempt_number": 1,
        "is_fallback": false,
        "connector_id": "conn_a1b2c3",
        "provider_slug": "acquirer_a",
        "status": "failed",
        "started_at": "2026-01-15T12:30:00.000Z",
        "finished_at": "2026-01-15T12:30:02.000Z",
        "error_category": "SOFT_DECLINE",
        "error_code": "INSUFFICIENT_FUNDS",
        "decline_reason": "insufficient_funds"
      },
      {
        "attempt_number": 2,
        "is_fallback": true,
        "connector_id": "conn_d4e5f6",
        "provider_slug": "acquirer_b",
        "status": "success",
        "started_at": "2026-01-15T12:30:02.000Z",
        "finished_at": "2026-01-15T12:30:04.000Z",
        "error_category": null,
        "error_code": null,
        "decline_reason": null
      }
    ],
    "payment_instructions": null,
    "metadata": { "campaign": "black_friday" },
    "created_at": "2026-01-15T12:30:00.000Z",
    "updated_at": "2026-01-15T12:30:04.000Z"
  },
  "request_id": "req_8f3c",
  "timestamp": "2026-01-15T12:30:04.000Z"
}

The example above shows a cascade: the primary connector declined, and Tokeflow's fallback authorized the charge — all in one API call.

A provider decline returns 201 with status: "failed" and an explanatory timeline, not an HTTP error. Branch on status. See The timeline for the fields that explain a failure.

Async methods (PIX and boleto)

For PIX and boleto, the response carries payment_instructions instead of an immediate authorization. The transaction stays pending until the customer pays; the final status arrives via webhook. Return payment_instructions to the browser so the customer can pay.

FieldMethodDescription
typebothpix or boleto.
qr_code_textPIXThe copy-and-paste ("copia e cola") code.
qr_code_urlPIXProvider-hosted QR code image.
digitable_lineBoletoThe linha digitável — the 47 digits the payer types into their bank app.
barcodeBoletoThe 44-digit barcode content.
boleto_urlBoletoProvider-hosted slip (PDF or instructions page).
due_dateBoletoDue date in Brasília time, YYYY-MM-DD, after any weekend roll-forward.
expires_atbothWhen the payment can no longer be made (ISO 8601).
{
  "success": true,
  "data": {
    "id": "tx_778",
    "status": "pending",
    "payment_method": "pix",
    "amount_authorized": 0,
    "amount_captured": 0,
    "currency": "BRL",
    "payment_instructions": {
      "type": "pix",
      "qr_code_text": "00020126580014BR.GOV.BCB.PIX…",
      "qr_code_url": "https://example.com/qrcode/image.png",
      "expires_at": "2026-01-15T13:00:00.000Z"
    },
    "timeline": [
      {
        "attempt_number": 1,
        "is_fallback": false,
        "connector_id": "conn_a1b2c3",
        "provider_slug": "acquirer_a",
        "status": "pending",
        "started_at": "2026-01-15T12:30:00.000Z",
        "finished_at": null,
        "error_category": null,
        "error_code": null,
        "decline_reason": null
      }
    ],
    "created_at": "2026-01-15T12:30:00.000Z",
    "updated_at": "2026-01-15T12:30:00.000Z"
  },
  "request_id": "req_9a2d",
  "timestamp": "2026-01-15T12:30:00.000Z"
}

A boleto charge returns the slip instead:

"payment_instructions": {
  "type": "boleto",
  "digitable_line": "23793381286000782713695000063305975520000370000",
  "barcode": "23799755200003700003381260007827139500006330",
  "boleto_url": "https://example.com/boleto/tx_779.pdf",
  "due_date": "2026-10-29",
  "expires_at": "2026-10-30T02:59:59.000Z"
}

PIX and boleto payers

PIX and boleto need the payer's details — name, email and CPF/CNPJ, plus a full billing address for a boleto. The recommended way to collect them is a payer token: the Bridge SDK registers the payer from the browser and returns a ptk_…, and your server charges it with payer_token_id:

{
  "payment_method": "boleto",
  "charge_type": "payment",
  "country": "BR",
  "amount": 10000,
  "currency": "BRL",
  "external_order_id": "order_123",
  "payer_token_id": "ptk_abc123",
  "boleto": { "expires_in_days": 3 }
}
RuleDetail
Single useA token is spent by the charge that uses it — even a failed one — and expires 30 minutes after creation. Send an Idempotency-Key so a retried request replays the charge instead of needing a new token.
BoundThe token is valid only for the payment_method it was collected for and, when collected inside a checkout session, only with that checkout_session_id.
RefusedA token that is unknown, used, expired, collected for the other method or for another session is refused with 400 and code INVALID_PAYER_TOKEN. Nothing is charged.
CustomerThe token's email alone never links the charge to an existing customer, since anyone can type any email in a browser. To attribute the charge, send customer_id, or send the same email from your server.
PrecedenceThe token's payer details win over payer details your server sends.

Without a payer token, the payer comes from the customer you name with customer_id and its stored details. A boleto whose payer is missing a required field is refused before it reaches a provider.


GET/api/v1/transactions

OrgMerchant

Auth: Organization key (with merchant_id) or Merchant key. Scope: transactions:read.

Returns a paginated list of transactions, newest first.

Query parameters

FieldTypeRequiredDescription
statusstringNoFilter by status. Repeatable or comma-separated for multiple (e.g. status=refunded,partially_refunded).
merchant_idstringConditionalRequired with an Organization key; inferred from a Merchant key.
customer_referencestringNoFilter by customer reference.
order_idstringNoFilter by order.
payment_methodstringNoFilter by payment method.
currencystringNoFilter by ISO 4217 currency code.
date_fromstringNoCreated on or after this timestamp (ISO 8601).
date_tostringNoCreated on or before this timestamp (ISO 8601).
pageintegerNoPage number (default 1, min 1).
limitintegerNoItems per page (default 20, max 100).

Example request

curl -G https://api.tokeflow.com/api/v1/transactions \
  -H "Authorization: Bearer sk_live_mer_…" \
  --data-urlencode "status=authorized,refunded" \
  --data-urlencode "currency=BRL" \
  --data-urlencode "date_from=2026-01-01T00:00:00Z" \
  --data-urlencode "page=1" \
  --data-urlencode "limit=20"

Example response — 200 OK

{
  "success": true,
  "data": [
    {
      "id": "tx_777",
      "organization_id": "org_123",
      "merchant_id": "mrc_123",
      "order_id": "ord_001",
      "external_order_id": "order_888",
      "customer_id": "cust_123",
      "amount_authorized": 15000,
      "amount_captured": 15000,
      "currency": "BRL",
      "payment_method": "credit_card",
      "charge_type": "payment",
      "country": "BR",
      "status": "authorized",
      "applied_routing_rule_id": "node_2",
      "mode": "live",
      "timeline": [
        {
          "attempt_number": 1,
          "is_fallback": false,
          "connector_id": "conn_a1b2c3",
          "provider_slug": "acquirer_a",
          "status": "success",
          "started_at": "2026-01-15T12:30:00.000Z",
          "finished_at": "2026-01-15T12:30:02.000Z",
          "error_category": null,
          "error_code": null,
          "decline_reason": null
        }
      ],
      "payment_instructions": null,
      "metadata": {},
      "created_at": "2026-01-15T12:30:00.000Z",
      "updated_at": "2026-01-15T12:30:02.000Z"
    }
  ],
  "meta": {
    "pagination": {
      "page": 1,
      "limit": 20,
      "total": 42,
      "total_pages": 3,
      "has_next": true,
      "has_prev": false
    }
  },
  "request_id": "req_3b7e",
  "timestamp": "2026-01-15T12:30:05.000Z"
}

GET/api/v1/transactions/:id

OrgMerchant

Auth: Organization key (any transaction in the org) or Merchant key (its own transactions). Scope: transactions:read.

Retrieves a single transaction, including its full routing timeline. Returns the transaction object.

Example request

curl https://api.tokeflow.com/api/v1/transactions/tx_777 \
  -H "Authorization: Bearer sk_live_mer_…"

Example response — 200 OK

{
  "success": true,
  "data": {
    "id": "tx_777",
    "merchant_id": "mrc_123",
    "amount_authorized": 15000,
    "amount_captured": 15000,
    "currency": "BRL",
    "payment_method": "credit_card",
    "charge_type": "payment",
    "country": "BR",
    "status": "authorized",
    "applied_routing_rule_id": "node_2",
    "mode": "live",
    "timeline": [
      {
        "attempt_number": 1,
        "is_fallback": false,
        "connector_id": "conn_a1b2c3",
        "provider_slug": "acquirer_a",
        "status": "success",
        "started_at": "2026-01-15T12:30:00.000Z",
        "finished_at": "2026-01-15T12:30:02.000Z",
        "error_category": null,
        "error_code": null,
        "decline_reason": null
      }
    ],
    "payment_instructions": null,
    "metadata": {},
    "created_at": "2026-01-15T12:30:00.000Z",
    "updated_at": "2026-01-15T12:30:02.000Z"
  },
  "request_id": "req_5c1a",
  "timestamp": "2026-01-15T12:30:06.000Z"
}

A 404 (not_found_error) is returned if the transaction does not exist or does not belong to the authenticated merchant.


GET/api/v1/transactions/:id/attempts

OrgMerchant

Auth: Organization key (any transaction in the org) or Merchant key (its own transactions). Scope: transactions:read.

Returns every individual provider attempt for a transaction, with more detail than the inline timeline — including 3DS status, normalized error messages, and gateway fees. Use it to debug declines and analyze routing behavior.

Attempt fields

FieldTypeDescription
idstringAttempt ID.
payment_transaction_idstringParent transaction, prefixed tx_.
merchant_connector_idstringConnector used for this attempt.
provider_slugstringNeutral provider slug.
attempt_numberinteger1-based sequence number.
is_fallbackbooleanWhether the attempt ran as a fallback.
statusstringpending, success, failed, or error.
three_ds_statusstring | null3DS authentication outcome, when applicable.
error_categorystring | nullHigh-level error class, on failure.
error_codestring | nullNormalized error code, on failure.
decline_reasonstring | nullTokeflow's reason for the failure, the same value whichever provider answered. See Decline reasons.
error_messagestring | nullHuman-readable error, on failure.
psp_transaction_idstring | nullProvider-side transaction reference.
gateway_feeinteger | nullProcessing fee as reported by the provider, in minor units. Null when the provider did not report one; some providers report it only later, and it is filled in when it arrives.
started_atstringWhen the attempt began (ISO 8601 UTC).
finished_atstring | nullWhen the attempt resolved (ISO 8601 UTC).

Example request

curl https://api.tokeflow.com/api/v1/transactions/tx_777/attempts \
  -H "Authorization: Bearer sk_live_mer_…"

Example response — 200 OK

{
  "success": true,
  "data": [
    {
      "id": "att_1",
      "payment_transaction_id": "tx_777",
      "merchant_connector_id": "conn_a1b2c3",
      "provider_slug": "acquirer_a",
      "attempt_number": 1,
      "is_fallback": false,
      "status": "failed",
      "three_ds_status": null,
      "error_category": "SOFT_DECLINE",
      "error_code": "INSUFFICIENT_FUNDS",
      "decline_reason": "insufficient_funds",
      "error_message": "Issuer declined: insufficient funds",
      "psp_transaction_id": "psp_tx_123",
      "gateway_fee": null,
      "started_at": "2026-01-15T12:30:00.000Z",
      "finished_at": "2026-01-15T12:30:02.000Z"
    },
    {
      "id": "att_2",
      "payment_transaction_id": "tx_777",
      "merchant_connector_id": "conn_d4e5f6",
      "provider_slug": "acquirer_b",
      "attempt_number": 2,
      "is_fallback": true,
      "status": "success",
      "three_ds_status": "authenticated",
      "error_category": null,
      "error_code": null,
      "decline_reason": null,
      "error_message": null,
      "psp_transaction_id": "psp_tx_456",
      "gateway_fee": 45,
      "started_at": "2026-01-15T12:30:02.000Z",
      "finished_at": "2026-01-15T12:30:04.000Z"
    }
  ],
  "request_id": "req_7d2f",
  "timestamp": "2026-01-15T12:30:07.000Z"
}

POST/api/v1/transactions/:id/capture

OrgMerchant

Auth: Organization key (any transaction in the org) or Merchant key (its own transactions). Scope: transactions:write.

Captures a transaction that was pre-authorized with capture: false. The transaction must be in capture_pending status; after a successful capture it becomes authorized.

Request fields

FieldTypeRequiredDescription
amountintegerNoAmount to capture, in minor units. Omit to capture the full authorized amount. For a partial capture, must be ≤ amount_authorized.

Most providers allow only one capture per authorization. On a partial capture, the uncaptured remainder is automatically released.

Capture and void on the same authorization never both win. If a void (yours, or one the provider reports) settles the transaction while a capture is in flight, or a capture at a different amount lands first, the losing call answers 409 (conflict_error) — the provider may already have acted, so read the transaction back with GET /transactions/:id instead of retrying. A capture that finds the same capture already recorded returns that transaction with 200.

Example request — full capture

curl -X POST https://api.tokeflow.com/api/v1/transactions/tx_777/capture \
  -H "Authorization: Bearer sk_live_mer_…" \
  -H "Content-Type: application/json" \
  -d '{}'

Example request — partial capture

curl -X POST https://api.tokeflow.com/api/v1/transactions/tx_777/capture \
  -H "Authorization: Bearer sk_live_mer_…" \
  -H "Content-Type: application/json" \
  -d '{ "amount": 10000 }'

Example response — 200 OK

{
  "success": true,
  "data": {
    "id": "tx_777",
    "merchant_id": "mrc_123",
    "amount_authorized": 15000,
    "amount_captured": 15000,
    "currency": "BRL",
    "payment_method": "credit_card",
    "charge_type": "payment",
    "country": "BR",
    "status": "authorized",
    "applied_routing_rule_id": "node_2",
    "mode": "live",
    "timeline": [
      {
        "attempt_number": 1,
        "is_fallback": false,
        "connector_id": "conn_a1b2c3",
        "provider_slug": "acquirer_a",
        "status": "success",
        "started_at": "2026-01-15T12:30:00.000Z",
        "finished_at": "2026-01-15T12:30:02.000Z",
        "error_category": null,
        "error_code": null,
        "decline_reason": null
      }
    ],
    "payment_instructions": null,
    "metadata": {},
    "created_at": "2026-01-15T12:30:00.000Z",
    "updated_at": "2026-01-15T12:35:00.000Z"
  },
  "request_id": "req_a4e9",
  "timestamp": "2026-01-15T12:35:00.000Z"
}

A 400 (validation_error) is returned if the transaction is not in capture_pending status or the amount exceeds the authorized amount.


POST/api/v1/transactions/:id/void

OrgMerchant

Auth: Organization key (any transaction in the org) or Merchant key (its own transactions). Scope: transactions:write.

Voids an authorization before it is captured, releasing the held funds. The transaction must be in capture_pending or authorized status; after voiding it becomes voided.

Example request

curl -X POST https://api.tokeflow.com/api/v1/transactions/tx_777/void \
  -H "Authorization: Bearer sk_live_mer_…"

Example response — 200 OK

{
  "success": true,
  "data": {
    "id": "tx_777",
    "status": "voided",
    "updated_at": "2026-01-15T12:36:00.000Z"
  },
  "request_id": "req_b8c0",
  "timestamp": "2026-01-15T12:36:00.000Z"
}

A 400 (validation_error) is returned if the transaction is not in a voidable status. A void that loses to a capture already recorded answers 409 (conflict_error); a void that finds the hold already released by the provider succeeds.

To reverse funds after capture, issue a refund instead of a void. See Refunds.


Errors

Every error uses the standard envelope. The most common cases for this resource:

HTTPtypeTypical cause
400validation_errorMissing required field, an invalid combination of card-source fields (payment_instrument_id alone, credential_on_file with a ciphertext, a one_time ciphertext with save_payment_instrument, an instrument with no stored credential yet), an unusable payer_token_id (INVALID_PAYER_TOKEN), or capture/void in the wrong state.
401authentication_errorMissing or invalid API key.
403authorization_errorKey lacks the required scope.
404not_found_errorTransaction not found or not owned by the merchant.
409conflict_errorA capture and a void raced on the same authorization and this call lost. Read the transaction back; do not retry blindly.
422business_rule_errorNo eligible connector for the charge — for example the currency, card brand or installment plan is not supported by the connector routing selected or pinned.
429rate_limit_errorRate limit exceeded — back off exponentially.

See Errors for the full envelope and type catalog.

On this page