Gozem Developer DocsDocs

Verify a webhook signature

Read the raw bytes, compare the HMAC in constant time, then acknowledge before doing the work.

Platform3 steps10 min

Your webhook URL is public. Anyone who finds it can post a courier.trip.completed, so check the signature before you act on anything.

It is an HMAC SHA-256 of the raw body, keyed with your webhook secret, sent in X-Webhook-Signature.

Read the raw bytes

The HMAC covers the exact bytes Gozem sent. Parse and re-encode, and your JSON writer will reorder keys or change spacing, and every signature fails.

Most frameworks discard the raw body, so ask for it explicitly.

Compare in constant time

== returns on the first differing byte. That timing difference is enough to recover a valid signature one byte at a time.

Use hmac.Equal, or timingSafeEqual in Node. Reject and return; do not log anything from a request that failed this.

Acknowledge, then work

Gozem retries if you do not return 2xx, and repeated failures disable the webhook. A handler that writes to four tables before responding will eventually look like a failure, so respond first and do the real work after.

recordEvent is your own idempotency store: it writes the guid and returns false if it was already there. Retries mean the same event arrives twice, and a unique index on that column is the whole implementation.

Before you ship

  • Branch on event_type and ignore ones you do not know. New types get added, and a handler that 500s on an unfamiliar one disables itself.
  • Return 5xx when your own storage is down. That is the one case where you want the retry.
  • Accept events over HTTPS only.
  • A gateway that rewrites bodies in transit breaks the signature. Worth checking first if it passes locally and fails on deploy.

Full event list and retry schedule: Webhooks.