document.completed delivery, the next night’s run catches the document.
Before you begin
- Python 3.9 or later, and the
requestspackage:pip install requests. - An API key in the
SAJN_API_KEYenvironment variable. To create one, go to workspace settings in the sajn app, then Utvecklare (Developer) > API-nycklar (API keys). The job archives the documents of the key’s workspace. - A scheduler, such as cron, that can run the job once a night.
Build the job
1
Write the job
Save the following file as The job works as follows:
nightly_sync.py. It reads the last run’s timestamp from last-sync.txt, lists documents completed since then with a cursor, archives each one, and saves the new timestamp only after every document succeeded:completedAfterincludes its boundary, and the job stores the time the run started, so a document completed during the run is archived again the next night. Writing to a fixed folder per document makes that harmless.- The job passes each response’s
nextCursorascursoruntilhasMoreisfalse. The cursor keeps the pages stable while documents change. - Each file
urlexpires at the response’sexpiresAt, so the job downloads it right away. - If any document fails, the job stops before it saves the timestamp, so the next run retries the same window.
- Each document costs three API requests, plus its share of the list pages. For your plan’s limits, see Rate limits and quotas.
2
Run it once by hand
last-sync.txt, so it archives every completed document. The output is similar to the following:3
Schedule it
Add a cron entry that runs the job at 02:00 every night:Replace
API_KEY with your API key, or load it from your secret store instead.Handle errors
409 INVALID_STATEon a file: sajn hasn’t produced the file yet. sajn generates the journal shortly after it seals the document. The job stops, and the next run retries the document.401 UNAUTHORIZED: the key is invalid or was revoked.400 VALIDATION_FAILED: a malformedcompletedAfterinlast-sync.txt. The value must be an ISO 8601 date-time.

