Anchor placeholders
The [[ls:KIND:ROLE]] marker syntax used by placement="anchors".
placement="anchors" (the default) finds markers in your PDF's
text layer and places fields on top. This page covers the marker
syntax, what we do with the marker once we find it, and the rules
that produce 400 errors.
Syntax
[[ ls : KIND : ROLE (: FIELD_KEY)? ]]
KIND — signature | initial | date | name | text
ROLE — must match a signers[].role
FIELD_KEY — only for KIND=text; ties to a future field_values keyWhitespace inside the brackets is tolerated ([[ls:signature:tenant]]
and [[ ls : signature : tenant ]] parse the same). The marker must
live on a single line in the PDF's text layer — line-wrapped
markers are skipped silently.
Example PDF excerpt
CLIENT — Acme GmbH
[[ls:signature:client_principal]] [[ls:date:client_principal]]
───────────────────────────────── ──────────────
[[ls:name:client_principal]] Date
VENDOR — letssign.now Partners AG
[[ls:signature:vendor_director]] [[ls:date:vendor_director]]
───────────────────────────────── ──────────────
[[ls:name:vendor_director]] DateWhen this contract is POSTed with two signers (client_principal and
vendor_director), the response contains anchors.found: 6 —
two signatures, two dates, two names — and the matching fields
array maps each one to its role.
Rules
A marker can appear once per page per role for signature,
initial, date, and name kinds. Multiple text markers per
page per role are allowed (e.g. multiple inline fill-in-the-blanks).
| Violation | Error | Status |
|---|---|---|
Marker references a role not in signers[] | unknown_role | 400 |
Same signature:role appears twice on the same page | duplicate_anchor | 400 |
placement="anchors" explicitly + zero markers found in PDF | no_anchors_found | 400 |
Signer in signers[] has no marker for their role | signer_has_no_anchor | 400 |
The default placement="anchors" (without explicit opt-in) does
not raise no_anchors_found — instead it silently falls through
to auto_append. To force the strict-anchors behaviour, post with
placement="anchors" explicitly and verify
anchors.found > 0 in the response.
What happens to the marker
Pre-signing modification is logged. Before presenting the PDF to
signers we draw a white rectangle over each marker — so the signer
sees their signature field on a clean page, not the [[ls:…]] text
underneath. The audit trail stores both the original SHA-256 and the
presented SHA-256 so a reviewer can see the masking step happened.
The white-rect mask is the only modification we make. Field rendering
on the signing page sits on top — the marker text is hidden, but the
underlying PDF byte stream still contains it. If you re-extract text
from the signed PDF (e.g. pdftotext), the marker is gone (PAdES
incremental updates supersede the masked region in viewers).
