Documentation menu

Signing a PDF where it is

Some documents are a page rather than words. A lease with initials in the margin of page four; a county form with a box in the corner. Those get signed where they are.

Most templates here are text: the wording is the template, and the certificate's fingerprint is of exactly those bytes. A PDF is a different job, because the layout is the document — the whole reason a business has one is that somebody cared where things sit. Extracting the text would throw away the thing they are trying to keep.

So the file is kept whole, byte for byte. The signer sees the pages. The signature goes where the business put it. And the finished document is that same file with the answers drawn on it and the certificate after it.

Where the pages are drawn, and why it matters

In the browser of the business setting the template up. Not on our servers, and not anywhere else.

Turning a PDF into pictures needs a renderer, and where that renderer runs is a decision about who holds customers' documents. Running it here would mean a second process with every uploaded lease passing through it; running it somewhere else would mean a new subprocessor. So it runs on the machine of the person who chose the file, and what reaches us is the file and a picture of each page.

A PDF a browser cannot draw fails visibly, at setup, to the person who chose it — rather than silently at a counter, to somebody who has never seen it before. That is the trade, and it is the right way round.

What a signer gets

One image per page, with ordinary HTML inputs positioned over them. The signing page carries default-src 'none' and no script at all — that is checkable in the response headers, and it does not change for a PDF. An image needs nothing relaxed.

A box on a page is filled in on the page. A question with no box is asked underneath the document, the way every field is. Both hold the signature back until they are answered, if they are required.

Where a box sits

A placement is a page and a rectangle, as fractions of the page a reader sees, with the origin at the top left:

{
  "key": "tenant_sig",
  "label": "Sign here",
  "kind": "signature",
  "place": { "page": 2, "x": 0.12, "y": 0.71, "w": 0.3, "h": 0.05 }
}

Fractions rather than points, because the same box has to mean the same thing in three places that measure differently: a picture at whatever resolution the browser produced, a CSS box at whatever width the signer's phone is, and the PDF itself in points. A fraction survives all three; a pixel survives none of them.

Top-left rather than the PDF's own bottom-left origin, because two of those three are CSS and the third is one subtraction — which lives in the sealer, once, rather than in every screen.

Rotation is handled. A page carrying /Rotate 90 is shown turned, so a fraction is a fraction of the turned page, and the mark is placed and drawn to match.

What can be placed

  • Any field the signing adult supplies.
  • Not a per-child field: one box cannot hold an answer for four children.
  • Not a staff field: it is never put to a signer.

Both are refused when the template is saved, rather than accepted and found empty at a counter.

What the certificate says

A template's body is what the certificate fingerprints, and a PDF template has no text to fingerprint. So its body names the file's own SHA-256:

This agreement is the attached document: lease.pdf (4 pages).

The file is identified by its SHA-256 fingerprint 9f2c…8ab1. The signed
copy is that same file, with each answer drawn where it was placed on the
page, and the certificate of completion after it.

The signed fingerprint therefore commits to those exact bytes. Change one byte of the original and the certificate no longer describes it.

The text, and why you cannot edit it

A PDF template's text is the sentence naming the file, and it is fixed. That is not tidiness: it is the sentence's whole job. The certificate fingerprints the body, so naming the file's SHA-256 there is what makes the signature commit to those exact bytes. Take the fingerprint out and the pages are still signed, but nothing in the record says which file they were.

So the dashboard shows it read-only, offers no tidying of it, and the engine refuses a change to it — including through the API. The name, the questions and the boxes change freely; none of those is what the certificate commits to. To change what the text says, use a different file.

Setting one up

In the dashboard, under Templates → a PDF, signed where it is: choose the file, let the pages draw, then drag a box for each question — or type the page and four percentages, which is the same thing and works without JavaScript.

Publishing is refused until every page has a picture. A template with a missing page would send somebody a row of gaps.

Before it goes out

Two things on the send screen read the text of a document, and a PDF template has none — its text is the sentence naming the file. Both say so rather than pretending otherwise.

The pre-send checks skip the rules that read the document and keep the ones about the people it is going to and the blanks that were filled in. The screen says the pages were not read, as a note rather than a warning: it does not hold the send, because a warning on every PDF would be clicked through by the third one of the morning and would take the real warnings with it.

The AI review is refused outright for a PDF template. It would otherwise read the naming sentence and write its findings to the evidence trail, where they would stand as a reading of the agreement — and a review of the wrong document, kept as a record, is worse than no review.

The same holds on a public form at /f/…: the panel headed “What you are about to read” says what the document is and that its pages are on the next screen, rather than showing the fingerprint.

From the API

Everything after setup is ordinary. A PDF template is a template: prepare a document from it, send it, read the link, supply fields, sign, and download the sealed copy exactly as for any other. GET /v1/sign/{token} carries the pages, so an integrator building their own signing screen gets the same pictures the hosted page uses:

{
  "title": "Tenancy — Flat 2",
  "body": "This agreement is the attached document: lease.pdf …",
  "pages": [
    { "n": 1, "width": 1275, "height": 1650 },
    { "n": 2, "width": 1275, "height": 1650 }
  ],
  "fields": [
    { "key": "tenant_sig", "label": "Sign here", "kind": "signature",
      "required": true, "supplied": false,
      "place": { "page": 2, "x": 0.12, "y": 0.71, "w": 0.3, "h": 0.05 } }
  ]
}

Each page is an image at GET /s/{token}/page?n=1 — the token is the whole credential, so no API key goes near it and an <img> can load it directly.

GET /v1/templates/{id}/pdf says whether a template is a PDF one and whether it is ready to use:

{
  "has_pdf": true,
  "page_count": 4,
  "drawn": 4,
  "ready": true,
  "sha256": "9f2c…8ab1",
  "original_name": "lease.pdf"
}

Uploading the file itself is a dashboard step, not an API call. The pages have to be drawn by a browser, and an API caller does not have one — so a route that accepted the PDF would leave a template that could never be published. If you need this from a server, say so and we will design it with you rather than guess.

What is kept

  • The file, exactly as uploaded, on the template version. A new version copies it; a new upload replaces it and takes the old pictures and every box with it, because a box chosen against a page that no longer exists is a signature in the margin of the wrong page.
  • A picture of each page, which is what a signer sees.
  • The placements, frozen onto each document when it is prepared — so revising a template afterwards never moves a signature on a document somebody already signed.

Retention and redaction work as they do for any document: evidence and certificates explains the package, and the sealed copy is the same artefact with the customer's own pages at the front.

Ready to build? An API key takes a minute in the portal, and the free plan covers the first 25 agreements a month.

Get an API key