> ## Documentation Index
> Fetch the complete documentation index at: https://docs.sajn.se/llms.txt
> Use this file to discover all available pages before exploring further.

# Create a document

> Create a draft document with parties, settings, and custom field values, from scratch or from a template

In this guide, you create a draft document through the API. You add the parties who sign it, set the invitation and signing settings, and fill in custom field values. The document stays a `DRAFT` until you [send it for signing](/guides/documents/send-for-signing).

## Before you begin

* Create an API key. In the sajn app, go to workspace settings, then **Utvecklare** (Developer) > **API-nycklar** (API keys).
* Store the key in the `SAJN_API_KEY` environment variable. Every example on this page reads it from there:

  ```bash theme={null}
  export SAJN_API_KEY="API_KEY"
  ```

  Replace `API_KEY` with your API key.

Every request sends the `Sajn-Version: 2026-10` header, so the examples behave the same no matter what your organization's default version is. For more information, see [API versioning](/api-fundamentals/versioning).

## Create the document

<Steps>
  <Step title="Create a draft with its parties">
    Send a `POST` request to `/api/v1/documents` with a `name` and the `parties` who take part. Each party is either an existing contact, referenced by `contactId`, or a person given by `name` and `email`:

    <CodeGroup>
      ```bash curl theme={null}
      curl -X POST https://app.sajn.se/api/v1/documents \
        -H "Authorization: Bearer $SAJN_API_KEY" \
        -H "Sajn-Version: 2026-10" \
        -H "Content-Type: application/json" \
        -d '{
          "name": "Employment contract - Alex Andersson",
          "externalId": "hr-2026-0142",
          "parties": [
            {
              "name": "Alex Andersson",
              "email": "alex@example.com",
              "role": "SIGNER",
              "deliveryMethod": "EMAIL",
              "requiredSignature": "SE_BANKID"
            }
          ]
        }'
      ```

      ```javascript Node.js theme={null}
      const response = await fetch("https://app.sajn.se/api/v1/documents", {
        method: "POST",
        headers: {
          Authorization: `Bearer ${process.env.SAJN_API_KEY}`,
          "Sajn-Version": "2026-10",
          "Content-Type": "application/json",
        },
        body: JSON.stringify({
          name: "Employment contract - Alex Andersson",
          externalId: "hr-2026-0142",
          parties: [
            {
              name: "Alex Andersson",
              email: "alex@example.com",
              role: "SIGNER",
              deliveryMethod: "EMAIL",
              requiredSignature: "SE_BANKID",
            },
          ],
        }),
      });
      const document = await response.json();
      console.log(document.id, document.parties[0].id);
      ```

      ```python Python theme={null}
      import os

      import requests

      response = requests.post(
          "https://app.sajn.se/api/v1/documents",
          headers={
              "Authorization": f"Bearer {os.environ['SAJN_API_KEY']}",
              "Sajn-Version": "2026-10",
          },
          json={
              "name": "Employment contract - Alex Andersson",
              "externalId": "hr-2026-0142",
              "parties": [
                  {
                      "name": "Alex Andersson",
                      "email": "alex@example.com",
                      "role": "SIGNER",
                      "deliveryMethod": "EMAIL",
                      "requiredSignature": "SE_BANKID",
                  }
              ],
          },
      )
      response.raise_for_status()
      document = response.json()
      print(document["id"], document["parties"][0]["id"])
      ```
    </CodeGroup>

    The response is the full document, in the same shape as [Get a document by ID](/api-reference/get-a-document-by-id). `fields` is `null` unless you pass `expand=fields`. The following example leaves out `documentMeta` and some party fields:

    ```json theme={null}
    {
      "id": "cm4k2x9p10001abcd1234efgh",
      "externalId": "hr-2026-0142",
      "name": "Employment contract - Alex Andersson",
      "status": "DRAFT",
      "expiresAt": "2026-10-31T09:00:00.000Z",
      "createdAt": "2026-10-01T09:00:00.000Z",
      "updatedAt": "2026-10-01T09:00:00.000Z",
      "completedAt": null,
      "deletedAt": null,
      "templateId": null,
      "folderId": null,
      "responsibleUserId": "cm4k2x7c00000abcd0000wxyz",
      "parties": [
        {
          "id": "cm4k2xa3f0002abcd5678ijkl",
          "documentId": "cm4k2x9p10001abcd1234efgh",
          "type": "INDIVIDUAL",
          "name": "Alex Andersson",
          "email": "alex@example.com",
          "company": null,
          "role": "SIGNER",
          "signingOrder": null,
          "deliveryMethod": "EMAIL",
          "requiredSignature": "SE_BANKID",
          "twoStepVerification": "NONE",
          "signingStatus": "NOT_SIGNED",
          "readStatus": "NOT_OPENED"
        }
      ],
      "tags": [],
      "customFields": [],
      "fields": null,
      "productTables": [],
      "approvalRequestId": null
    }
    ```

    Store the document `id` and each party `id`. The other document and party endpoints take them as path parameters.

    If you leave out `expiresAt`, the document gets the workspace's default expiration, if the workspace has one. If you leave out `requiredSignature`, the party gets the workspace's default signing method.
  </Step>

  <Step title="Configure the invitation and signing settings">
    Set the email subject, the invitation message, the signing order, and the automatic reminders in `documentMeta`. Set the deadline in `expiresAt`. You can send these fields when you create the document, or later with a `PATCH` request:

    ```bash theme={null}
    curl -X PATCH https://app.sajn.se/api/v1/documents/DOCUMENT_ID \
      -H "Authorization: Bearer $SAJN_API_KEY" \
      -H "Sajn-Version: 2026-10" \
      -H "Content-Type: application/json" \
      -d '{
        "expiresAt": "2026-10-31T16:00:00Z",
        "documentMeta": {
          "subject": "Your employment contract",
          "message": "Hi Alex, here is your contract. Sign it before October 31.",
          "signingMode": "SEQUENTIAL",
          "language": "en",
          "reminderIntervalDays": 3,
          "forceReadFullDocument": true
        }
      }'
    ```

    Replace `DOCUMENT_ID` with the document `id` from the previous step.

    The most-used `documentMeta` fields are the following:

    * `signingMode`: `PARALLEL` invites every party at once. `SEQUENTIAL` invites them one at a time, in the order of each party's `signingOrder`. For more information, see [Multi-party signing](/guides/documents/multi-party-signing).
    * `reminderIntervalDays`: the number of days between automatic reminders, as an integer. `0` turns them off, and `null` uses the default of 3 days. For more information, see [Reminders and expiration](/guides/documents/reminders-expiration).
    * `language`: the language of the emails and the signing page, such as `sv` or `en`.
    * `redirectUrl` and `redirectEnabled`: where to send a party after signing. For more information, see [Redirect after signing](/guides/documents/redirect-url).
    * `internalRecipients`: up to five email addresses that get a copy of the sealed PDF when the document is completed.

    For every field, see [Create a new document](/api-reference/create-a-new-document).
  </Step>

  <Step title="Fill in custom field values">
    To set the workspace's custom fields on the document, send `customFields` with each field's `customFieldId` and `value`. To find the IDs, call [List all custom fields](/api-reference/list-all-custom-fields):

    ```bash theme={null}
    curl -X PATCH https://app.sajn.se/api/v1/documents/DOCUMENT_ID \
      -H "Authorization: Bearer $SAJN_API_KEY" \
      -H "Sajn-Version: 2026-10" \
      -H "Content-Type: application/json" \
      -d '{
        "customFields": [
          { "customFieldId": "cm4k2xe9t0006abcd1357yzab", "value": "Engineering" }
        ]
      }'
    ```

    Replace `DOCUMENT_ID` with the document ID. The response's `customFields` array lists every value on the document. For more information, see [Custom fields](/guides/fields/custom-fields).
  </Step>

  <Step title="Add the content">
    A document created without a template has no content. Add it in one of the following ways:

    * Upload a PDF file and attach it as a `PDF` field. For more information, see [Upload files](/guides/documents/file-uploads).
    * Add text and HTML fields. For more information, see [HTML fields](/guides/fields/html-fields).
    * Create the document from a template that already has content, as described in the following section.

    The document is ready to send. Continue with [Send a document for signing](/guides/documents/send-for-signing).
  </Step>
