# Templates API reference

> Reusable documents with fields and roles, used to create signature requests.

Source: https://signwith.co/docs/api/templates · Updated 2026-10-02

## List templates

`GET https://app.signwith.co/api/v1/templates`

Read-only keys can call this.

Lists the templates the key's user can access, newest first. Use it to let users pick a
template in your app, or to look up a template by your own `external_id` or by folder.
Archived templates are excluded unless `archived=true`. List items omit `fields` and
`documents`; fetch a single template to get them.

### Query parameters

| Name | Type | Description |
| --- | --- | --- |
| `limit` | integer | Number of items per page, 1–100. Values outside that range fall back to 20 (below 1) or 100 (above 100). Default `20`. |
| `cursor` | integer | The `next_cursor` from the previous page. Omit it for the first page. |
| `q` | string | Case-insensitive search on the template name. |
| `archived` | boolean | `true` to list only archived templates instead of active ones. Default `false`. |
| `external_id` | string | Only templates with this `external_id`. |
| `folder` | string | Only templates in the folder with this exact name. |

### Request sample

cURL:

```bash
curl https://app.signwith.co/api/v1/templates \
  -H "Authorization: Bearer $SIGNWITH_API_KEY"
```

Node:

```javascript
const response = await fetch('https://app.signwith.co/api/v1/templates', {
  headers: {
    Authorization: `Bearer ${process.env.SIGNWITH_API_KEY}`,
  },
})

console.log(response.status, await response.json())
```

Python:

```python
import os

import requests

response = requests.get(
    "https://app.signwith.co/api/v1/templates",
    headers={
        "Authorization": f"Bearer {os.environ['SIGNWITH_API_KEY']}",
    },
)

print(response.status_code, response.json())
```

### Response 200

A page of templates.

```json
{
  "object": "list",
  "data": [
    {
      "object": "template",
      "id": 311,
      "name": "Residential lease",
      "external_id": "lease-v3",
      "folder": "Leasing",
      "roles": [
        "Tenant",
        "Landlord"
      ],
      "edit_url": "https://app.signwith.co/templates/311/edit",
      "created_by": {
        "id": 42,
        "email": "ada@acme.co",
        "name": "Ada Lovelace"
      },
      "archived_at": null,
      "created_at": "2026-09-20T09:12:44Z",
      "updated_at": "2026-09-21T16:03:10Z"
    }
  ],
  "has_more": true,
  "next_cursor": 311
}
```

### Errors

| Status | Meaning |
| --- | --- |
| 401 | The API key is missing, invalid or expired, or its account has been archived. |
| 403 | The key is read-only, or its user can't access this resource. |
| 429 | Rate limit exceeded (`rate_limited`, with `Retry-After`); more than 20 `POST /feedback` messages in an hour (`rate_limited`, with `Retry-After`: seconds until the next clock hour); or — for `POST /signature_requests/{id}/remind` — signers were reminded less than an hour ago (`remind_too_soon`, with `Retry-After`).  |
| 500 | Something went wrong on SignWith's side. It's safe to retry with the same `Idempotency-Key`. |

## Create a template from documents

`POST https://app.signwith.co/api/v1/templates`

Needs a full-access key. Accepts `Idempotency-Key`.

Uploads one or more documents (PDF or image, up to 10 per template, 25 MB each) and creates a
template from them. Fillable PDF form fields are converted into template fields automatically.

**Text tags.** Write fields into the document itself and they're placed where the tag is, with
the tag text hidden: `{{Client signature;type=signature;role=Client}}`. The first part is the
field name, followed by `key=value` settings: `type` (any field type; default `text`), `role`
(created on the template if new), `required` (default `true`), `options` (comma-separated, for
`select`) and `width`/`height` in points. `{{signature;role=Client}}` on its own is a signature
field named "Signature". The same tag on several pages becomes one field (e.g. initials on every
page). When every tag names a role, the template gets exactly those roles. Tags work in PDFs from
any editor; keep each one on a line of its own text, or colour it white, for the cleanest result.

To place signature and other fields yourself, pass `fields` (JSON requests): each field has a
`type`, a `role` and one or more `areas` giving its page and position as fractions of the page
size. Roles named in `fields` are created on the template. Otherwise, open the returned
`edit_url` and place fields in the SignWith editor — a template needs at least one field before
it can be sent.

