Skip to main content
Treat every webhook as untrusted input until you have verified it and reconciled it against the Transactions API.

Signature

Each delivery includes an X-Zeam-Signature header of the form sha256=<hex>, where <hex> is an HMAC-SHA256 of the exact raw request body. The HMAC key is the X-Webhook-Id header value — the UUID that uniquely identifies this delivery. To verify, recompute the HMAC over the raw body bytes and compare it to the header using a constant-time comparison. Use the raw bytes before any JSON parsing or re-serialisation.
The HMAC key is the X-Webhook-Id value — a per-delivery UUID that is transmitted in the same request. This protects against accidental corruption and casual tampering but is not strong proof of origin, since the key is visible to anyone who intercepts the delivery. Always:
  • require HTTPS and validate TLS on your endpoint;
  • treat the signature as an integrity check, not authentication;
  • reconcile every event against the Transactions API before acting;
  • restrict who can reach your endpoint where you can.

Replay protection

Each delivery includes an X-Webhook-Ts header containing the delivery timestamp as Unix milliseconds (UTC). Use it to reject stale deliveries and narrow the window in which a captured request could be replayed:
Combine the timestamp window with X-Webhook-Id deduplication: persist each processed X-Webhook-Id and ignore any delivery whose ID you have already seen, regardless of timestamp.

Build an idempotent consumer

  • Persist a processed-event key (the X-Webhook-Id, or intentId plus event type) and ignore duplicates.
  • Return a 2xx for an event you have already processed.
  • Separate acknowledgement from processing: acknowledge fast, then process on a background worker.
  • Log deliveries safely. Never log the raw signature key, tokens, or full personal data.
  • Reconcile webhook state with the Transactions API rather than trusting the event in isolation.

IP allowlisting

Zeam does not currently publish a fixed set of delivery IP addresses, so do not rely on IP allowlisting as your only control. Use signature verification and reconciliation instead.