Skip to main content
We use Svix to deliver webhook events. You can manage your endpoints from the Webhook section in the dashboard

Events

EventDescription
checkout.completedA checkout payment was completed successfully.
checkout.expiredA checkout expired without being completed.

Setting up endpoints

  1. Go to the Webhook section in your store’s dashboard.
  2. Add an endpoint URL (e.g. https://example.com/webhooks/zenobank).
  3. Select the event types you want to receive.

Payload format

checkout.completed

{
  "type": "checkout.completed",
  "data": {
    "id": "ch_l0k1o87yt6",
    "orderId": "order-12345",
    "priceCurrency": "USD",
    "priceAmount": "100.00",
    "status": "COMPLETED",
    "expiresAt": "2025-10-05T12:00:00Z",
    "checkoutUrl": "https://pay.zenobank.io/ch_l0k1o87yt6",
    "createdAt": "2025-10-04T10:00:00Z",
    "successRedirectUrl": "https://example.com/success"
  }
}

checkout.expired

{
  "type": "checkout.expired",
  "data": {
    "id": "ch_9xR3mPq2vW",
    "orderId": "order-67890",
    "priceCurrency": "USD",
    "priceAmount": "50.00",
    "status": "EXPIRED",
    "expiresAt": "2025-10-05T12:00:00Z",
    "checkoutUrl": "https://pay.zenobank.io/ch_9xR3mPq2vW",
    "createdAt": "2025-10-04T10:00:00Z",
    "successRedirectUrl": null
  }
}

Verifying webhooks

Every webhook request includes three headers used for signature verification:
HeaderDescription
svix-idUnique message identifier
svix-timestampUnix timestamp of the message
svix-signatureHMAC signature
Use the official Svix library to verify signatures. To find your signing secret, go to Developers, click on a webhook endpoint, and copy the Signing Secret on the right side. It starts with whsec_.

Install the Svix library

pnpm add svix

Verify the signature

You must use the raw request body when verifying webhooks. The cryptographic signature is sensitive to even the slightest changes. Watch out for frameworks that parse the request as JSON and then stringify it, as this will break the signature verification.
import { Webhook } from 'svix';

const secret = process.env.ZENO_WEBHOOK_SECRET; // whsec_...

const payload = rawBody; // raw request body as string
const headers = {
  'svix-id': request.headers.get('svix-id'),
  'svix-timestamp': request.headers.get('svix-timestamp'),
  'svix-signature': request.headers.get('svix-signature'),
};

const wh = new Webhook(secret);

try {
  const msg = wh.verify(payload, headers);
  const { type, data } = msg;

  switch (type) {
    case 'checkout.completed':
      // Payment successful — fulfill the order
      console.log(`Order ${data.orderId} completed`);
      break;
    case 'checkout.expired':
      // Checkout expired — notify the customer or cancel the order
      console.log(`Order ${data.orderId} expired`);
      break;
  }
} catch (err) {
  // Signature verification failed
  console.error('Invalid webhook signature');
}
Always verify the signature before processing the event. Never trust the payload without verification. You must use the raw request body — do not parse the JSON before verifying.
For framework-specific examples (Express, Next.js, Django, Flask, Laravel, Rails, etc.), see the Svix verification docs.

FAQ

If Zeno Bank does not receive a 2xx response from your webhook endpoint, we will retry the delivery.Each message is attempted based on the following schedule, where each period starts after the failure of the preceding attempt:
  • 5 seconds
  • 5 minutes
  • 30 minutes
  • 2 hours
  • 5 hours
  • 10 hours
Respond with any 2xx status code to acknowledge the event. You can monitor delivery attempts and manually retry from the Developers section in the dashboard.
Zeno Bank webhooks provide at-least-once delivery. Every event will be delivered to your endpoint at least once, but may be delivered more than once in rare cases (such as network timeouts where your server processed the event but the acknowledgement was lost).To handle duplicates, use the svix-id header included with every webhook request. This is a unique identifier for each event delivery. Store processed svix-id values and skip any duplicates.
Yes. Go to Developers in the dashboard, click on your webhook endpoint, find the event you want to retry, and click the replay button to resend it.
No. If you use one of our official plugins (WooCommerce, PrestaShop, WHMCS, etc.), webhooks are configured automatically. You don’t need to set up endpoints or verify signatures manually.