Use it to sync documents generated by your system into SignWith. Two request formats are
supported:

- `application/json` — `documents` is an array of `{ name, file }` where `file` is base64
  content (a `data:` URI prefix is allowed) or an `https://` URL SignWith downloads.
- `multipart/form-data` — upload files directly as `documents[]`.

If `name` is omitted, the first document's filename is used. If `folder` doesn't exist it is
created. Invalid `fields` return `422 invalid_field`. Triggers the `template.created` webhook.

### Headers

| Name | Type | Description |
| --- | --- | --- |
| `Idempotency-Key` | string | A unique value (e.g. a UUID) that makes retries of this request safe. A successful response is stored for 24 hours and replayed for retries with the same key.  |

### Request body (`application/json`)

- `name` (string). Template name. Defaults to the first document's name.
- `external_id` (string). Your own ID for the template.
- `folder` (string). Folder name. Created if it doesn't exist.
- `password` (string). Password for encrypted PDFs.
- `documents` (array of objects, required, 1 to 10 items).
  - `name` (string). Document name. Defaults to `Document <n>`.
  - `file` (string, required). Base64-encoded PDF or image (a `data:` URI prefix is allowed), or an `https://` URL to download it from. Max 25 MB.
- `fields` (array of objects). Fields to place on the documents, in addition to any fillable PDF form fields. Roles named here are added to the template (at most 10 roles).
  - `name` (string). Field name, used as the key in `prefill`. Defaults to e.g. `Signature 2`.
  - `type` (string, required, one of `text`, `signature`, `initials`, `date`, `checkbox`, `number`, `phone`, `select`, `radio`, `multiple`, `image`, `file`, `stamp`).
  - `role` (string). Role that fills this field. Created on the template if it doesn't exist. Defaults to the template's first role.
  - `required` (boolean, default `true`).
  - `options` (array of strings). Choices for `select`, `radio` and `multiple` fields (required for those types).
  - `areas` (array of objects, required, at least 1 item). Where the field goes. A field can appear in several places.
    - `page` (integer, required, at least 1). 1-based page number; must exist in the document.
    - `x` (number, required, 0 to 1).
    - `y` (number, required, 0 to 1).
    - `w` (number, required, at most 1, greater than 0).
    - `h` (number, required, at most 1, greater than 0).
    - `document` (integer, default `0`, at least 0). 0-based index of the document within the template.

### Request body (`multipart/form-data`)

- `name` (string). Template name. Defaults to the first file's name.
- `external_id` (string).
- `folder` (string). Folder name. Created if it doesn't exist.
- `password` (string). Password for encrypted PDFs.
- `documents[]` (files, required, 1 to 10 items). PDF or image files, 25 MB max each.

### Request sample

cURL:

```bash
curl -X POST https://app.signwith.co/api/v1/templates \
  -H "Authorization: Bearer $SIGNWITH_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
  "name": "Residential lease",
  "external_id": "lease-v3",
  "folder": "Leasing",
  "documents": [
    {
      "name": "Lease agreement",
      "file": "https://files.acme.co/templates/lease-v3.pdf"
    }
  ]
}'
```

Node:

```javascript
const response = await fetch('https://app.signwith.co/api/v1/templates', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.SIGNWITH_API_KEY}`,
    'Content-Type': 'application/json',
    'Idempotency-Key': crypto.randomUUID(),
  },
  body: JSON.stringify({
    name: 'Residential lease',
    external_id: 'lease-v3',
    folder: 'Leasing',
    documents: [
      {
        name: 'Lease agreement',
        file: 'https://files.acme.co/templates/lease-v3.pdf',
      },
    ],
  }),
})

console.log(response.status, await response.json())
```

Python:

```python
import os
import uuid

import requests

response = requests.post(
    "https://app.signwith.co/api/v1/templates",
    headers={
        "Authorization": f"Bearer {os.environ['SIGNWITH_API_KEY']}",
        "Idempotency-Key": str(uuid.uuid4()),
    },
    json={
        "name": "Residential lease",
        "external_id": "lease-v3",
        "folder": "Leasing",
        "documents": [
            {
                "name": "Lease agreement",
                "file": "https://files.acme.co/templates/lease-v3.pdf",
            },
        ],
    },
)

