Developer Docs
English
English
Receive HTTPS signed notifications every time an operation or a flow changes state. Your system stays in sync in real time without polling.
A few examples of what you'll receive: an operation being opened, a successful payment, a rejection, a flow expiry, or cancellations performed via the API. Every webhook is signed with HMAC-SHA256 for authenticity and integrity, using webhooks instead of polling cuts latency, traffic and integration complexity.
webhookSecret Provide Zertiban with:
businessUuidhttps://yourapp.com/webhooks/zertiban)Zertiban will register the webhook and give you the webhookSecret you'll use to verify that each notification you receive is authentic.
Endpoint requirements:
POST requests2xx to acknowledge receipt (see timing and retries in Delivery & Retries)Local development
For local development use ngrok: ngrok http 3000 gives you a public URL you can hand to Zertiban to register temporarily in sandbox.
All webhooks share the same structure. Only eventType and the resource data change. The key order is the one actually sent:
{
"metadata": {
"apiVersion": "v1",
"businessUuid": "3b90ee0e-f85e-4591-a0b2-5c785a860334"
},
"eventType": "OPERATION_COMPLETED",
"eventUuid": "13e83b92-13d8-5b6d-94c0-05feb58d3189",
"timestamp": "2026-09-17T09:41:12.480Z",
"resource": {
"uuid": "bd51a1af-7779-4010-a876-0630851a1858",
"externalId": "OP-2026-000123",
"status": "COMPLETED"
}
}| Field | Description |
|---|---|
metadata.apiVersion | API version (v1) |
metadata.businessUuid | Organisation that owns the resource. It is the same value in the copy the organisation receives and in the one its collaborator receives. |
metadata.collaboration.businessUuid | Only when the event is attributed to a collaborator. See Collaborator attribution. |
eventType | Event type (see Event Reference) |
eventUuid | Identifier of the originating event. It is identical across all its copies and all its retries. Use it to deduplicate. |
timestamp | When the change occurred in Zertiban — not the send time, nor the retry time. ISO 8601 in UTC. See The two timestamps. |
resource | Depends on the event family: flows and operations carry uuid, externalId and status; organisations carry uuid and status; PSD2 payments carry paymentUuid and psd2Payment.status. |
resource.uuid | UUID of the resource: the operation, the flow or the organisation |
resource.externalId | Your externalId set on the operation or flow at creation time (invoice number, order ID, collection reference, ERP key…). Use it to reconcile against your system without storing Zertiban UUIDs. |
resource.status | Current status of the resource |
Two parsing details that break integrations
The fractional seconds in timestamp can carry either 3 or 6 digits, so parse it as an instant rather than with a fixed pattern.
resource.externalId travels as a literal null when it does not exist: it is never omitted. BUSINESS_* events do not carry it at all.
A collaborator is another Zertiban organisation acting on behalf of the owning organisation — for example, the Partner or Agent that created the flow or registered the organisation. Any event type can arrive attributed.
When it does, the webhook is delivered to the organisation and also to the collaborator, provided both have that type subscribed. Each copy goes to its recipient's URL and is signed with its recipient's key, but the body is identical: metadata.businessUuid is still the owning organisation, and metadata.collaboration.businessUuid identifies the attributed collaborator, not the recipient of that copy.
The collaboration key is omitted when there is no attribution.
| Header | Value |
|---|---|
User-Agent | Zertiban Webhooks Service |
Content-Type | application/json |
zb-timestamp | Unix milliseconds when this request was sent, changes on retries |
zb-signature | HMAC-SHA256, see Signature Verification |
Every webhook carries two timestamps that answer different questions. They will typically not match, so pick the one that fits what you need to do.
zb-timestamp (header) | timestamp (body) | |
|---|---|---|
| Means | The moment Zertiban sent this HTTP request | The moment the event that triggered the webhook occurred |
| Format | Unix epoch in milliseconds — 1775035202150 | ISO 8601 date-time — 2026-04-01T09:20:00Z |
| On retries | Changes on every attempt | Identical across every attempt of the same event |
| Use it for | Signature verification and replay protection | Ordering and reconciliation against your own records |
timestamp is always ≤ zb-timestamp: the event happens first, the delivery comes afterwards. The gap is normally milliseconds, but it widens with every retry and with each batch reprocessing cycle.
zb-timestamp is part of the signed message, so recompute the HMAC with exactly the value received (see Signature Verification). It is also the value to compare against your own clock if you decide to add replay protection — the best practices on that page describe the window.
timestamp is the time the underlying action happened — for example, the moment an operation transitioned to COMPLETED. It is the value to store next to the resource, show to your users, and use to decide which of two events is the more recent (see Ordering and out-of-order delivery).
Never order events by zb-timestamp
A retried event is delivered after the attempts that failed, so it can arrive behind an event that was emitted later. Delivery order does not reflect the order things happened: order by the body timestamp, never by zb-timestamp or by arrival order.