</Steps>

## Create a document from a template

To reuse content and parties, pass a `templateId`. The new document copies the template's fields, parties, and settings. If you also send `parties`, they replace the template's parties, and signature and initials boxes placed on a PDF for the template's parties are removed. For a template with placed boxes, leave out `parties` and update the copied parties instead, as described in [Create documents from templates](/guides/templates/templates-and-forms):

```bash theme={null}
curl -X POST https://app.sajn.se/api/v1/documents \
  -H "Authorization: Bearer $SAJN_API_KEY" \
  -H "Sajn-Version: 2026-10" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Employment contract - Alex Andersson",
    "templateId": "TEMPLATE_ID",
    "parties": [
      {
        "name": "Alex Andersson",
        "email": "alex@example.com",
        "role": "SIGNER"
      }
    ]
  }'
```

Replace `TEMPLATE_ID` with the ID of a template from [List all templates](/api-reference/list-all-templates).

To fill in the template's form fields before you send the document, use [Fill in values on a document](/api-reference/fill-in-values-on-a-document).

## Add a company party

A party with a `company` is a `COMPANY` party, which signs on behalf of the company. Set the company's `name` and `orgNumber` together, and optionally the party's `role` at the company. Leave out `company` for a private individual:

```json theme={null}
{
  "name": "Kai Berg",
  "email": "kai@example.com",
  "company": {
    "name": "Example AB",
    "orgNumber": "5560000000",
    "role": "CEO"
  },
  "country": "SE",
  "role": "SIGNER",
  "requiredSignature": "SE_BANKID"
}
```

