---
title: "Save or update a template"
method: POST
path: "/api/templates"
tags: ["Templates"]
---

# Save or update a template

`POST /api/templates`

## Request

- Base URL: `https://morfee.furo.solutions`
- URL: `https://morfee.furo.solutions/api/templates`
- Auth: one of:
  - API key in header `X-Api-Key`
  - HTTP bearer

Send `id` to update, leave it out for a new one. A new one needs room in the plan; an update never does, otherwise you would be stuck with what you have the moment you hit the ceiling.

Needs a key scoped `write` or `full`.

## Request body

- SaveTemplate: What POST /api/templates takes. The template is trial-rendered against `sample` before anything is stored: a template that does not render is not saved, and the 400 says why.
  - `hbs` string, required: The template that gets rendered. Required.
  - `bindings` object[], required: What the builder needs to open this template again. Send [] if you have none: the handler requires the field to be a list, so leaving it out is a 400.
  - `id` string: Send it to update an existing template. An id belonging to another organization is a 400.
  - `name` string: Falls back to the id.
  - `sample` unknown
  - `source` string: Your original HTML, kept untouched.
  - `folderId` string, nullable: Put it on this shelf. null takes it out of every folder. Leave the field out entirely and it stays where it is, which is what the builder does.
  - `replaceLogic` boolean: Only needed to overwrite a template that has logic in it with something that has none. Refused with 409 would_drop_logic without it, because that is nearly always a design landing on top of a working template rather than a new version of it.

## Response `200`

Saved.

- object
  - `ok` boolean
  - `template` TemplateMeta: A template as the list hands it over: everything except the template body itself.
    - `id` string, required: The id to render with. Lower case, digits and dashes.
    - `name` string, required
    - `createdAt` string, date-time
    - `updatedAt` string, date-time
    - `createdBy` string, nullable: The email address that saved it first.
    - `folderId` string, nullable: null means it is in no folder.
    - `bindingCount` integer: How many fields are pointed at.
    - `listCount` integer: How many of those are lists.
    - `byHand` boolean: True when the template has logic in it but no bindings: written directly rather than built by pointing at a design. The builder cannot rebuild such a template and opens it read only.
    - `sizeKb` integer

## Other responses

- `400`: Something in the request is wrong, and the message says what.
- `401`: No key, an unknown key or a revoked one.
- `402`: The ceiling of the plan, or a plan whose end date has passed. The message says which, and the hint points at /billing.
- `403`: The key is real and the organization is right, but the scope on it does not cover this. The message names the scope the key has, what that scope may do, and how to get a wider one, because the thing reading it is usually the thing that has to act on it.

---

[API](https://skmtc.dev/furo/apis/morfee.md) · [All operations](https://skmtc.dev/furo/apis/morfee/llms.txt) · [OpenAPI document](https://skmtc.dev/furo/apis/morfee/revisions/83f95f89653f?raw)