print(response.status_code, response.json())
```

### Response 201

The template was created.

```json
{
  "object": "template",
  "id": 311,
  "name": "Residential lease",
  "external_id": "lease-v3",
  "folder": "Leasing",
  "roles": [
    "Tenant",
    "Landlord"
  ],
  "edit_url": "https://app.signwith.co/templates/311/edit",
  "created_by": {
    "id": 42,
    "email": "ada@acme.co",
    "name": "Ada Lovelace"
  },
  "archived_at": null,
  "created_at": "2026-09-20T09:12:44Z",
  "updated_at": "2026-09-21T16:03:10Z",
  "fields": [
    {
      "id": "0f9c2b7e-5d1a-4e8b-9a61-3c2e7d4f1a90",
      "name": "Tenant name",
      "type": "text",
      "role": "Tenant",
      "required": true
    },
    {
      "id": "6a3e1d42-8b7c-4f19-a0d5-2e9b4c7f8a13",
      "name": "Monthly rent",
      "type": "number",
      "role": "Tenant",
      "required": true
    },
    {
      "id": "b2d8f4a1-3c6e-4a7b-8d92-5f1e0c3a9b76",
      "name": "Start date",
      "type": "date",
      "role": "Tenant",
      "required": true
    },
    {
      "id": "91c7e3b5-2a4d-4f8e-b610-7d3a5c9e2f48",
      "name": "Pets",
      "type": "select",
      "role": "Tenant",
      "required": false,
      "options": [
        "None",
        "Cat",
        "Dog"
      ]
    },
    {
      "id": "4e8a2c6f-9b1d-4a3e-8c57-1f6d0b9e3a24",
      "name": "Tenant signature",
      "type": "signature",
      "role": "Tenant",
      "required": true
    },
    {
      "id": "c5f1a9d3-7e2b-4c8a-9f60-3b8e4d2a7c15",
      "name": "Landlord signature",
      "type": "signature",
      "role": "Landlord",
      "required": true
    }
  ],
  "documents": [
    {
      "id": 7730,
      "name": "Lease agreement",
      "url": "https://app.signwith.co/file/eyJfcmFpbHMiOnsiZGF0YSI6MTIzfX0/lease-agreement.pdf",
      "preview_image_url": "https://app.signwith.co/file/eyJfcmFpbHMiOnsiZGF0YSI6MTI0fX0/0.jpg"
    }
  ]
}
```

### Errors

| Status | Meaning |
| --- | --- |
| 400 | The request body is not valid JSON. |
| 401 | The API key is missing, invalid or expired, or its account has been archived. |
| 403 | The key is read-only, or its user can't access this resource. |
| 409 | A request with the same `Idempotency-Key` is still being processed. Retry shortly. |
| 422 | The request is valid JSON but can't be processed. See `error.code`; the codes each endpoint can return are described in the endpoint's description and in the error table above.  |
| 429 | Rate limit exceeded (`rate_limited`, with `Retry-After`); more than 20 `POST /feedback` messages in an hour (`rate_limited`, with `Retry-After`: seconds until the next clock hour); or — for `POST /signature_requests/{id}/remind` — signers were reminded less than an hour ago (`remind_too_soon`, with `Retry-After`).  |
| 500 | Something went wrong on SignWith's side. It's safe to retry with the same `Idempotency-Key`. |

## Get a template

`GET https://app.signwith.co/api/v1/templates/{id}`

Read-only keys can call this.

Returns a template with its roles, fields and documents. Use it to find out which roles to
assign signers to and which field names you can prefill before creating a signature request.

### Path parameters

| Name | Type | Description |
| --- | --- | --- |
| `id` (required) | integer | Template ID. |

### Request sample

cURL:

```bash
curl https://app.signwith.co/api/v1/templates/311 \
  -H "Authorization: Bearer $SIGNWITH_API_KEY"
```

Node:

```javascript
const response = await fetch('https://app.signwith.co/api/v1/templates/311', {
  headers: {
    Authorization: `Bearer ${process.env.SIGNWITH_API_KEY}`,
  },
})

console.log(response.status, await response.json())
```

Python:

```python
import os

import requests

response = requests.get(
    "https://app.signwith.co/api/v1/templates/311",
    headers={
        "Authorization": f"Bearer {os.environ['SIGNWITH_API_KEY']}",
    },
)

print(response.status_code, response.json())
```

### Response 200

The template.

