Placement modes

Where signature fields land on the PDF — anchors, auto-append, explicit. Visualised, with when-to-use guidance. Manual placement is retired.

Pick a mode with the placement form field on POST /v1/signing-requests. The default is anchors with a fall-through to auto_append when no markers are found. Three live modes; every one of them places the fields at API call time, so the request that answers 201 is the request that went out.

manual is retired. A fourth mode — placement="manual": POST the PDF and the signers with no field information, get back a placementUrl, and let a person drop the fields in a hosted editor before anything was sent — was retired on 2026-07-31. It never dispatched a request in production, and the guest placement editor it opened went with the classic-editor retirement. The value is still parsed so that an old request body fails loudly instead of with a generic validation error: POST /v1/signing-requests answers 400 placement_retired before any document is minted (placement_assignee_email is accepted and ignored), and its companion POST /v1/documents — ingest a PDF by URL, get the same placement link — answers 410 placement_retired.

Use one of the three live modes instead: anchors when your generator can drop [[ls:signature:role]] markers into the PDF, explicit when it already knows the coordinates, auto_append when a signature page on the end is enough. Ingest-by-URL lives on as file_url on POST /v1/signing-requests. To keep a person in the loop before the send, stage a template instance with review: true and confirm or discard it — the fields come from the template, so there is nothing left to place.

At a glance

In every mode a field belongs to a role, and each signer needs its own role: two signers with the same role are refused with 400 duplicate_role (meta.role, meta.emails), since each would get every field of the other.

ModeWhen to pick itCaller passes coordinates?Field placement happens at
anchorsYou generated the PDF programmatically (HTML→PDF, LaTeX, Word) with markers.NoAPI call time
auto_appendAd-hoc letters, no structure, just need a signature page on the end.NoAPI call time
explicitYou generated the PDF programmatically AND tracked field positions yourself.YesAPI call time

anchors (default)

Drop a marker like [[ls:signature:tenant]] in your PDF (HTML→PDF, LaTeX, Word, anywhere with a real text layer). We find it, mask the marker with a white rectangle, and place the signature field on top.

1 — UPLOAD
PDF with markers in text layer
Tenant signature:
[[ls:signature:tenant]]
─────────────────
2 — SCAN
pdfjs reads positions; we white-rect each marker
Markers are masked so they don't bleed through under the field.
3 — PLACE
Signature field rendered on top of the masked region
Sign here

Best ergonomics for programmatically generated contracts — HTML→PDF templates, document-assembly tools (Portant, DocAssemble), LaTeX, Pandoc. See Anchor placeholders for the full marker syntax.

Caveats:

  • The PDF's text layer must contain the marker. Scanned-image PDFs don't qualify (run them through OCR first).
  • Markers wrapped across two lines are skipped silently — keep them on one line in the source template.
  • A marker can appear once per page per role for signature / initial / date / name. Duplicates → 400 duplicate_anchor.
  • Anchored signature and initials boxes get the caption check of explicit placement as notices only, never refused: caption_outside_page or field_over_caption in warnings[], with field = the marker as your PDF spells it ([[ls:signature:tenant]]).

auto_append

We add a fresh signature page after your PDF — one block per signer, role-labelled with a signature line and a date line. No coordinates needed from you.

1 — UPLOAD
Original PDF (N pages)
2 — APPEND
We add page N+1 with role-labelled blocks
3 — SIGN
Signers sign on the appended page
TENANT
LANDLORD

Good for ad-hoc letters and quick-and-clean send-and-forget flows where there's no existing signature area. Also the fall-through when anchors mode finds zero markers in the PDF: whether you passed placement="anchors" or left the default, we switch to auto_append so the document still goes out, and the response says so — "placement": "auto_append", anchors.found: 0. Check those two fields if a PDF without markers must not be sent.

Caveats:

  • Adds at least one extra page — six signer blocks fit on a page, so a seventh signer starts a second one.
  • The appended page is A4 portrait, unrotated and uncropped, regardless of your source PDF's page size, rotation or crop.

explicit

You pass a fields[] array with one tuple per field, in normalized [0..1] coordinates with a top-left origin:

