Skip to content
Developer Docs

Webhooks ​

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.

Register your endpoint → get the webhookSecret ​

Provide Zertiban with:

  • Your businessUuid
  • The HTTPS URL of your endpoint (e.g. https://yourapp.com/webhooks/zertiban)
  • Environment: Sandbox or Production

Zertiban will register the webhook and give you the webhookSecret you'll use to verify that each notification you receive is authentic.

Endpoint requirements:

  • Publicly reachable over HTTPS
  • Accepts POST requests
  • Responds with 2xx 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.

Payload structure ​

All webhooks share the same structure. Only eventType and the resource data change. The key order is the one actually sent:

json
{
  "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"
  }
}

Payload fields ​

FieldDescription
metadata.apiVersionAPI version (v1)
metadata.businessUuidOrganisation that owns the resource. It is the same value in the copy the organisation receives and in the one its collaborator receives.
metadata.collaboration.businessUuidOnly when the event is attributed to a collaborator. See Collaborator attribution.
eventTypeEvent type (see Event Reference)
eventUuidIdentifier of the originating event. It is identical across all its copies and all its retries. Use it to deduplicate.
timestampWhen the change occurred in Zertiban — not the send time, nor the retry time. ISO 8601 in UTC. See The two timestamps.
resourceDepends 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.uuidUUID of the resource: the operation, the flow or the organisation
resource.externalIdYour 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.statusCurrent 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.

Collaborator attribution ​

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.

Headers on every request ​

HeaderValue
User-AgentZertiban Webhooks Service
Content-Typeapplication/json
zb-timestampUnix milliseconds when this request was sent, changes on retries
zb-signatureHMAC-SHA256, see Signature Verification

The two timestamps ​

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)
MeansThe moment Zertiban sent this HTTP requestThe moment the event that triggered the webhook occurred
FormatUnix epoch in milliseconds — 1775035202150ISO 8601 date-time — 2026-04-01T09:20:00Z
On retriesChanges on every attemptIdentical across every attempt of the same event
Use it forSignature verification and replay protectionOrdering 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.

Continue with ​