---
title: "Update a template"
method: PUT
path: "/api/templates/{id}"
tags: ["Templates"]
---

# Update a template

`PUT /api/templates/{id}`

## Request

- Base URL: `https://core-api.getaptly.com`
- URL: `https://core-api.getaptly.com/api/templates/{id}`
- Auth: one of:
  - API key in header `x-token`
  - API key in header `Authorization`
  - HTTP bearer
- TypeScript: <https://skmtc.dev/getaptly/apis/aptly-api/docs/api/templates/:id/put.ts> (a function with typed inputs; its response is checked against the schema)

Replaces the fields of an existing template. The payload and its validation are
identical to `POST /api/templates` — including the merge-field placeholders
documented there, whose available `value`s come from
`GET /api/board/{boardId}/merge-fields`. On top of the template permission, the
acting user must have access to the library folder the template sits in. A
template that does not exist — or belongs to another company — returns 404; an
archived one returns 403, since it is the caller's own and
`GET /api/templates/{id}` still returns it.

## Path parameters

- `id` string, required

## Request body

- TemplateUpsert
  - `companyId` string: Required with a partner token; resolved from an API key or delegate token.
  - `userId` string: The acting user. Required with an API key or partner token; a delegate token supplies its own.
  - `name` string, required
  - `description` string, required
  - `templateType` 'sms' | 'email' | 'form' | 'eSignature' | 'pdf', required: Template kind. `blockDocument` is not accepted — it is an internal type for document blocks, not a user-facing template.
  - `subject` string, required: Email subject, or the file name for a `pdf` template — in which case filename-illegal characters are stripped. Merge placeholders work here too, and are shape-checked the same way.
  - `content` string, required: Template body. Merge placeholders take the form `{{value}}` or `{{value || fallback: text}}`, where `value` is an item's `value` from `GET /api/board/{boardId}/merge-fields` — for example `{{firstname}}`, `{{Locations["Rent"] || fallback: TBD}}`. They are checked for shape — an unclosed `{{`, an empty field name or a malformed bracket reference is rejected. Whether each field exists is not checked: an unknown one renders as its fallback at merge time.
  - `htmlBuilder` false: Must be `false` or omitted. HTML-builder templates keep their markup in a builder-owned `builderData` format and can only be authored in the app.
  - `builderData` object: Builder document, when one already exists.
  - `folderId` string: Library folder the template belongs to — must be an existing, non-archived folder in the company. Governs who may edit the template.
  - `aptletUuid` string: Board the template is scoped to. Must be an existing, non-archived board in the company.
  - `signature` string
  - `attachmentIds` string[]: Uploaded file ids to attach.

## Response `200`

Template updated.

- object
  - `data` Template
    - `_id` string: Template ID.
    - `companyId` string: Company the template belongs to.
    - `name` string: Template display name.
    - `templateType` 'sms' | 'email' | 'form' | 'eSignature' | 'pdf' | 'blockDocument': Template category.
    - `archived` boolean
    - `createdAt` string, date-time
    - `createdBy` string: User ID of the creator.
    - `updatedAt` string, date-time

## Other responses

- `400`: Missing companyId, or an invalid payload.
- `401`: Invalid or missing credential.
- `403`: The acting user lacks the template permission or folder access.
- `404`: Template not found.

---

[API](https://skmtc.dev/getaptly/apis/aptly-api.md) - [All operations](https://skmtc.dev/getaptly/apis/aptly-api/llms.txt) - [OpenAPI document](https://skmtc.dev/getaptly/apis/aptly-api/revisions/75c367e0b8e5?raw)
