POST/api/v1/projects/{project_id}/templates
Needs scope: writeIdempotency-KeyMCP tool: create_template
operationId create_template
Create a template
Creates a message template, its version 1, after checking it: it
parses, uses only what Postwind templates offer and only variables of
the render context, renders with a sample context within the render
limits, and, when the project’s auto_footer is false, each body shows
{{ unsubscribe_url }}. Each problem is in errors with its line and
column. Needs scope write.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
project_idrequired |
path | string · uuid | The project’s id |
Idempotency-Key |
header | string
1–128 characters · pattern |
A key of the client’s choosing, one per request it means to send once (a UUID will do). A repeat with the same key and the same body within 24 h creates nothing again and gets the first answer, marked Idempotent-Replayed: true. The key belongs to the API key that sent it. Only a 2xx answer is kept: after any other answer the key is free again. |
Request body
application/json · required
- CreateTemplateRequest object
-
html_bodystringrequiredThe HTML body: 1 byte to 1 MiB. Values are HTML-escaped. A message’s must show
{{ unsubscribe_url }}, itself or through the partials it includes, when the project’sauto_footeris false.example
<p>Hi!</p><a href="{{ unsubscribe_url }}">Unsubscribe</a> -
namestringrequiredUnique in the project: 1 to 128 characters, trimmed.
example
Welcome -
kindTemplateKind | nullmessage(the default) orpartial: a fragment without a subject that other templates include as{% include "name" %}.- message
- partial
-
subjectstring | nullThe subject, a template too: 1 to 998 characters, one line. A message needs one; a partial has none.
example
Welcome, {{ subscriber.attributes.first_name|default('friend') }} -
text_bodystring | nullThe text body: 1 byte to 1 MiB;
nullor left out: made from the HTML when the message is sent.
Responses
201
Version 1 of the template
| Header | Type | Description |
|---|---|---|
Idempotent-Replayed | string · enum | true when the answer is a replay of an earlier request with the same Idempotency-Key; absent otherwise. |
Location | string | The template’s URL |
- Template object · all fields required
-
created_atstring · date-timeWhen this version was saved.
-
engineTemplateEngineThe template engine.
- minijinja
-
html_bodystring -
idstring · uuidThe template’s id, the same in every version.
example
01900000-0000-7000-8000-000000000001 -
kindTemplateKindWhat a template is.
- message
- partial
-
namestringexample
Welcome -
project_idstring · uuid -
subjectstring | nullnullfor a partial. -
text_bodystring | nullnull: the text is made from the HTML when the message is sent. -
versioninteger · int32From 1, one more at each save.
≥ 1 · example
2
409
The project is deleted, or a template has the name (conflict); or a request with the same Idempotency-Key has not answered yet (idempotency_key_in_progress)
422
Invalid fields, every one in errors (validation_failed): unknown_field, required, invalid_type, invalid, and for a source, with line L, column C: in message: template_syntax, template_not_allowed, unknown_variable, template_limit, template_render, unsubscribe_link_missing; or the Idempotency-Key was used in the last 24 h for another request (idempotency_key_reused), or is not 1 to 128 visible ASCII characters (validation_failed, field Idempotency-Key)
429
The key is over its rate limit, api.rate_limit_per_minute requests a minute on this node (rate_limited)
| Header | Type | Description |
|---|---|---|
Retry-After | integer | Seconds until the key’s next request passes; rounded up. |
504
Postwind’s storage did not answer within its time limit (storage_timeout). A change the request makes may still take effect: check before repeating it. A repeat with the same Idempotency-Key never runs it twice: it is 409 idempotency_key_in_progress until the key’s 24 h end