Skip to main content
Webhooks are delivered at least once, but only while your endpoint is reachable. If it was down, paused, or rejected deliveries by mistake, use the following tools to catch up:

Read past events

GET /api/v1/events returns the workspace’s events from the last 30 days, newest first:
The response is similar to the following:
data.object in this example is shortened. Each event is the same object as the body of a webhook delivery, so your webhook handler can process it unchanged. An event that a 2026-10 endpoint subscribed to when it happened carries the snapshot that the endpoint received. For any other event, sajn builds data.object from the resource’s current state when you read the list. If that resource no longer exists, the list leaves the event out, and GET /api/v1/events/{id} returns 404 NOT_FOUND. The endpoint takes the following query parameters: To get the next page, pass nextCursor as cursor and keep the other parameters unchanged. The last page has hasMore set to false and nextCursor set to null. The list uses keyset pagination, so events that arrive while you page don’t shift the pages. For more information, see Pagination. To read one event, pass its ID, the webhook-id of a delivery, to GET /api/v1/events/{id}. The events endpoints need an API key for the workspace, or an OAuth token with the webhooks:write scope.

Reconcile on a schedule

A reconcile job reads recent events and passes each one to the same handler as your webhook endpoint. Because the handler skips IDs that it has already processed, the job only fills gaps. Run it after an outage, or on a schedule, such as every hour, as a safety net.
1

Store a watermark

Store the time when the last successful run started. On the first run, use the time from which you need events, up to 30 days back.
2

Walk the events

Request events with createdAfter set to the watermark minus a few minutes, and follow nextCursor until it’s null. The overlap covers events that were being written while the last run read the list.
3

Process each event

Pass each event to your webhook handler, which deduplicates on id.
4

Move the watermark

After the walk completes, store the time when this run started as the new watermark. If the run fails partway, keep the old watermark, so the next run starts over.
The following samples implement the loop:
A large backlog can take many requests. If you get a 429 Too Many Requests status code, wait for the time in Retry-After and continue with the same cursor. For the limits, see Rate limits. If you need events older than 30 days, sync the resources themselves instead, for example with GET /api/v1/documents and its updatedAfter filter. For a full sync pattern, see Syncing documents.

Retry a delivery

To have sajn send a logged delivery to your endpoint again, call POST /api/v1/webhooks/{id}/deliveries/{deliveryId}/retry, where deliveryId is the delivery’s id from the delivery log. In the dashboard, open the delivery in Inställningar > Utvecklare > Loggar and click Sänd om (Resend).
The response is the new delivery, with status set to PENDING, no attempts yet, and replayOfId set to the delivery it retries. Follow it with GET /api/v1/webhooks/{id}/deliveries/{deliveryId}. A retried delivery behaves as follows:
  • It sends the stored body as is, in the API version it was first sent in, even if the endpoint has moved to another version since. It’s signed with the endpoint’s current secret.
  • It keeps the event id, so webhook-id is unchanged, and a receiver that deduplicates on it ignores the retry of an event that it already processed. To make your receiver process an event again, remove its id from your deduplication store first.
  • It works only for deliveries from the last 7 days, and only while the endpoint is enabled and not paused. Otherwise, sajn returns 409 INVALID_STATE.
To send every event that your endpoint missed, list the endpoint’s deliveries with GET /api/v1/webhooks/{id}/deliveries, and retry each one whose status is FAILED.
API version 2026-09 also has POST /api/v1/events/{id}/replay, which sends an event to every subscribed endpoint. 2026-10 removes it: to send an event again, retry its delivery to the endpoint that missed it, or process it from GET /api/v1/events.

Recover from an outage

1

Fix the endpoint

Make sure that your endpoint returns 2xx for a signed test request.
2

Reactivate it if it's paused

If sajn paused the endpoint, reactivate it. Events from the pause aren’t sent automatically.
3

Fill the gap

Run your reconcile job with createdAfter set to the start of the outage. To have sajn push the events instead, retry the endpoint’s FAILED deliveries from the last 7 days.