Skip to main content
In this guide, you keep a copy of your sajn documents in your own database. You fetch only what changed since the last run, walk the list with a cursor that stays stable while documents change, and retry writes without creating duplicates. We recommend combining a sync like this with webhooks: webhooks tell you about changes as they happen, and the sync catches anything a delivery missed.

Before you begin

  • Store your API key in the SAJN_API_KEY environment variable. To create a key, go to workspace settings in the sajn app, then Utvecklare (Developer) > API-nycklar (API keys). The key sees the documents of its workspace.
  • Have somewhere to store the newest updatedAt you’ve synced, such as a row in your database.

Run an incremental sync

1

Ask for what changed

Filter GET /api/v1/documents with updatedAfter set to the newest updatedAt you’ve stored, sorted by updatedAt in ascending order:
updatedAfter includes its boundary, so the last document of the previous run comes back again. Write each document as an upsert, and the overlap is harmless. On the first run, leave out updatedAfter.The response is similar to the following:
The example leaves out documentMeta content. Each list item includes its parties’ signing status and its tags, but not the parties’ full details or the custom fields; get those from Get a document by ID for the documents you need them for. To get the total count, add include=total.
2

Walk the pages with the cursor

Pass nextCursor back as cursor, with the same filters and sort, until hasMore is false. The following programs run the whole sync and print the timestamp to store for the next run:
Cursor pages stay stable while documents change between requests, which page numbers don’t. The cursor follows these rules:
  • It works with every orderBy value. Documents without a completedAt or expiresAt value come last when you sort by that field.
  • Keep the same orderBy, orderDirection, and filters for every request in one walk. A cursor from another sort returns 400 VALIDATION_FAILED.
  • Cursors are opaque. Don’t build or edit them.
For more information, see Pagination.
3

Store the timestamp

After the last page, store the newest updatedAt you saw. The next run passes it as updatedAfter.

Narrow the sync

The list takes the following filters. Send each value as a plain string, not JSON-encoded:
  • completedAfter and completedBefore: the completion time, for syncing signed documents only.
  • status: one or more statuses, such as status=PENDING,COMPLETED, or a repeated parameter.
  • externalId: the document with exactly this externalId, case-sensitive. For a partial match, use query.
  • templateId: documents created from one or more templates.
  • tagId, folderId, and responsibleUserId: documents with a tag, in a folder, or with a responsible user. For top-level documents, use folderId=root.
  • archived: true for archived documents only. The default, false, leaves archived documents out.
Dates take an ISO 8601 date or date-time, and a value without an offset is UTC. An unknown query parameter returns 400 VALIDATION_FAILED with the issue code UNRECOGNIZED_KEY, so a misspelled filter fails instead of returning every document. For more information, see Query parameters.

Retry writes safely

A POST /api/v1/documents request that times out might have created the document. Send an Idempotency-Key header on every write, and a retry with the same key and body replays the first response instead of running again:
Use one key per logical operation, such as a UUID, and keep it across retries. sajn stores the response for 24 hours. For the full rules, see Idempotency.

Handle errors

  • 400 VALIDATION_FAILED: an unknown filter, a malformed date, or a cursor from another sort. Read issues.
  • 429 RATE_LIMITED: wait the number of seconds in the Retry-After header, and then continue from the same cursor.
  • 400 IDEMPOTENCY_KEY_REUSED: you sent a key again with a different request. Use a new key.
  • 409 IDEMPOTENCY_KEY_IN_USE: the first request with the key is still running. Wait and retry.
For the error shape and every code, see Errors.

Next steps

Sync completed documents nightly

Archive every signed PDF on a schedule.

Replay and reconcile

Recover webhook events you missed.

Pagination

Learn how every list paginates.