Webhooks
Receive signed events at your own URL when payments, refunds and terminals change.
ZyloPay sends an HTTP POST to your endpoint each time something happens in your account: a payment settles, a refund completes, a terminal is added. Webhooks are how your systems learn about payments that nobody asked about, such as a sale started by a cashier on the terminal.
The request
POST /zylopay/webhooks HTTP/1.1
Host: example.com
Content-Type: application/json; charset=utf-8
User-Agent: ZyloPay-Webhooks/1.0 (+https://docs.zylopay.com/webhooks)
ZyloPay-Signature: t=1790604160,v1=5257a869e7ecebeda32affa62cdca3fa51cad7e77a0e56ff536d0ce8e108d8bd
ZyloPay-Event-Id: evt_7Hq2Zp9LwK4mXr8Vb3Ns1Td5
ZyloPay-Event-Type: payment.succeeded
ZyloPay-Delivery-Id: wdl_8Tq3Zm1Xk6Pv9Rw2Lb4Ns7Hd
ZyloPay-Delivery-Attempt: 1
{"id":"evt_7Hq2Zp9LwK4mXr8Vb3Ns1Td5","object":"event","type":"payment.succeeded","api_version":"2026-09-28","livemode":false,"created":"2026-09-28T14:02:40.000Z","data":{"object":{"id":"pay_1042","object":"payment","…":"…"}}}The body is exactly the event object, the same as GET /v1/events/{id}. data.object is the object as it was when the event happened. The event types page lists every type and its payload.
Set up an endpoint
Build the handler. It must:
- read the raw request body, before any JSON parsing;
- verify the signature and reject anything that fails;
- record the event ID and ignore IDs it has already processed;
- answer
2xxwithin 10 seconds, then do slow work asynchronously.
Register the URL, in the dashboard (Developers → Webhooks → Add endpoint) or with the API:
const endpoint = await zp.webhookEndpoints.create({
url: 'https://example.com/zylopay/webhooks',
enabled_events: ['payment.succeeded', 'payment_intent.*', 'refund.*'],
description: 'Order service',
});The response contains the signing secret, whsec_…, once. Store it in your secrets manager.
Send a test event and check that your handler answers 2xx. See Testing webhooks.
Endpoint rules
- One mode. An endpoint belongs to the mode of the key or dashboard view that created it. It receives only that mode's events. Create one endpoint per mode.
- URL. Live endpoints must use
https. Test endpoints may usehttp. Ports 80, 443 and 1024-65535 only. No user name or password in the URL, no fragment. - Public addresses only. ZyloPay refuses URLs that resolve to private, loopback, link-local or reserved addresses (
localhost,10.0.0.0/8,192.168.0.0/16,169.254.169.254,*.internal…), when you create the endpoint and again at every delivery. Use a tunnel to receive events on a development machine. - No redirects. A
3xxanswer counts as a failure. - Up to 16 endpoints per mode.
- Subscriptions.
enabled_eventstakes exact types, families such asrefund.*, or*for all. Subscribe only to what you handle.
Security
- Always verify the signature. Anyone can send a
POSTto your URL. - The signature covers a timestamp, which stops old deliveries being replayed. See replay protection.
- Do not trust
data.objectfor high-value decisions without the signature check. If in doubt, re-read the object from the API.