```json
{
  "object": "template",
  "id": 311,
  "name": "Residential lease",
  "external_id": "lease-v3",
  "folder": "Leasing",
  "roles": [
    "Tenant",
    "Landlord"
  ],
  "edit_url": "https://app.signwith.co/templates/311/edit",
  "created_by": {
    "id": 42,
    "email": "ada@acme.co",
    "name": "Ada Lovelace"
  },
  "archived_at": null,
  "created_at": "2026-09-20T09:12:44Z",
  "updated_at": "2026-09-21T16:03:10Z",
  "fields": [
    {
      "id": "0f9c2b7e-5d1a-4e8b-9a61-3c2e7d4f1a90",
      "name": "Tenant name",
      "type": "text",
      "role": "Tenant",
      "required": true
    },
    {
      "id": "6a3e1d42-8b7c-4f19-a0d5-2e9b4c7f8a13",
      "name": "Monthly rent",
      "type": "number",
      "role": "Tenant",
      "required": true
    },
    {
      "id": "b2d8f4a1-3c6e-4a7b-8d92-5f1e0c3a9b76",
      "name": "Start date",
      "type": "date",
      "role": "Tenant",
      "required": true
    },
    {
      "id": "91c7e3b5-2a4d-4f8e-b610-7d3a5c9e2f48",
      "name": "Pets",
      "type": "select",
      "role": "Tenant",
      "required": false,
      "options": [
        "None",
        "Cat",
        "Dog"
      ]
    },
    {
      "id": "4e8a2c6f-9b1d-4a3e-8c57-1f6d0b9e3a24",
      "name": "Tenant signature",
      "type": "signature",
      "role": "Tenant",
      "required": true
    },
    {
      "id": "c5f1a9d3-7e2b-4c8a-9f60-3b8e4d2a7c15",
      "name": "Landlord signature",
      "type": "signature",
      "role": "Landlord",
      "required": true
    }
  ],
  "documents": [
    {
      "id": 7730,
      "name": "Lease agreement",
      "url": "https://app.signwith.co/file/eyJfcmFpbHMiOnsiZGF0YSI6MTIzfX0/lease-agreement.pdf",
      "preview_image_url": "https://app.signwith.co/file/eyJfcmFpbHMiOnsiZGF0YSI6MTI0fX0/0.jpg"
    }
  ]
}
```

### Errors

| Status | Meaning |
| --- | --- |
| 401 | The API key is missing, invalid or expired, or its account has been archived. |
| 403 | The key is read-only, or its user can't access this resource. |
| 404 | The resource doesn't exist or belongs to another account. |
| 429 | Rate limit exceeded (`rate_limited`, with `Retry-After`); more than 20 `POST /feedback` messages in an hour (`rate_limited`, with `Retry-After`: seconds until the next clock hour); or — for `POST /signature_requests/{id}/remind` — signers were reminded less than an hour ago (`remind_too_soon`, with `Retry-After`).  |
| 500 | Something went wrong on SignWith's side. It's safe to retry with the same `Idempotency-Key`. |

## Update a template

`PATCH https://app.signwith.co/api/v1/templates/{id}`

Needs a full-access key.

Renames a template, changes its `external_id` or folder, renames its roles, or replaces its
fields. Use it to keep template metadata in sync with your system, or to place fields on a
template created without them. Only the parameters you send are changed.

`roles` is matched by position: the first name renames the first role, and so on. Extra names
add new roles (without fields). Roles can't be removed through the API.

`fields`, when sent, **replaces all of the template's fields** (send `[]` to remove them all).
Roles named in `fields` that don't exist yet are added. Invalid fields return
`422 invalid_field`.

Changes only affect signature requests sent afterwards: requests already sent keep the fields
and documents they were sent with. `PUT` is accepted as an alias. Triggers the
`template.updated` webhook.

### Path parameters

| Name | Type | Description |
| --- | --- | --- |
| `id` (required) | integer | Template ID. |

### Request body (`application/json`)

