Skip to main content
In this recipe, you read a CSV file of employees and send each one a personal agreement created from the same template, with their own values filled in. The script is safe to run again after a failure: it skips rows that already have a document and uses idempotency keys so a retried request never creates a duplicate.

Before you begin

  • Python 3.9 or later, and the requests package: pip install requests.
  • An API key in the SAJN_API_KEY environment variable. To create one, go to workspace settings in the sajn app, then Utvecklare (Developer) > API-nycklar (API keys).
  • A template with a party named Employee and FORM fields with the keys employee-name and start-date. Store its ID in SAJN_TEMPLATE_ID. For more information, see Create documents from templates.
  • A CSV file named employees.csv with a header row:

Build the script

1

Look up the keys once

Every document from the template has the same keys. To check them, create one draft in the sajn app or through the API, and list its values:
Replace DOCUMENT_ID with the draft’s ID. The response lists the values in data. Use the key of each value with filledBy set to SENDER.
2

Write the script

Save the following file as bulk_send.py. For each row, it finds an existing document by externalId, or creates one, fills in the values, sets the party, and sends it:
The script works as follows:
  • externalId ties each document to a row, so a second run finds the document instead of creating another one. The externalId filter matches the whole value.
  • The create request and each item in the list return the document with its parties, so the script finds the employee’s party without another request.
  • The idempotency keys make a retried create or send replay the first response.
  • A value that isn’t written doesn’t fail the request. The script checks success on each item in results.
  • call waits for the number of seconds in Retry-After when the API returns 429.
3

Run it

Run the script:
The output is similar to the following:
Run it again, and every row reports already sent.

Handle errors

  • 403 LIMIT_EXCEEDED on create: the organization reached its hourly limit for created documents, or its monthly limit for sent documents. Wait, and run the script again; it continues where it stopped.
  • 429 RATE_LIMITED: the script waits and retries. For the limits per plan, see Rate limits and quotas.
  • values not written: each failed result has an error with a code. NOT_FOUND means the key doesn’t exist on the template, and VALIDATION_FAILED means the value doesn’t match the field’s type. Fix the CSV or the template.
For the error shape and every code, see Errors.