Skip to main content
Provide a webhookUrl when creating a checkout to receive lifecycle notifications. We currently emit a single event: checkout.completed.

Delivery

  • We POST JSON with Content-Type: application/json to the webhookUrl configured on the checkout.
  • On network errors or 5xx responses we retry up to 5 times with exponential backoff.
  • Respond with any 2xx status code to acknowledge the event.

Verifying Webhooks

Always verify incoming webhooks before processing them:
  1. Check the status: Ensure data.status is "COMPLETED" before fulfilling the order.
  2. Verify the token: Compare data.verificationToken with the token you provided when creating the checkout. This ensures the webhook is legitimate.

Event: checkout.completed

Sent when a checkout is marked as completed.
{
  "event": "checkout.completed",
  "id": "1e3e2cf0-3f89-48cf-b6c2-2e9d4dfd3c7f",
  "eventDate": "2025-09-18T17:15:26.969Z",
  "data": {
    "id": "ch_l0k1o87yt6",
    "orderId": "order-12345",
    "priceCurrency": "USD",
    "priceAmount": "0.01",
    "status": "COMPLETED",
    "expiresAt": "2025-10-05T12:00:00Z",
    "checkoutUrl": "https://pay.zenobank.io/ch_l0k1o87yt6",
    "createdAt": "2025-10-04T10:00:00Z",
    "webhookUrl": "https://example.com/webhooks/checkout",
    "successRedirectUrl": "https://example.com/success",
    "verificationToken": "123e4567-e89b-12d3-a456-426614174000"
  }
}
  • id is a UUIDv4 that uniquely identifies this event delivery.
  • eventDate is when we emitted the event.
  • data contains the checkout resource, including verificationToken so you can ensure the payload matches what you configured when creating the checkout.

Example Implementation

app.post('/webhooks/checkout', async (req, res) => {
  const { event, data } = req.body;

  // 1. Check if status is COMPLETED
  if (data.status !== 'COMPLETED') {
    return res.status(200).send('Not completed yet');
  }

  // 2. Verify the token matches what you sent when creating the checkout
  if (data.verificationToken !== process.env.VERIFICATION_TOKEN) {
    return res.status(400).send('Invalid verification token');
  }

  // 3. Process the order
  await fulfillOrder(data.orderId);

  return res.status(200).send('OK');
});