- `name` (string).
- `external_id` (string or null). Your own ID for the template. Send `null` to clear it.
- `folder` (string). Folder name. Created if it doesn't exist.
- `roles` (array of strings). New role names, matched by position. Extra names add roles.
- `fields` (array of objects). Replaces all of the template's fields. Roles named here are added if missing.
  - `name` (string). Field name, used as the key in `prefill`. Defaults to e.g. `Signature 2`.
  - `type` (string, required, one of `text`, `signature`, `initials`, `date`, `checkbox`, `number`, `phone`, `select`, `radio`, `multiple`, `image`, `file`, `stamp`).
  - `role` (string). Role that fills this field. Created on the template if it doesn't exist. Defaults to the template's first role.
  - `required` (boolean, default `true`).
  - `options` (array of strings). Choices for `select`, `radio` and `multiple` fields (required for those types).
  - `areas` (array of objects, required, at least 1 item). Where the field goes. A field can appear in several places.
    - `page` (integer, required, at least 1). 1-based page number; must exist in the document.
    - `x` (number, required, 0 to 1).
    - `y` (number, required, 0 to 1).
    - `w` (number, required, at most 1, greater than 0).
    - `h` (number, required, at most 1, greater than 0).
    - `document` (integer, default `0`, at least 0). 0-based index of the document within the template.

### Request sample

cURL:

```bash
curl -X PATCH https://app.signwith.co/api/v1/templates/311 \
  -H "Authorization: Bearer $SIGNWITH_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "name": "Residential lease (2027)",
  "external_id": "lease-v4",
  "folder": "Leasing",
  "roles": [
    "Tenant",
    "Landlord"
  ]
}'
```

Node:

```javascript
const response = await fetch('https://app.signwith.co/api/v1/templates/311', {
  method: 'PATCH',
  headers: {
    Authorization: `Bearer ${process.env.SIGNWITH_API_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    name: 'Residential lease (2027)',
    external_id: 'lease-v4',
    folder: 'Leasing',
    roles: ['Tenant', 'Landlord'],
  }),
})

console.log(response.status, await response.json())
```

Python:

```python
import os

import requests

response = requests.patch(
    "https://app.signwith.co/api/v1/templates/311",
    headers={
        "Authorization": f"Bearer {os.environ['SIGNWITH_API_KEY']}",
    },
    json={
        "name": "Residential lease (2027)",
        "external_id": "lease-v4",
        "folder": "Leasing",
        "roles": ["Tenant", "Landlord"],
    },
)

print(response.status_code, response.json())
```

### Response 200

The updated template.

```json
{
  "object": "template",
  "id": 311,
  "name": "Residential lease",
  "external_id": "lease-v3",
  "folder": "Leasing",
  "roles": [
    "Tenant",
    "Landlord"
  ],
  "edit_url": "https://app.signwith.co/templates/311/edit",
  "created_by": {
    "id": 42,
    "email": "ada@acme.co",
    "name": "Ada Lovelace"
  },
  "archived_at": null,
  "created_at": "2026-09-20T09:12:44Z",
  "updated_at": "2026-09-21T16:03:10Z",
  "fields": [
    {
      "id": "0f9c2b7e-5d1a-4e8b-9a61-3c2e7d4f1a90",
      "name": "Tenant name",
      "type": "text",
      "role": "Tenant",
      "required": true
    },
    {
      "id": "6a3e1d42-8b7c-4f19-a0d5-2e9b4c7f8a13",
      "name": "Monthly rent",
      "type": "number",
      "role": "Tenant",
      "required": true
    },
    {
      "id": "b2d8f4a1-3c6e-4a7b-8d92-5f1e0c3a9b76",
      "name": "Start date",
      "type": "date",
      "role": "Tenant",
      "required": true
    },
    {
      "id": "91c7e3b5-2a4d-4f8e-b610-7d3a5c9e2f48",
      "name": "Pets",
      "type": "select",
      "role": "Tenant",
      "required": false,
      "options": [
        "None",
        "Cat",
        "Dog"
      ]
    },
    {
      "id": "4e8a2c6f-9b1d-4a3e-8c57-1f6d0b9e3a24",
      "name": "Tenant signature",
      "type": "signature",
      "role": "Tenant",
      "required": true
    },
    {
      "id": "c5f1a9d3-7e2b-4c8a-9f60-3b8e4d2a7c15",
      "name": "Landlord signature",
      "type": "signature",
      "role": "Landlord",
      "required": true
    }
  ],
  "documents": [
    {
      "id": 7730,
      "name": "Lease agreement",
      "url": "https://app.signwith.co/file/eyJfcmFpbHMiOnsiZGF0YSI6MTIzfX0/lease-agreement.pdf",
      "preview_image_url": "https://app.signwith.co/file/eyJfcmFpbHMiOnsiZGF0YSI6MTI0fX0/0.jpg"
    }
  ]
}
```

### Errors

| Status | Meaning |
| --- | --- |
| 400 | The request body is not valid JSON. |
| 401 | The API key is missing, invalid or expired, or its account has been archived. |
| 403 | The key is read-only, or its user can't access this resource. |
| 404 | The resource doesn't exist or belongs to another account. |
| 422 | The request is valid JSON but can't be processed. See `error.code`; the codes each endpoint can return are described in the endpoint's description and in the error table above.  |
| 429 | Rate limit exceeded (`rate_limited`, with `Retry-After`); more than 20 `POST /feedback` messages in an hour (`rate_limited`, with `Retry-After`: seconds until the next clock hour); or — for `POST /signature_requests/{id}/remind` — signers were reminded less than an hour ago (`remind_too_soon`, with `Retry-After`).  |
| 500 | Something went wrong on SignWith's side. It's safe to retry with the same `Idempotency-Key`. |

## Duplicate a template

`POST https://app.signwith.co/api/v1/templates/{id}/duplicate`

