# Templates and versions

The text people sign, and why it is never changed under them.

Watch it done: [Have a waiver drafted, then have it read](https://signsealer.com/guides/have-a-waiver-drafted-then-read) (2:49)

A template has a **code** (`rental-agreement`) and numbered **versions**. A version is a draft until it is published, and a published version is frozen: the database refuses to change or delete it, because somebody may have signed it. Changing the words means a new version. Each document records the exact version it was made from, and the certificate says which, so "what did they sign?" always has one answer.

## The lifecycle

| Step | Call | What happens |
| --- | --- | --- |
| Create | POST /v1/templates | Version 1, as a draft, with its text, placeholders, consent wording and questions. |
| Change the draft | PATCH /v1/templates/{id} | `name`, `body`, `body_format`, `variables`, `fields` (the whole list). Only while it is a draft. |
| Publish | POST /v1/templates/{id}/publish | New documents from this code use this version, and its text is frozen. Refused, by name, for a placeholder the template does not declare. |
| Revise | POST /v1/templates/{id}/revise | A new draft, one version higher, copied from the newest with whatever you change. Publish it to put it into use. |
| Go back | POST /v1/templates/{id}/restore | An older published version's text, questions, consent wording and file, as a new draft above the newest. Its `change_note` says where it came from. Not while a draft is open. |
| Throw a draft away | DELETE /v1/templates/{id} | Only a draft nothing was made from. The only version of a code going frees the code. |
| Read one | GET /v1/templates/{id} | The version whole, with `versions`: every version of its code, newest first. |
| List | GET /v1/templates?code= | Every version of every template, or one code's; no text. |

```
// A new clause for next season, without touching what people signed this one.
const current = await signsealer.template(templateId);
const next = await signsealer.reviseTemplate(current.template_id, {
  body: current.body + "\n\nHelmets are required on every trail.",
});
await signsealer.publishTemplate(next.template_id);
```

Revise only from the newest version. Revising an older one would quietly throw away every change made since, so it answers `409 conflict`, and the hint names the newest version's id. A draft is not revised; it is changed with `PATCH`.

**What changed, and going back.** Each version carries a `change_note` of up to 500 characters: set it on `revise` or with `PATCH` while it is a draft, and it is frozen with the version when it is published. `GET /v1/templates/{id}` lists every version with its note, name, whether it has a PDF and how many documents were made from it -- the same list as the dashboard's history page, which also compares any two versions line by line. To go back to an older wording, `POST /v1/templates/{id}/restore` on that version makes a new draft above the newest; the versions in between keep their numbers and their signatures.

## Questions and fields

A template's `fields` are what it asks besides the signature: a date of birth, a tick against each safety statement, a photo of the boat before it leaves. Send them as a list on `POST /v1/templates`, or as the whole list on `PATCH /v1/templates/{id}` and `POST /v1/templates/{id}/revise`, where the list you send replaces the one it had. `GET /v1/templates/{id}` answers with them in the same shape. A template asks at most fifty.

The list is checked twice. The API checks each question's shape and answers `422 invalid` naming the property. The engine then reads the list as a whole and refuses it with `422` and a sentence naming the question: a condition on a question below it, a block with two headings, a choice with one option. A refused list on a create leaves no template behind.

> **A property that is not in the table below is dropped without a word.** A misspelt `show_if` saves, answers `201`, and leaves a question that is always asked. Read the template back with `GET /v1/templates/{id}` when you are building the list.

### Kinds

Every answer is checked by the engine when it is given, whatever the page or your client did first. An empty answer to a required question is refused as required; an optional one may be left empty.

| Kind | What it accepts | How the signing page asks it |
| --- | --- | --- |
| `signature` | Anything that is not empty. Cannot be optional. | Placed on an uploaded PDF, it is the box the signature itself fills, and is never asked. Asked under the document, it is a typed line: a second signature, typed. |
| `initials` | Anything that is not empty. Cannot be optional. | A one-line box. On a page, up to six characters. |
| `checkbox` | Ticked is `true`, `yes`, `on` or `1`, in any case. A required one has to be ticked. | On its own, a button: *I confirm:* and the label, and *Leave it unticked* beside it when it is optional. In a block, a tickbox. |
| `text` | Anything that is not empty. | A one-line box. |
| `paragraph` | Anything that is not empty. No minimum length: "No damage" is an answer. | A box several lines tall. |
| `date` | `YYYY-MM-DD`, and a day the calendar has: `2026-02-31` is refused. | A date picker. Placed on a page with a signing-date key or label, it is filled by signing instead ([Signing a PDF](https://signsealer.com/docs/pdf)). |
| `birthdate` | As a date, and no later than tomorrow (a day of slack for time zones), with the year 1900 or later, so `0084-05-02` is refused. | Month and day picked, the year typed. On a page, a date picker. |
| `time` | `HH:MM` on a 24-hour clock: `14:30`, `9:05`. | A time picker. |
| `datetime` | `YYYY-MM-DDTHH:MM`, or a space for the `T`, on a day the calendar has. | A date-and-time picker. |
| `photo` | A JPEG or PNG, sent to the photo route. Text is refused. The answer becomes `sha256:<hex>`. | A camera button. An optional one offers *Carry on without a photo*. |
| `email` | Something, an `@`, then a domain with a dot in it, and no spaces. | An email box, with the email keyboard. |
| `phone` | At least seven digits; anything else in it is ignored for the count. | A country code to pick and the number to type. On a page, one box. |
| `address` | At least five characters. | A box several lines tall, rather than street, city and zip: those are not the shape of an address everywhere. |
| `number` | Digits, with a minus in front and a decimal point if needed: `12`, `-3`, `4.5`. No commas, no units. | A number box, with the number keyboard. |
| `money` | An amount as people type one: `1250`, `1,250.00`, `$1,250`, `USD 40`. Two decimal places at most. Written into the document as typed. | A box with the number keyboard, which takes a currency sign and commas. |
| `vin` | Seventeen letters and digits, never I, O or Q; spaces and dashes are ignored. Written in capitals. | A box that types in capitals. |
| `ssn_last4` | Exactly four digits. A whole Social Security number is refused, not trimmed. | A four-digit box with the number keyboard, never offered back by the browser. |
| `postal_code` | Three to ten letters and digits, with a space or a dash between, and at least one digit: `90210`, `90210-1234`, `SW1A 1AA`. | A box the browser can fill with the postal code it knows. |
| `percent` | A number, with or without its `%`. Written into the document with it. | A box with the number keyboard. |
| `choice` | Exactly one of its `options`, as written. | Six options or fewer are buttons to tap; more are a list. |

### Properties

| Property | Takes | What it does |
| --- | --- | --- |
| `key` | Required. A lower-case letter, then up to 58 lower-case letters, digits and underscores. Once per list. | Names the answer everywhere: in `answers`, on `POST /v1/sign/{token}/fields`, and in `values` for a box the sender fills. |
| `kind` | Required. One of the kinds above. | What the answer must be, and the box it is asked in. |
| `label` | 1 to 200 characters. | What the signer reads. Without one, the key is shown. |
| `required` | `true` or `false`. `true` when absent. | The signature is refused until a required question is answered. An optional one can be passed, and the signature does not wait for it. A `signature` or `initials` cannot be `false`. |
| `hint` | Up to 200 characters. | A line under the question, read with it by a screen reader. |
| `options` | A `choice` only: 2 to 30 of them, each 1 to 80 characters, none blank. | What can be picked. Any other kind carrying `options`, even an empty list, is refused. |
| `blank` | `true` or `false`. `false` when absent. Written templates only. | The answer fills the blank of the same name in the text: `{{plate}}` for a question keyed `plate`. See [A blank the signer fills in](#signer-blanks). |
| `sensitive` | `true` or `false`. `false` when absent. | The answer is masked wherever the business's staff read it back and in the API. It is not masked on the sealed PDF, because the PDF is the document that was signed. On the page the box turns off the browser's autofill and suggestions, and a box on a PDF page does not show the answer back. |
| `supplied_by` | `adult` (when absent), `per_child`, `everyone`, `staff` or `business`. | Who answers it: below. |
| `show_if` | An object: `field`, the key of a question earlier in the list, and one rule. Or several such rules, joined by all or any. | Asked only when those earlier answers match: below. |
| `flag_when` | An object with one rule, about this question's own answer. | Marks the answer for a person to read: below. |
| `block` | A name shaped like a key. | Questions with the same `block` are asked together, as one thing. |
| `block_label` | Up to 200 characters. | The block's heading. Given once, on any question in the block. Every block needs one; two different ones are refused, and so is one on a question with no `block`. |
| `block_intro` | Up to 2,000 characters. | A sentence or two under the heading, given once on the same terms. |
| `block_step` | `true` or `false`. | `true` on any question of a block gives the whole block a page of its own. Refused on a question with no `block`. |
| `place` | `{page, x, y, w, h}`: a page counted from one and no higher than the file has, and four fractions of the page from its top left, for a box with a width and a height that fits on it. | Where on an uploaded PDF's page the question is answered ([Signing a PDF](https://signsealer.com/docs/pdf)). |

`show_if`, `flag_when`, `block`, `block_label`, `block_intro`, `block_step` and `place` may also be `null`, which is the same as leaving them out.

### Conditions and flags

`show_if` and `flag_when` both take these four rules, exactly one of them per object:

| Rule | Matches |
| --- | --- |
| `{"ticked": true}` | A ticked box. A `checkbox` only. |
| `{"unticked": true}` | A box not ticked, including one never answered. A `checkbox` only. |
| `{"answered": true}` | Any answer that is not empty. |
| `{"equals": ["Yes", "Not sure"]}` | One of these answers, ignoring case and the spaces around it. Not for a `photo`. |

For `show_if` the rule is about the question it names, so `ticked` needs that question to be a checkbox: `{"field": "injured", "ticked": true}`. The named question has to be above this one, because a form is read top to bottom; one below it, or the question itself, is refused. A hidden question is not required, and the signature does not wait for it. Change the earlier answer so that a question is hidden again and its answer is cleared, along with any that depended on it, so nothing is kept in answer to a question the signed document never asked.

A `show_if` rule can also say more than the four:

| Rule | Matches |
| --- | --- |
| `{"not_equals": ["No"]}` | An answer, and none of these. An empty answer does not match, so the question waits for the one it depends on. Not for a `checkbox`, `photo`, `signature` or `initials`. |
| `{"contains": "allergy"}` | An answer with these words in it, ignoring case. A `text`, `paragraph`, `email`, `phone` or `address`. |
| `{"not_contains": "nuts"}` | An answer without these words in it, ignoring case. Like `not_equals`, an empty answer does not match. The same kinds as `contains`. |
| `{"gt": 10000}`, `{"lt": 500}` | A number above or below this one. A `number` only. |
| `{"age_under": 18}`, `{"age_at_least": 18}` | Whole years from the date in the answer to today, under or at least this many. A `birthdate`, `date` or `datetime`; from 1 to 120. |

Several rules, up to ten, are joined: `{"match": "all", "rules": [...]}` asks the question when every rule is met, and `"match": "any"` when one is enough. Each rule names its own question:

```
"show_if": {
  "match": "any",
  "rules": [
    { "field": "birthday", "age_under": 18 },
    { "field": "with_school", "ticked": true }
  ]
}
```

A part of a condition can be a group of two or more rules with its own `match`, which is how *(A and B) or C* is written. A group holds rules, not further groups, and a condition has at most ten rules in all, counting those in its groups. And `"action": "hide"` turns a condition round: the question is hidden when the condition holds, and asked otherwise.

```
"show_if": {
  "action": "hide",
  "match": "any",
  "rules": [
    { "match": "all", "rules": [
      { "field": "member", "unticked": true },
      { "field": "birthday", "age_under": 18 } ] },
    { "field": "injured", "answered": true }
  ]
}
```

In the dashboard's builder, the condition says **Show** or **Hide**, and **+ Add a group** adds one. In a form's lines the same are `hide if` in place of `show if` on every part, a group as `show if all: member is unticked; birthday is
under age: 18` (its rules between semicolons), and `show if notes
does not contain: nuts`.

A rule about a question that was itself not asked is not met, whatever it says: its answer was cleared when it was hidden.

### A paragraph that depends on an answer

A paragraph of the document can be there only when an answer says so: the treatment consent's extra clause for somebody who is pregnant, the photo release left out for somebody who said no. Put a line of its own above it and another below it, in the words a question's `show if` takes:

```
[[show if pregnant is: Yes]]
My doctor has cleared me for this treatment while pregnant.
[[end]]

[[show if birthday is under age: 18 | show if with_school is ticked | show if any]]
A parent or guardian has read this with me.
[[end]]

[[hide if photos is ticked]]
We will not take or use any photographs of you.
[[end]]
```

`[[hide if ...]]` leaves a paragraph out when its condition holds, and a group is written as on a question's line: `[[show if any: birthday
is under age: 18; with_school is ticked | show if notes does not contain:
cleared]]`.

In the dashboard, **Show a paragraph only if…** under the text writes the two lines for you. A paragraph can name a question the signer answers, or a box you fill in on an uploaded PDF; not one asked once per child, not a question your staff fill in that has no place on the page, since nobody answers it on the document, and not a box the signature fills in, such as the signing date, which has no answer until after the paragraphs are shown. The markers are refused when the text is saved if they cannot be read, and a question they name that the template does not have, or cannot name, is refused when it is published.

**The first signer's answers decide it**: the first person in signing order who is not only copied in. One document has one text, so it is decided once. That signer is asked every question before the document, optional ones too, and reads it with the paragraphs their answers called for; when they sign, which paragraphs applied is frozen, and anybody else on the document waits until then, so nobody signs a text that could still change. The signed copy has only the paragraphs that applied, and its certificate says how many and whose answers decided them. The fingerprint is of the text as it was sent, every paragraph and its condition included, and the answers that decided it are in the evidence. The printable blank copy and the previews show every paragraph, each with the sentence saying when it applies.

Over the API, `GET /v1/sign/{token}` says so under `paragraphs`, and a page that draws the document itself passes back which paragraphs it drew when it signs. While they are undecided, the first signer's signature is refused without that, so an app or an integration that predates it cannot freeze a paragraph its signer never saw; see [the API reference](https://signsealer.com/docs/api).

`flag_when` marks an answer somebody at the business should read: the shooter who left *I am not under the influence of alcohol* unticked. The rule is kept with the document when it is sent, and the mark is worked out from the rule and the answer, so it cannot disagree with either. A flagged answer is listed under **Needs review** in the dashboard once the document is finished, and comes back `flagged: true` in the API. The signer is never told: a page that said so would teach the next signer which answer avoids the question. The flag is not on the certificate either, which is evidence of what was said, not of what the business made of it.

### Who answers

Every question is put to every person on the document who signs, approvers and witnesses included, and to nobody copied in, except the person signing for the business. A document with two signers asks each of them the whole list, and each answers for themselves. `supplied_by` changes that:

- **`adult`**: the person signing. The ordinary case.
- **`per_child`**: asked once for each child the document covers, named, with the child's name after the label. A document knows its children when it was started from a packet ([Reservations and packets](https://signsealer.com/docs/packets)) or by a booking's party ([Signers, roles and order](https://signsealer.com/docs/signers)); one sent with `POST /v1/documents/{id}/send` covers nobody, so it asks none. It cannot be placed on a page: one box cannot hold an answer per child.
- **`everyone`**: asked of each person for themselves and, for each child someone signs for, once more about that child, of whoever signs for them: "Can swim 50 metres" of every adult, and of Kit's parent for Kit. With no child on the document it is exactly `adult`. Like `per_child`, it is not placed on a page and no paragraph depends on it. A parent named to sign only for a child, who is not in the party themselves, is asked the child's questions and nothing about themselves. In the dashboard: *Each person, and a parent or guardian for each child*, which a new question about the person (swimming, allergies, a size, a date of birth) is set to until you choose.
- **`staff`**: never asked of a signer. Placed on an uploaded PDF, it is filled in by whoever sends the document, under `values` on `POST /v1/documents` or `fields` or `values` on a workflow start, and a required one that is missing refuses the send. The signer sees it filled in and cannot change it. Such a box cannot be a signature, initials, a photo or the signing date, cannot be `sensitive`, and cannot have a `show_if`, because it is filled in before anybody has answered anything. `GET /v1/workflows` lists a workflow's as `sender_fields`.
- **`business`**: answered by the person who signs for the business, and nobody else. On an uploaded PDF, the business's own signature line, its date and its name. That person is the signer sent with `for_business: true`, or a workflow's fixed role with `business: true`. Everybody else's questions are not asked of them, so each box on the page has one person's answer. A `business` question's `show_if` can name only another `business` question, and nobody else's can name one. Sent with nobody for the business, its boxes stay empty.

### A blank the signer fills in

A written template's blanks are the sender's to fill: on `POST /v1/documents` a blank with no value is refused with `no value for …`. A blank only the signer knows (a licence plate, an emergency contact) is filled by them instead: give the template a question with the blank's name and `"blank": true`, or on the dashboard tick *Write the answer into the document* on the question.

- **Sending.** The sender may still fill it. Then it is filled and nobody is asked. Left out of `values`, the text keeps `{{plate}}` for the signer.
- **Who answers.** The first signer: the first person in `sign_order`, never somebody copied in, never the person signing for the business. Nobody else is asked it.
- **Signing.** The signing page shows the question's label in brackets where the blank is, then the signer's answer once they give it. Their signature writes the answers into the text, in words as a form's answers are, before the text is dated and fingerprinted. Every signature, the certificate and `GET /v1/documents/{id}/verify` are of the finished text.
- **Order.** Nobody signs a text with a blank still open. The first signer is told to answer it, and anybody else that the document is waiting for the first signer: in parallel or in order, the first signer signs first.
- **Evidence.** The first signature's event keeps which blanks it filled and the fingerprint of the text before (`detail.filled`), and the certificate names them.

Because everyone who reads the document reads the answer, a blank question must be words that can sit in a sentence (not a signature, initials, a tick box, a photo or the last four of a Social Security number), required, not `sensitive`, without a `show_if`, and for no particular `recipient`. A template is refused if a blank question names a blank the text does not have, or the signing date.

### What the signer sees

The signing page runs no script, so every box is one the browser draws and checks itself. None of that is the check; the engine is.

- The questions come after the signer agrees to sign electronically and before the signature, under the document, in the order of the list. A workflow can ask them before the document instead (`document_after_questions` on `GET /v1/sign/{token}`).
- A block's questions are drawn under its heading and introduction. Several in a block are one form with one **Continue**, unless the block holds a photo or a per-child question; then each is asked on its own. The page groups a block's questions where they sit next to each other in the list, so keep them together.
- A block with `block_step` is a page of its own. The page always opens on the first step with anything left to answer, so a signer who comes back lands where they stopped, and a step whose questions are all hidden is skipped.
- An optional question says *(optional)* beside its label and can be passed: *Save or skip*, *Leave it unticked*, *Carry on without a photo*.
- A question placed on an uploaded PDF is a box on the page, filled in on the same step as the signature. A signature box and a signing-date box are filled by signing, and a box the sender filled is shown and not asked ([Signing a PDF](https://signsealer.com/docs/pdf)).

Your own signing screen reads the questions from `GET /v1/sign/{token}`, each with `visible`, the engine's own answer to its condition: draw only the visible ones. A screen that decides conditions itself as the answers come in has `rules_at_start`, the engine's answer to each rule on its own, for a rule about a question it does not ask, and `condition_zone`, the zone whose day an age is counted on. Answer with `POST /v1/sign/{token}/fields`, taking `key`, `value` (up to 20,000 characters) and, for a per-child question, `about`; a photo goes to `POST /v1/sign/{token}/fields/{key}/photo`. A refused answer is `422` with the engine's sentence, such as *Date of birth needs the year in full, like 1984*. While a required, visible question is unanswered, `POST /v1/sign/{token}` is refused with `422` naming each one: *still needed before signing: …*.

### An example

A kayak rental waiver: a safety statement that is optional but flagged when left unticked, a birthday, a section on its own page with a follow-up that is only asked after a yes, a medical note that is masked and always flagged when given, an optional photo, and initials.

```
"fields": [
  { "key": "swimmer", "label": "I can swim 50 metres unaided", "kind": "checkbox",
    "required": false, "flag_when": { "unticked": true } },
  { "key": "date_of_birth", "label": "Date of birth", "kind": "birthdate" },
  { "key": "paddled_before", "label": "Have you paddled before?", "kind": "choice",
    "options": ["Yes", "No"],
    "block": "experience", "block_label": "Your paddling",
    "block_intro": "So we can give you the right boat.", "block_step": true },
  { "key": "trips", "label": "Roughly how many trips?", "kind": "number",
    "block": "experience", "show_if": { "field": "paddled_before", "equals": ["Yes"] } },
  { "key": "medical", "label": "Anything medical we should know about?", "kind": "paragraph",
    "required": false, "sensitive": true, "hint": "Only what affects you on the water.",
    "flag_when": { "answered": true } },
  { "key": "hull_photo", "label": "Photo of the boat before you launch", "kind": "photo",
    "required": false },
  { "key": "rules_initials", "label": "Initial to confirm you read the safety rules",
    "kind": "initials" }
]
```

### How answers come back

`GET /v1/documents/{id}` carries `answers`: every question on the document, in the order the form asks it, for each signer in turn.

```
"answers": [
  { "signer_id": "5f0a…", "key": "swimmer", "label": "I can swim 50 metres unaided",
    "kind": "checkbox", "block": null, "about": null, "required": false,
    "sensitive": false, "asked": true, "value": "",
    "supplied_at": "2026-10-03T14:20:51Z", "flagged": true },
  { "signer_id": "5f0a…", "key": "medical", "label": "Anything medical we should know about?",
    "kind": "paragraph", "block": null, "about": null, "required": false,
    "sensitive": true, "asked": true, "value": "•••••••thma",
    "supplied_at": "2026-10-03T14:21:30Z", "flagged": true }
],
"flagged": 2
```

- `asked` is whether the question was on that signer's page. A question its condition hid is `asked: false`, has no value, and is never flagged.
- A `sensitive` value is masked: shorter than eight characters, it is all dots; longer, dots and its last four.
- A photo's value is `sha256:<hex>`, the fingerprint of the photograph kept with the document.
- `about` names the child a per-child answer is for, and `block` the block it was asked in.
- `flagged` on the document counts the flagged answers.
- A redacted document keeps its questions and gives up every value, and each child's name: `about` reads *Redacted child 1*, *Redacted child 2* and so on, the same child the same number on every question.

The AI assistants' `signsealer_get_document` leaves the answers out, and says how many there are, unless asked with `include_answers: true` ([AI assistants](https://signsealer.com/docs/mcp)).

Webhooks do not carry answers, on purpose: a webhook goes to whatever address was typed into a form, and some answers are about somebody's health. Two events come close. `signing.photo_supplied` names the question and the child it was about and carries the photo's SHA-256, never the image; and when the sender filled boxes on an uploaded PDF, `signing.created` lists their keys under `detail.filled_by_sender`, never the values ([Webhooks](https://signsealer.com/docs/webhooks)). Wait for `signing.completed`, then read the document.

### What is frozen, and when

The list is part of the version. While the version is a draft it changes freely; once it is published, `PATCH` answers `422`, and the way to ask something different is the next version, with `fields` on `POST /v1/templates/{id}/revise`. What you were asked to initial is part of what you agreed to.

Then each document keeps its own copy. When a document is sent, every question is written onto it for each signer: its label, kind, options, hint, whether it is required or sensitive, its block's heading and introduction, its condition, its flag rule and its place on the page. A later version changes nothing about a document already sent, so a flag rule changed next season does not decide what last season's answers meant.

## What happens to what was already sent

- **Documents already sent keep their version.** The text is stored on the document when it is prepared, and a new version changes nothing about a document on its way to a signer.
- **New documents use the newest published version.** A draft is never sent.
- **A tablet that ran the form with no network** names the version it showed (`expected_template_version`) when it catches up. If a newer one was published meanwhile, the start answers `409 template_changed` and nothing is sealed against words the person did not read.

## Settings that outlive a version

Some settings belong to the code, not one version, and carry over to every version after: `PATCH /v1/templates/{id}/settings` with any of

| Setting | Means |
| --- | --- |
| valid_months | How long a signature stays good, in months; `null` for as long as the document is kept. `GET /v1/standing` answers against it. |
| remind_days | Days before the end each signer is emailed a link to sign again. Needs `valid_months`. |
| resign | `true`: everybody who signed an older version must sign the newest published one; their standing reads `resign`. `false` lifts it. |
| one_time | Made to send once rather than reused. |
| show_address | The business's address printed under it. |
| photos_in_copy | The photographs a signer takes as answers are printed after the certificate in the signed PDF, each with its SHA-256, under the same seal. On unless turned off; the certificate keeps every hash either way. |

### What an NDA grants

An NDA's template can carry `grants`: a JSON object, set when the template is created (`POST /v1/templates`), recording what signing it gives the signer. SignSealer keeps it and does not act on it: who may see your material is for the system that holds the material to decide. A template of any other `kind` that carries one is refused with `422` (“only an NDA carries a grant”).

Grants belong to a version, as its text does. `PATCH` does not change them; a revision carries the newest version's forward, and a restore brings back the restored version's. They come back on the template (`GET /v1/templates/{id}`); on each document made from it, as `grants` on `GET /v1/documents/{id}`, where each signer whose role is `signer` is also marked `grants: true`; on the signing link (`GET /v1/sign/{token}`); and in the certificate, as `payload.document.grants` from `GET /v1/documents/{id}/certificate`, sealed into its hash when the document completes. The sealed PDF does not print them, and the `signing.completed` webhook does not carry them: read the document or its certificate when it arrives.

## A template that is a PDF

Uploading the file is a dashboard step, where the boxes are placed on its pages; there is no API route for the upload yet ([Signing a PDF](https://signsealer.com/docs/pdf)). Everything on this page works on it afterwards, except changing its text: a PDF's text is the file. Revise it to rename it or change its questions; to change what it says, start a new template from the new file.

[This page as Markdown](https://signsealer.com/docs/templates.md) Ask an AI about it: [ChatGPT](https://chatgpt.com/?q=Please%20read%20https%3A%2F%2Fsignsealer.com%2Fdocs%2Ftemplates%20and%20explain%20it%20to%20me%20as%20a%20developer%20adding%20SignSealer%20to%20my%20application%3A%20what%20it%20covers%2C%20the%20calls%20involved%20and%20anything%20to%20watch%20out%20for.%20Use%20https%3A%2F%2Fsignsealer.com%2Fllms.txt%20for%20the%20rest%20of%20the%20docs%2C%20and%20cite%20the%20page%27s%20URL%20in%20your%20answer.) · [Claude](https://claude.ai/new?q=Please%20read%20https%3A%2F%2Fsignsealer.com%2Fdocs%2Ftemplates%20and%20explain%20it%20to%20me%20as%20a%20developer%20adding%20SignSealer%20to%20my%20application%3A%20what%20it%20covers%2C%20the%20calls%20involved%20and%20anything%20to%20watch%20out%20for.%20Use%20https%3A%2F%2Fsignsealer.com%2Fllms.txt%20for%20the%20rest%20of%20the%20docs%2C%20and%20cite%20the%20page%27s%20URL%20in%20your%20answer.) · [Perplexity](https://www.perplexity.ai/search?q=Please%20read%20https%3A%2F%2Fsignsealer.com%2Fdocs%2Ftemplates%20and%20explain%20it%20to%20me%20as%20a%20developer%20adding%20SignSealer%20to%20my%20application%3A%20what%20it%20covers%2C%20the%20calls%20involved%20and%20anything%20to%20watch%20out%20for.%20Use%20https%3A%2F%2Fsignsealer.com%2Fllms.txt%20for%20the%20rest%20of%20the%20docs%2C%20and%20cite%20the%20page%27s%20URL%20in%20your%20answer.) · [Google AI](https://www.google.com/search?udm=50&q=Please%20read%20https%3A%2F%2Fsignsealer.com%2Fdocs%2Ftemplates%20and%20explain%20it%20to%20me%20as%20a%20developer%20adding%20SignSealer%20to%20my%20application%3A%20what%20it%20covers%2C%20the%20calls%20involved%20and%20anything%20to%20watch%20out%20for.%20Use%20https%3A%2F%2Fsignsealer.com%2Fllms.txt%20for%20the%20rest%20of%20the%20docs%2C%20and%20cite%20the%20page%27s%20URL%20in%20your%20answer.) · [Grok](https://grok.com/?q=Please%20read%20https%3A%2F%2Fsignsealer.com%2Fdocs%2Ftemplates%20and%20explain%20it%20to%20me%20as%20a%20developer%20adding%20SignSealer%20to%20my%20application%3A%20what%20it%20covers%2C%20the%20calls%20involved%20and%20anything%20to%20watch%20out%20for.%20Use%20https%3A%2F%2Fsignsealer.com%2Fllms.txt%20for%20the%20rest%20of%20the%20docs%2C%20and%20cite%20the%20page%27s%20URL%20in%20your%20answer.)
