Skip to main content
WEBHOOK

Headers

webhook-id
string
required

The event id. It stays the same across retries and replays, so deduplicate on it.

webhook-timestamp
string
required

When sajn sent this attempt, in Unix seconds. Reject a timestamp older than your tolerance, such as five minutes.

webhook-signature
string

One or more space-separated signatures, v1,<base64 HMAC-SHA256>, over <webhook-id>.<webhook-timestamp>.<raw request body>. The key is the base64 decoding of the secret after whsec_. Accept the request when any signature matches; for 24 hours after a secret rotation, there is one per secret. Any Standard Webhooks library verifies it. Webhooks created without a secret don't send this header.

Sajn-Version
enum<string>
required

The endpoint's API version, the same value as apiVersion in the body.

Available options:
2026-10

Body

application/json
id
string
required

Event ID, also in webhook-id. It's the same on every retry, replay and endpoint that receives the event, so deduplicate on it. To read the event again, pass it to GET /api/v1/events/{id}.

type
enum<string>
required
Available options:
contact.deleted
createdAt
string<date-time>
required

When the event happened. It doesn't change across retries and replays.

apiVersion
enum<string>
required

The endpoint's API version, which sets the shape of data.

Available options:
2026-10
workspaceId
string
required
environment
enum<string>
required

SANDBOX for an event in a sandbox organization.

Available options:
PRODUCTION,
SANDBOX
actor
object | null
required

Who caused the event. Null when sajn can't attribute it: a party's action, such as signing, and most changes made in the sajn app.

data
object
required

Response

200

Return any 2xx status code within 30 seconds to acknowledge the delivery. sajn retries any other status code, a redirect, a timeout and a network error with backoff for about three days, 12 attempts in all. A 410 Gone stops the retries and pauses the webhook.