Needs a full-access key. Accepts `Idempotency-Key`.

Creates a copy of a template, including its documents, fields and roles. Use it to create a
variant (for example a per-customer version) without re-uploading and re-placing fields.
Optionally give the copy a new name, `external_id` or folder. Triggers the
`template.created` webhook.

### Path parameters

| Name | Type | Description |
| --- | --- | --- |
| `id` (required) | integer | Template ID. |

### Headers

| Name | Type | Description |
| --- | --- | --- |
| `Idempotency-Key` | string | A unique value (e.g. a UUID) that makes retries of this request safe. A successful response is stored for 24 hours and replayed for retries with the same key.  |

### Request body (`application/json`)

- `name` (string). Name of the copy. Defaults to the original name followed by "(Clone)".
- `external_id` (string).
- `folder` (string). Folder for the copy. Created if it doesn't exist.

### Request sample

cURL:

```bash
curl -X POST https://app.signwith.co/api/v1/templates/311/duplicate \
  -H "Authorization: Bearer $SIGNWITH_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
  "name": "Residential lease — Riverside Apartments",
  "external_id": "lease-v3-riverside",
  "folder": "Leasing"
}'
```

Node:

```javascript
const response = await fetch('https://app.signwith.co/api/v1/templates/311/duplicate', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.SIGNWITH_API_KEY}`,
    'Content-Type': 'application/json',
    'Idempotency-Key': crypto.randomUUID(),
  },
  body: JSON.stringify({
    name: 'Residential lease — Riverside Apartments',
    external_id: 'lease-v3-riverside',
    folder: 'Leasing',
  }),
})

console.log(response.status, await response.json())
```

Python:

```python
import os
import uuid

import requests

response = requests.post(
    "https://app.signwith.co/api/v1/templates/311/duplicate",
    headers={
        "Authorization": f"Bearer {os.environ['SIGNWITH_API_KEY']}",
        "Idempotency-Key": str(uuid.uuid4()),
    },
    json={
        "name": "Residential lease — Riverside Apartments",
        "external_id": "lease-v3-riverside",
        "folder": "Leasing",
    },
)

