Webhooks overview
Receive normalized, signed payment events from Tokeflow in real time — configure endpoints, understand the event envelope, and handle delivery and retries.
Webhooks let your platform react to payment activity the moment it happens. As transactions, refunds, disputes, and subscriptions change state across your connected providers, Tokeflow POSTs a normalized JSON event to the HTTPS endpoint(s) you configure.
Instead of polling the API, you subscribe once and let events come to you. Because Tokeflow normalizes webhooks across every provider you orchestrate, you write one handler — not one per provider — and the event shape stays the same no matter which acquirer processed the charge.
Tokeflow is payment orchestration infrastructure. Webhooks describe the lifecycle of operations Tokeflow coordinates; the underlying processing and settlement are performed by your connected payment providers.
Why webhooks
| Outcome | How webhooks help |
|---|---|
| React in real time | Fulfill orders, grant access, or notify customers the instant a payment is authorized — no polling loop. |
| One handler, every provider | Events are normalized to a single schema, so provider-specific payloads never leak into your code. |
| Reliable delivery | Failed deliveries are retried with exponential backoff and recorded, so a brief outage on your side doesn't drop events. |
| Verifiable authenticity | Every request is signed with HMAC-SHA256 so you can confirm it came from Tokeflow and was not altered in transit. |
| Audit trail | Every delivery attempt is persisted and inspectable, giving you traceability for reconciliation and debugging. |
How delivery works
- An event occurs. A transaction, refund, dispute, payment method, or subscription changes state.
- Tokeflow builds a normalized event and signs it with your endpoint's signing secret.
- Tokeflow POSTs the event to each matching endpoint as a JSON request body.
- Your endpoint responds. A
2xxstatus (returned quickly) marks the delivery as succeeded. Anything else triggers a retry.
Configure your endpoints
You register webhook endpoints in the Tokeflow Dashboard during onboarding (and any time afterward). For each endpoint you provide:
| Setting | Description |
|---|---|
| Endpoint URL | A publicly reachable HTTPS URL that accepts POST requests. You can register more than one. |
| Event filter | An optional allowlist of event types. Omit it to receive every event type. |
| Signing secret | Generated when the endpoint is created — a value prefixed whsec_. Use it to verify signatures. |
Register separate endpoints for separate concerns — for example one URL for transaction.* events feeding fulfillment, and another for subscription.* events feeding your billing system. Each endpoint carries its own filter and signing secret.
The signing secret is shown when the endpoint is created. Store it securely (server-side only) — you'll need it to verify every incoming event. Treat it like any other credential.
The event envelope
Every webhook request body shares the same top-level shape. The data.object field carries the resource the event is about (a transaction, refund, subscription, and so on).
{
"id": "evt_8f3c2a1b9d7e4f60",
"type": "transaction.authorized",
"created_at": "2026-01-15T12:30:00.000Z",
"data": {
"object": {
"id": "tx_3n8Q2k1p7w",
"merchant_id": "mrc_7Yh2Kd9",
"external_order_id": "order-2026-0042",
"customer": {
"id": "cust_5Tg8Lp2",
"email": "buyer@example.com"
},
"previous_status": "pre_authorized",
"current_status": "authorized",
"amount_authorized": 15000,
"amount_captured": 15000,
"currency": "BRL",
"changed_at": "2026-01-15T12:30:00.000Z"
}
}
}| Field | Type | Description |
|---|---|---|
id | string | Unique event identifier (prefix evt_). Use it to deduplicate. |
type | string | The event type, e.g. transaction.authorized. |
created_at | string | ISO 8601 UTC timestamp of when the event was generated. |
data.object | object | The resource snapshot for this event. Its fields depend on type. |
Monetary amounts are integers in minor units (cents). 15000 with currency: "BRL" means R$150.00. Always pair an amount with its ISO 4217 currency.
What data.object contains
The shape of data.object depends on the event family. See Event types for the full catalog and per-resource fields.
| Event family | data.object represents | Example types |
|---|---|---|
| Transactions | A payment transaction | transaction.authorized, transaction.failed, transaction.voided |
| Refunds | A refund | transaction.refunded, transaction.partially_refunded, transaction.refund_failed |
| Disputes | A chargeback / dispute | transaction.dispute_created, transaction.dispute_won, transaction.dispute_lost |
| Payment methods | A stored payment instrument | payment_method.action_required |
| Subscriptions | A subscription | subscription.created, subscription.dunning, subscription.cancelled |
Request headers
Each delivery is an HTTP POST with a JSON body and these notable headers:
| Header | Description |
|---|---|
Content-Type | Always application/json. |
X-Tokeflow-Signature | HMAC signature of the event, in the form t=<unix-seconds>,v1=<hex>. |
User-Agent | Identifies the request as originating from Tokeflow's webhook delivery system. |
Always verify X-Tokeflow-Signature before trusting an event. The signature is computed over the raw request body bytes — read and verify the body before any JSON parsing or middleware re-serializes it. See Verifying signatures.
Responding to events
Your endpoint should acknowledge receipt fast and do the real work afterward.
- Respond
2xxwithin a few seconds. Return the response as soon as you've safely persisted the event (for example, enqueued it). Tokeflow treats any2xxas success. - Process asynchronously. Do slow work — fulfillment, emails, downstream calls — outside the request/response cycle so you never risk a timeout.
- Deduplicate by
id. Retries and at-least-once delivery mean the same eventidcan arrive more than once. Make handling idempotent: record processed event IDs and skip duplicates. - Don't depend on ordering. Events may arrive out of order, especially after a retry. Use the resource's status fields (and
changed_at) rather than assuming arrival order reflects the true sequence.
// Express example — acknowledge fast, process async.
// Use a raw body parser on this route so signature verification sees exact bytes.
import express from "express";
const app = express();
app.post(
"/webhooks/tokeflow",
express.raw({ type: "application/json" }),
(req, res) => {
// 1. Verify the signature against the raw body (see Verifying signatures).
if (!verifyTokeflowSignature(req)) {
return res.status(400).send("invalid signature");
}
const event = JSON.parse(req.body.toString("utf8"));
// 2. Deduplicate and enqueue for async processing.
enqueueForProcessing(event); // your job queue
// 3. Acknowledge immediately.
return res.status(200).send("ok");
},
);Delivery, failures, and retries
Tokeflow records every delivery attempt for every endpoint, so you can audit exactly what was sent and how your endpoint responded.
A delivery is considered successful only when your endpoint returns an HTTP 2xx. A delivery fails when it returns a non-2xx status, times out, or is unreachable. Each request has a delivery timeout of 30 seconds — keep handlers well under that.
When a delivery fails, Tokeflow retries with exponential backoff:
| Attempt | Delay after previous attempt |
|---|---|
| 1 | Immediate (initial delivery) |
| 2 | 1 minute |
| 3 | 5 minutes |
| 4 | 30 minutes |
| 5 | 2 hours |
| (final) | 24 hours |
After the retry schedule is exhausted, the delivery is abandoned and no further attempts are made. The full delivery history — status codes, response snippets, attempt counts, and next retry time — is retained for inspection.
Because a single endpoint outage can produce a burst of retries once you recover, design your consumer to absorb spikes: return 2xx quickly, enqueue, and process from the queue. Idempotency on event id keeps retried events from being applied twice.
A persistently failing endpoint will be retried up to the limit above and then abandoned for that event. If your endpoint is down for an extended period, you may miss events; reconcile against the API once you recover, and keep your handler idempotent so replays are safe.
Security checklist
- Verify every signature. Reject requests whose
X-Tokeflow-Signaturedoesn't validate against the raw body and yourwhsec_secret. - Enforce a timestamp tolerance. Reject events whose signature timestamp is outside a small window (for example, 5 minutes) to mitigate replay attacks.
- Use HTTPS only. Endpoints must be HTTPS so payloads and signatures are protected in transit.
- Keep secrets server-side. The webhook signing secret, like your
sk_*API keys, must never appear in browser or client code.
Next steps
- Event types — the full catalog of event types and the resource carried in
data.object. - Verifying signatures — validate
X-Tokeflow-Signaturestep by step. - Authentication — how API keys, scopes, and environments work.