Skip to main content
In this guide, you place boxes on the pages of an uploaded PDF: a signature that a party draws when signing, an input that a party fills in, and fixed text that you stamp. Then you move a box and read the layout back. A PDF field holds one uploaded PDF. The boxes on its pages are in fieldMeta.placedFields, an array where each entry is one box, drawn in array order.

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).
  • Have a DRAFT document with its parties, and each party’s id. For more information, see Create a document.
  • Upload the PDF file and keep the storage key. For more information, see Upload files.

Coordinates

Boxes use the PDF’s own coordinate model:
  • page: the 0-based page index.
  • rect: x, y, width, and height in PDF points (1/72 inch). The origin is the bottom-left corner of the page, and y grows upward.
  • pageWidth and pageHeight: optional. The page size that rect is measured on. A4 portrait is 595.28 by 841.89. If you send them, sajn scales rect to the real page. If you leave them out, sajn reads them from the PDF.
  • pageRotation: optional. 0, 90, 180, or 270. If you leave it out, sajn reads it from the PDF.
If your own model uses fractions measured from the top-left corner, convert them with x = xFraction * pageWidth and y = pageHeight - (yFraction + heightFraction) * pageHeight.

Box kinds

Each box has an id that’s unique in the field, and a kind:
  • INPUT with inputType SIGNATURE or INITIALS: a mark that the party in partyId draws when signing. sajn seals the mark into the PDF at this position. The party must have the SIGNER role.
  • INPUT with inputType TEXT, DATE, CHECKBOX, or SELECT: a value that the party in partyId fills in before signing. Add options for SELECT and "multiline": true for long text. If required is true, the party can’t sign until it’s filled in. Without a partyId, you fill the box in yourself.
  • STATIC: fixed text that you stamp on the page. content is HTML, and style takes fontSize (6 to 72), color (hex), bold, italic, and align (LEFT, CENTER, or RIGHT).
Every enum value in a box is uppercase; a lowercase value, such as input, fails with 400 VALIDATION_FAILED. To fill in an INPUT box through the API, give it a key. Keys can contain lowercase letters, digits, hyphens, and underscores.

Place the boxes

1

Create the PDF field with its boxes

Send a POST request to /api/v1/documents/DOCUMENT_ID/fields with the PDF field in a fields array. The following request places a signature on page 3, a start-date input on page 1, and a reference number in the top-right corner of page 1:
Replace the following:
  • DOCUMENT_ID: the ID of the draft document.
  • STORAGE_KEY: the key from the file upload.
  • PARTY_ID: the id of the signing party.
The response has the created PDF field in data. Store its id for the next step.sajn checks every box before it writes anything. The request fails with 400 VALIDATION_FAILED, and writes nothing, when a box’s page doesn’t exist, its rect doesn’t fit on the page, its partyId isn’t a party on the document, or it’s a signature or initials box for a party without the SIGNER role.
2

Move, add, or remove single boxes

To change boxes without sending the whole field again, send a PATCH request to /api/v1/documents/DOCUMENT_ID/fields/FIELD_ID/placed-fields:
Replace FIELD_ID with the PDF field’s id. The request works as follows:
  • A box in upsert with an existing id replaces that box and keeps its drawing order. A box with a new id is added on top.
  • remove lists the IDs of boxes to delete. Boxes you don’t mention stay as they are.
  • The change is atomic: if any box is invalid, nothing is written, and issues lists every problem.
The response is the PDF field with its full fieldMeta after the change.
3

Read the layout back

List the document’s fields:
The response lists every field in position order in data, and the PDF field has the placedFields you sent, with pageWidth, pageHeight, and pageRotation filled in. The following example leaves out most boxes:
GET /api/v1/documents/DOCUMENT_ID?expand=fields returns the same fields in the document’s fields array.

Fill in boxes and PDF form fields

To fill in an INPUT box that has no partyId, use Fill in values on a document with the box’s key. The same endpoint fills in the uploaded PDF’s own form fields (AcroForm fields), which sajn lists in fieldMeta.formFields with an uppercase type: TEXT, CHECKBOX, DROPDOWN, or RADIO. To see every fillable key, call List the fillable values on a document. The values are in data: values with kind set to PDF_PLACED are boxes, and values with kind set to PDF_ACROFORM are the PDF’s own form fields.

Use placements on templates

The same requests work on templates, through /api/v1/templates/TEMPLATE_ID/fields and /api/v1/templates/TEMPLATE_ID/fields/FIELD_ID/placed-fields. On a template, partyId refers to a template party. A document created from the template gets the boxes, mapped to the matching document parties.

Handle errors

A placement error lists every invalid box in issues, with its path:
  • 400 VALIDATION_FAILED: a box is invalid, uses a lowercase enum value such as signature, or uses a 2026-09 name such as signerId instead of partyId.
  • 409 INVALID_STATE: the document isn’t a DRAFT, or another edit changed the field while the request ran. In the second case, send the request again.
For the error shape and every code, see Errors.

Next steps

Send for signing

Send the document to its parties.

Fields that parties fill in

Add form inputs outside the PDF.

Add, update, or remove boxes

See the placed-fields endpoint in the API reference.

Fields

Learn how the field model works.