print(response.status_code, response.json())
```

### Response 201

The new template.

```json
{
  "object": "template",
  "id": 311,
  "name": "Residential lease",
  "external_id": "lease-v3",
  "folder": "Leasing",
  "roles": [
    "Tenant",
    "Landlord"
  ],
  "edit_url": "https://app.signwith.co/templates/311/edit",
  "created_by": {
    "id": 42,
    "email": "ada@acme.co",
    "name": "Ada Lovelace"
  },
  "archived_at": null,
  "created_at": "2026-09-20T09:12:44Z",
  "updated_at": "2026-09-21T16:03:10Z",
  "fields": [
    {
      "id": "0f9c2b7e-5d1a-4e8b-9a61-3c2e7d4f1a90",
      "name": "Tenant name",
      "type": "text",
      "role": "Tenant",
      "required": true
    },
    {
      "id": "6a3e1d42-8b7c-4f19-a0d5-2e9b4c7f8a13",
      "name": "Monthly rent",
      "type": "number",
      "role": "Tenant",
      "required": true
    },
    {
      "id": "b2d8f4a1-3c6e-4a7b-8d92-5f1e0c3a9b76",
      "name": "Start date",
      "type": "date",
      "role": "Tenant",
      "required": true
    },
    {
      "id": "91c7e3b5-2a4d-4f8e-b610-7d3a5c9e2f48",
      "name": "Pets",
      "type": "select",
      "role": "Tenant",
      "required": false,
      "options": [
        "None",
        "Cat",
        "Dog"
      ]
    },
    {
      "id": "4e8a2c6f-9b1d-4a3e-8c57-1f6d0b9e3a24",
      "name": "Tenant signature",
      "type": "signature",
      "role": "Tenant",
      "required": true
    },
    {
      "id": "c5f1a9d3-7e2b-4c8a-9f60-3b8e4d2a7c15",
      "name": "Landlord signature",
      "type": "signature",
      "role": "Landlord",
      "required": true
    }
  ],
  "documents": [
    {
      "id": 7730,
      "name": "Lease agreement",
      "url": "https://app.signwith.co/file/eyJfcmFpbHMiOnsiZGF0YSI6MTIzfX0/lease-agreement.pdf",
      "preview_image_url": "https://app.signwith.co/file/eyJfcmFpbHMiOnsiZGF0YSI6MTI0fX0/0.jpg"
    }
  ]
}
```

### Errors

| Status | Meaning |
| --- | --- |
| 400 | The request body is not valid JSON. |
| 401 | The API key is missing, invalid or expired, or its account has been archived. |
| 403 | The key is read-only, or its user can't access this resource. |
| 404 | The resource doesn't exist or belongs to another account. |
| 409 | A request with the same `Idempotency-Key` is still being processed. Retry shortly. |
| 422 | The request is valid JSON but can't be processed. See `error.code`; the codes each endpoint can return are described in the endpoint's description and in the error table above.  |
| 429 | Rate limit exceeded (`rate_limited`, with `Retry-After`); more than 20 `POST /feedback` messages in an hour (`rate_limited`, with `Retry-After`: seconds until the next clock hour); or — for `POST /signature_requests/{id}/remind` — signers were reminded less than an hour ago (`remind_too_soon`, with `Retry-After`).  |
| 500 | Something went wrong on SignWith's side. It's safe to retry with the same `Idempotency-Key`. |

## Archive a template

`POST https://app.signwith.co/api/v1/templates/{id}/archive`

Needs a full-access key. Accepts `Idempotency-Key`.

Archives a template so it no longer shows among active templates. Use it when a document
version is retired. Existing signature requests are not affected. Archiving an already
archived template succeeds and returns it unchanged. The `template.archived` webhook fires only
the first time. Archived templates can't be used for new signature requests
(`422 template_archived`), and signing links of unfinished requests from them stop working.

### Path parameters

| Name | Type | Description |
| --- | --- | --- |
| `id` (required) | integer | Template ID. |

### Headers

| Name | Type | Description |
| --- | --- | --- |
| `Idempotency-Key` | string | A unique value (e.g. a UUID) that makes retries of this request safe. A successful response is stored for 24 hours and replayed for retries with the same key.  |

### Request sample

cURL:

```bash
curl -X POST https://app.signwith.co/api/v1/templates/311/archive \
  -H "Authorization: Bearer $SIGNWITH_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)"
```

Node:

```javascript
const response = await fetch('https://app.signwith.co/api/v1/templates/311/archive', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.SIGNWITH_API_KEY}`,
    'Idempotency-Key': crypto.randomUUID(),
  },
})

console.log(response.status, await response.json())
```

Python:

```python
import os
import uuid

import requests

response = requests.post(
    "https://app.signwith.co/api/v1/templates/311/archive",
    headers={
        "Authorization": f"Bearer {os.environ['SIGNWITH_API_KEY']}",
        "Idempotency-Key": str(uuid.uuid4()),
    },
)