{
  "placement": "explicit",
  "fields": [
    { "page": 0, "x": 0.10, "y": 0.78, "w": 0.30, "h": 0.06, "kind": "signature", "role": "tenant" },
    { "page": 0, "x": 0.55, "y": 0.78, "w": 0.30, "h": 0.06, "kind": "signature", "role": "landlord" },
    { "page": 0, "x": 0.10, "y": 0.74, "w": 0.15, "h": 0.03, "kind": "date",      "role": "tenant" }
  ]
}
1 — UPLOAD
PDF + JSON coords from your generator
{ "page": 0,
"x": 0.10,
"y": 0.78,
...
2 — VALIDATE
Each role must match a signer; every field must lie wholly on its page
3 — PLACE
Field rendered exactly where you said

Use when you generated the PDF programmatically AND tracked field positions at generation time — most often a templating system with inline metadata about where each field belongs.

Coordinate system:

  • Origin top-left (matches our editor; PDF native is bottom-left but you don't need to think about that). Pass "origin": "center" on a field to give its centre instead.
  • x, y, w and h are in [0, 1] — fractions of the visible page: the CropBox (the MediaBox when the page has none) after /Rotate is applied, measured from its visible top-left corner. That is the page as a PDF viewer shows it, as the signer sees it, and as the signature is drawn into the signed PDF. A value outside [0, 1] is a 400 invalid_request, not clamped. page is 0-based.
  • Portrait, landscape, /Rotate 90 / 180 / 270, a MediaBox that does not start at 0/0 and a CropBox inside the MediaBox are all supported. We never rotate or crop your PDF to make a field fit.
  • Strict, never approximate. A field must lie wholly on an existing page: a page the document does not have, x + w > 1, y + h > 1, a w or h of 0, or an origin: "center" field reaching past an edge is a 422 field_out_of_bounds. A page carrying a field that we cannot place on exactly — a CropBox not wholly inside the MediaBox, a box written reversed, under 1 pt or unreadable, a /Rotate that is not a number or not a multiple of 90 — is a 422 page_geometry_unsupported. Both list every offending page and field in meta.problems, and nothing is created.
  • Leave room for the caption. Every signature and initials box gets a caption printed below it (name and email, signing time, platform, masked IP and method — see What prints under each signature): 42 pt under the box, 8.5 pt more for each extra line a stated job_title or company takes. Keep y + h ≤ 1 − D / H, H being the visible page height in points (0.950 on A4 portrait for D = 42). A box whose caption would cross the bottom edge is still created and named in warnings[] (caption_outside_page, field fields[i]); from 2027-01-31 (00:00 UTC) it is a 422 field_out_of_bounds with meta.reason caption_outside_page (caption_depth_pt, space_below_pt in meta.problems). A field inside those D pt under a signature or initials box, at least across the box's width, prints over the caption and is named (field_over_caption), never refused. A caption whose widest line would run past the right edge moves left; it is never cut there.
  • kind is signature | initial | date | text (default signature).
  • role MUST match a signers[].role value (400 unknown_role otherwise), and every signer needs at least one signature or initial field (422 signer_without_signature otherwise).
  • A field accepts exactly page, x, y, w, h, kind, role and origin; any other key is ignored and named in warnings[] (fields[i].<key>), and from 2027-01-31 (00:00 UTC) refused with 400 unknown_field.

Date fields. A date field is filled by wesign when that signer's signature is sealed; the signer never types it. It gets the signer's signing day in the issuer's time zone (the workspace owner's profile time zone, else their country's, else UTC), written DD.MM.YYYY — MM/DD/YYYY for a workspace in the US — and centred in the box at half the box's height, between 8 and 14 pt, shrunk to fit the box's width down to 6 pt. There is no format option on explicit fields. The signing page shows the same text, computed when the page is opened.

Caveats:

  • Coords land exactly where you say — or the call is refused. A bug in your generator that keeps the box on the page still puts it on top of the legalese.
  • Page sizes vary; if your generator outputs Letter and the field table assumes A4, fields land where they shouldn't.