Skip to content
Developer resourcesWebhooks

Receive Tokenz events in your webhook endpoint

Listen to events in your Tokenz account on your webhook endpoint so your integration can automatically trigger reactions.

Amount format: Monetary values in webhook payloads (such as amount fields) are expressed in the smallest minor unit of each currency. See Supported currencies for the exact encoding per currency.

Why use webhooks

When building Tokenz Checkout integrations, your applications should receive events as they occur in your account so that your backend systems can execute actions accordingly.

To enable webhook events, you need to register webhook endpoints. After registering them, Tokenz can push real-time event data to your application's webhook endpoint when events happen in your Tokenz account. Tokenz uses HTTPS to send webhook events to your app as a JSON payload with an Event object.

We strongly recommend implementing webhooks in addition to handling redirects from our checkout to ensure that you always receive notification of the checkout result.

Event object

When an event occurs, Tokenz generates a new Event object. A single API request might create multiple events.

By registering webhook endpoints in your Tokenz account, you enable Tokenz to automatically send Event objects as part of POST requests to the registered webhook endpoint hosted by your application. After your webhook endpoint receives the Event, your app can run backend actions (for example, sending the customer a download link for their purchased item or topping up their account balance after you receive an order.succeeded event).

The Event object we send to your webhook endpoint provides a snapshot of the changed object. The webhook always contains the full object on which the event occurred, along with event metadata.

Example event payload

The following example shows an Event sent for a successful order.

json
{
    "id": "a1b2c3d4-e5f6-7g8h-9i0j-k1l2m3n4o5p6",
    "object": "order.succeeded",
    "createdAt": "2025-09-24T03:22:20.297Z",
    "test": true,
    "eventData": {
        "type": "order",
        "version": "v2",
        "data": {
            "order": {
                "id": "order_1D5xA9BnKfv_t",
                "object": "order",
                "status": "succeeded",
                "amount": {
                  "amount": 3700,
                  "currency": "JPY"
                },
                "items": [
                  {
                    "id": "item_1D6F8mR5TnK_t",
                    "detail": {
                      "product": {
                        "price": {
                          "amount": 1200,
                          "currency": "JPY"
                        },
                        "quantity": 3,
                        "label": "ひとにぎりのエメラルド",
                        "description": "80+8",
                        "images": [
                          "https://images.ctfassets.net/z82qbo7cv7ia/1dWPbk5Qx2M1Qikj6Knyuc/e37b2c26829c0d30793a348ae3adb3b0/fake-pass.webp"
                        ]
                      }
                    }
                  },
                  {
                    "id": "item_1xejV7puGeK_t",
                    "detail": {
                      "product": {
                        "price": {
                          "amount": 100,
                          "currency": "JPY"
                        },
                        "quantity": 1,
                        "label": "Diamond",
                        "description": "",
                        "images": [],
                        "sku": "sku_103843dfjhdfgiu",
                        "taxCategory": "VIRTUAL_CURRENCY"
                      }
                    }
                  }
                ],
                "description": "Game items purchase",
                "reference": "ORDER_2024_001",
                "test": true,
                "expiresAt": "2024-12-31T23:59:59Z",
                "createdAt": "2024-01-15T10:00:00Z",
                "updatedAt": "2024-01-15T10:05:30Z"
            }
        }
    }
}

Live and test mode

You might receive event delivery requests for both live and test mode to your endpoints if you use a single endpoint for both live and test mode. Use the test flag to check whether the object exists in live or test mode and determine the correct handling for the event.

Version

The version indicates the API version of the event and dictates the structure of the included data.object.

Types of events

Scroll horizontally if needed
TYPEDESCRIPTION
order.createdA new order is created via the Create a Checkout Session endpoint.
order.succeededAn order was successfully paid by your customer. You can deliver the items to the customer.
order.expiredAn order has expired.
order.canceledAn order has been canceled.
order.failedAn order payment has failed.
refund.createdA refund has been created.
refund.failedA refund has failed.
dispute.createdA dispute has been created.
dispute.closedA dispute has been closed.
redemption.completedA Gift Code has been redeemed or a Free Item has been claimed. The redemption kind identifies the flow (source is deprecated); code is omitted for Free Item claims.

Retries and idempotency

Tokenz expects your endpoint to acknowledge a webhook with a 2xx response. If your endpoint responds with any other status code, times out, or is unreachable, Tokenz automatically retries delivery for up to three days. The first retries are attempted approximately 5 seconds, 15 seconds, and 30 seconds after a failed delivery. Later retries use increasing delays and become less frequent over time. Retry timing may vary slightly; do not depend on an exact later-attempt schedule. Test-mode webhook deliveries may use a different retry policy, so do not use them to measure or validate live-mode retry timing. Once your endpoint returns a 2xx response, Tokenz stops retrying that event. Your endpoint can receive the same event more than once, and events can arrive out of order.

Handle deliveries idempotently:

  • Respond with a 2xx as soon as the event is safely received, and do any heavy processing asynchronously.
  • Use the event's top-level id as an idempotency key: record the event ids you have processed and skip any event you have already handled, so a retried delivery cannot double-fulfill an order.

Troubleshooting: my endpoint isn't receiving events

Almost always, "the webhook never arrived" means Tokenz did send it and your endpoint rejected it. Tokenz treats any non-2xx response (or a timeout or unreachable endpoint) as a failed delivery and automatically retries for up to three days — so from your side it can look like nothing arrived, while Tokenz keeps seeing the same delivery fail (for example, a run of HTTP 400s).

Because Tokenz does not expose a per-endpoint delivery log, diagnose from your own endpoint:

1. Check the HTTP status your endpoint returned. This is exactly what Tokenz sees — look in your server's access/error logs for the incoming POSTs.

  • 2xx — the event was delivered and acknowledged. If your system still didn't act on it, the problem is in your handler after the response, not in delivery.
  • 400, 401, 403 — your endpoint received the event but rejected it (see below).
  • 5xx or a timeout — your handler errored or was too slow to respond.

2. If you're returning 400, check signature verification first — it's the most common cause:

  • Verify over the raw request body. Most frameworks parse and re-serialize JSON, which changes the bytes and breaks the HMAC. Read the exact raw bytes (for example with express.raw()), verify, and only then parse. See Secure your webhook endpoint.
  • Use the correct signing secret. It is shown only once when you register the endpoint and is specific to that endpoint; a rotated or mistyped secret fails every event.
  • Match test and live mode. A test-mode event verified against your live signing secret (or the reverse) will never match. If one endpoint serves both, choose the secret using the event's test flag.
  • Watch for clock skew. If you reject on the 5-minute timestamp tolerance, a badly skewed server clock can reject otherwise-valid events.

3. Other causes of a non-2xx response:

  • A firewall, WAF, or IP allowlist in front of your endpoint blocking Tokenz's request.
  • The endpoint is not publicly reachable over HTTPS, or the URL registered in the dashboard is wrong or points at the wrong environment.
  • Heavy work in the request path causing a timeout — acknowledge with a 2xx first, then process asynchronously.

4. Confirm delivery independently. Point your endpoint (or a copy of it) at Webhook.site to confirm Tokenz is delivering and to inspect the exact payload and headers, then trigger an event with a test-mode payment.

Once your endpoint returns 2xx, retries stop. Because a retry can re-send an event you already processed, keep your handler idempotent (see above).