print(response.status_code, response.json())
```

### Response 200

The archived template.

```json
{
  "object": "template",
  "id": 311,
  "name": "Residential lease",
  "external_id": "lease-v3",
  "folder": "Leasing",
  "roles": [
    "Tenant",
    "Landlord"
  ],
  "edit_url": "https://app.signwith.co/templates/311/edit",
  "created_by": {
    "id": 42,
    "email": "ada@acme.co",
    "name": "Ada Lovelace"
  },
  "archived_at": null,
  "created_at": "2026-09-20T09:12:44Z",
  "updated_at": "2026-09-21T16:03:10Z",
  "fields": [
    {
      "id": "0f9c2b7e-5d1a-4e8b-9a61-3c2e7d4f1a90",
      "name": "Tenant name",
      "type": "text",
      "role": "Tenant",
      "required": true
    },
    {
      "id": "6a3e1d42-8b7c-4f19-a0d5-2e9b4c7f8a13",
      "name": "Monthly rent",
      "type": "number",
      "role": "Tenant",
      "required": true
    },
    {
      "id": "b2d8f4a1-3c6e-4a7b-8d92-5f1e0c3a9b76",
      "name": "Start date",
      "type": "date",
      "role": "Tenant",
      "required": true
    },
    {
      "id": "91c7e3b5-2a4d-4f8e-b610-7d3a5c9e2f48",
      "name": "Pets",
      "type": "select",
      "role": "Tenant",
      "required": false,
      "options": [
        "None",
        "Cat",
        "Dog"
      ]
    },
    {
      "id": "4e8a2c6f-9b1d-4a3e-8c57-1f6d0b9e3a24",
      "name": "Tenant signature",
      "type": "signature",
      "role": "Tenant",
      "required": true
    },
    {
      "id": "c5f1a9d3-7e2b-4c8a-9f60-3b8e4d2a7c15",
      "name": "Landlord signature",
      "type": "signature",
      "role": "Landlord",
      "required": true
    }
  ],
  "documents": [
    {
      "id": 7730,
      "name": "Lease agreement",
      "url": "https://app.signwith.co/file/eyJfcmFpbHMiOnsiZGF0YSI6MTIzfX0/lease-agreement.pdf",
      "preview_image_url": "https://app.signwith.co/file/eyJfcmFpbHMiOnsiZGF0YSI6MTI0fX0/0.jpg"
    }
  ]
}
```

### Errors

| Status | Meaning |
| --- | --- |
| 401 | The API key is missing, invalid or expired, or its account has been archived. |
| 403 | The key is read-only, or its user can't access this resource. |
| 404 | The resource doesn't exist or belongs to another account. |
| 409 | A request with the same `Idempotency-Key` is still being processed. Retry shortly. |
| 429 | Rate limit exceeded (`rate_limited`, with `Retry-After`); more than 20 `POST /feedback` messages in an hour (`rate_limited`, with `Retry-After`: seconds until the next clock hour); or — for `POST /signature_requests/{id}/remind` — signers were reminded less than an hour ago (`remind_too_soon`, with `Retry-After`).  |
| 500 | Something went wrong on SignWith's side. It's safe to retry with the same `Idempotency-Key`. |

## The template object

Anchor: https://signwith.co/docs/api/templates#the-template-object

- `object` (string, required, always `template`).
- `id` (integer, required).
- `name` (string, required).
- `external_id` (string or null, required). Your own ID for the template.
- `folder` (string or null, required). Name of the folder the template is in.
- `roles` (array of strings, required). Role names in signing order.
- `edit_url` (string, required, URL). Opens the template in the SignWith editor, where the user can place or adjust fields.
- `created_by` (object or null, required). A SignWith user (a member of your team).
  - `id` (integer, required).
  - `email` (string, required, email address).
  - `name` (string or null, required). First and last name, or `null` if not set.
- `archived_at` (string (date-time) or null, required).
- `created_at` (string (date-time), required).
- `updated_at` (string (date-time), required).
- `fields` (array of objects, required). A field placed on a template's documents. Keys with no value are omitted.
  - `id` (string (uuid), required). Stable field ID.
  - `name` (string). Field name. Use it as the key in `prefill`. Omitted if the field has no name.
  - `type` (string, required). Field type, e.g. `text`, `signature`, `initials`, `date`, `number`, `checkbox`, `radio`, `select`, `multiple`, `image`, `file`, `phone`, `stamp`, `cells`.
  - `role` (string). Name of the role that fills this field.
  - `required` (boolean, required). Whether the signer must fill the field.
  - `options` (array of strings). Allowed values for `select`, `radio` and `multiple` fields.
- `documents` (array of objects, required). A document (one uploaded file) of a template.
  - `id` (integer, required).
  - `name` (string, required). File name without extension.
  - `url` (string, required, URL). Download link for the original file.
  - `preview_image_url` (string or null, URL). Image of the first page, if available.
