Read past events
GET /api/v1/events returns the workspace’s events from the last 30 days, newest first:
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.
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, callPOST /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).
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, sowebhook-idis 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 itsidfrom 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.
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.