`country` is an ISO 3166-1 alpha-2 code, such as `SE`. The response returns the company as `company`, with `id`, `name`, `orgNumber`, and `role`, and `company` is `null` for a private individual.

A party added by `name` and `email` has no phone number. To deliver the invitation by SMS, add the party from a contact that has a phone number, with `contactId` and `"deliveryMethod": "SMS"`. You can also set `phone` later with [Update a party](/api-reference/update-a-party).

## Handle errors

Errors have the same shape on every endpoint. Branch on `code`:

* `400 VALIDATION_FAILED`: the body is invalid, for example a party without `email`, a `company` with `name` but no `orgNumber`, or a flat key such as `companyName`. The `issues` array lists each problem with its `path`, such as `parties.0.email`.
* `404 NOT_FOUND`: a `contactId` or the `templateId` doesn't exist in the workspace.
* `429 RATE_LIMITED`: wait the number of seconds in the `Retry-After` header, and then retry.

To retry a `POST` request safely, send the same `Idempotency-Key` header on every attempt. For more information, see [Errors](/api-fundamentals/errors) and [Idempotency](/api-fundamentals/idempotency).

## Next steps

<CardGroup cols={2}>
  <Card title="Send for signing" icon="paper-plane" href="/guides/documents/send-for-signing">
    Send the draft and track each party's progress.
  </Card>

  <Card title="Upload files" icon="file-arrow-up" href="/guides/documents/file-uploads">
    Attach a PDF file as the document's content.
  </Card>

  <Card title="Set the signing method" icon="fingerprint" href="/guides/identity/signing-methods">
    Choose BankID, eID, drawn, or click-to-sign for each party.
  </Card>

  <Card title="Create a new document" icon="code" href="/api-reference/create-a-new-document">
    See every request field in the API reference.
  </Card>
</CardGroup>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.