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.4. Redeliver events
Thewebhook-id header contains the event ID (evt_...). You can also find events with
GET /events and GET /events/{eventId}.
You can redeliver an event to a webhook for up to 90 days after the event was created, provided
that webhook was one of the event’s original destinations. The endpoint must be enabled, and another
manual redelivery for the same event and webhook cannot already be in progress. For a delegated
event, the exact delegation that authorized the original delivery must still be active and grant
access to that event type. Revoking it permanently closes redelivery for that event and webhook;
creating a new delegation does not reopen it.
POST /webhooks/{webhookId}/events/{eventId}/redeliver sends the stored event once and returns
202 Accepted with the pending redelivery. It takes no request body and requires an
Idempotency-Key header.
A redelivery keeps the original event payload and
webhook-id, but uses the webhook’s current URL
and active signing secret with a fresh webhook-timestamp and signature. Treat it as a possible
duplicate, and do not assume it will arrive in order relative to other events. Automatic retries
continue independently, even when the manual redelivery succeeds. The automatic and manual sends
can overlap, and another copy can arrive later. A manual failure does not contribute to automatic
endpoint disabling. A delegated redelivery is sent only to the same developer webhook that
received the original delivery. It does not fan out to the customer’s webhooks or any other
endpoint. Natural checks the original delegation again immediately before transmission. If it is
no longer valid, the redelivery is marked CANCELED and no request is sent. If authorization is
temporarily unavailable, Natural retries that check for a bounded period without consuming the
manual attempt; no request is sent unless authorization succeeds.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.