1. Register an endpoint
POST /webhooks registers your URL and subscribes it to event types. The signing secret is returned once in the response; store it immediately.
enabledEvents accepts any event type from the Event catalog, or the wildcard "*" (which must be the only entry). description and tags are optional.
The
signingSecret (whsec_...) appears only in this response. If you lose it, rotate it with
POST /webhooks/{webhookId} /rotate-secret.2. Verify the signature
Every delivery is a POST whose JSON body is the event object. Three signature headers ride on each delivery (lowercase, per the Standard Webhooks spec):
Always verify before trusting a payload. Use the official
standardwebhooks library (Python and Node); construct it with your whsec_ secret and pass the raw body plus headers. verify returns the parsed event, or raises on a bad signature:
Verify against the raw request body, the exact bytes Natural sent. Parsing and re-serializing
the JSON first changes the bytes and breaks verification.
webhook-timestamp is outside a tolerance window (replay defense), and it accepts a delivery if any of the space-separated signatures verifies, which is what lets a secret rotation overlap two valid secrets.
Verify manually, without the library
Verify manually, without the library
The signed content is the string
{webhook-id}.{webhook-timestamp}.{body}. Strip the whsec_
prefix from the secret, base64-decode the remainder for the HMAC key, compute HMAC-SHA256, and
base64-encode the result. Compare it against each space-separated v1,<sig> entry.3. Delivery, retries & failures
Natural treats any 2xx response as success. The delivery request times out after 30 seconds. Failed deliveries (non-2xx, network error, or timeout) are retried up to 7 attempts total with jittered backoff (~20% jitter):An endpoint that fails every attempt for 5 consecutive events is automatically disabled. Re-enable
it with
PATCH /webhooks/{webhookId} once your endpoint
is healthy.Best practices
- Return 2xx fast. Acknowledge as soon as the signature verifies, then process the event asynchronously; slow handlers risk the 30-second timeout and trigger retries.
- Deduplicate on
webhook-id. Retries reuse the samewebhook-id, and Natural may deliver an event more than once; record processed IDs and skip duplicates. - Store the
whsec_secret in a secrets manager, never in source control. Rotate it withPOST /webhooks/{webhookId}/rotate-secret; the previous secret stays valid for the grace period you specify, so both signatures arrive during the overlap. - Don’t depend on event ordering. Retries and independent delivery mean events can arrive out of order; use the
versionfield on the resource snapshot, or refetch the resource, when ordering matters.