Templates API
Manage reusable email templates stored per team.
Every request needs a bearer token and goes to a path under https://api.anypost.com/v1. See API conventions for the shared request, error, and pagination rules.
List templates
GET /v1/templates
Returns the authenticated team's templates, newest-first, with cursor pagination.
Parameters
limitintegerin query[optional]Number of items to return.
afterstringin query[optional]Opaque cursor from a previous response's
next_cursor. Do not parse.
Example request
curl https://api.anypost.com/v1/templates \
-H "Authorization: Bearer $ANYPOST_API_KEY"Response body
On success (200), the response body is:
dataarray of Templatehas_morebooleannext_cursorstringMay be null.
{
"data": [
{
"id": "template_550e8400-e29b-41d4-a716-446655440000",
"name": "Welcome email",
"subject": "Welcome to Anypost!",
"kind": "html",
"html": "string",
"text": "string",
"markdown": "string",
"has_draft": true,
"published_at": "string",
"created_at": "string",
"updated_at": "string"
}
],
"has_more": true,
"next_cursor": "string"
}Responses
| Status | Description |
|---|---|
200 | Paginated list of templates. |
401 | Missing or invalid credentials. |
Create a template
POST /v1/templates
Creates a new template for the authenticated team. name is
required and must be unique within the team. kind defaults
to html and is immutable thereafter: an html template
supplies an html body, a markdown template supplies a
markdown source. The plain-text body is always derived
server-side and is never accepted as input. The new template
starts unpublished — publish it before sending. Each team is
capped at 500 templates; exceeding it returns
422 validation_error.
Request body
Send as JSON with Content-Type: application/json.
namestring[required]subjectstring[optional]May be null.
kindstring[optional]Defaults to
htmlif omitted. Immutable once the template exists.One of:
html,markdown.htmlstring[optional]May be null.
markdownstring[optional]emailmd source. Required when
kind=markdown; rejected whenkind=html.May be null.
Example request
curl https://api.anypost.com/v1/templates \
-X POST \
-H "Authorization: Bearer $ANYPOST_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Welcome email"
}'Response body
On success (201), the response body is:
idstringnamestringIdentifier for the template, unique within the team.
subjectstringPublished default subject line.
nulluntil the template is first published.May be null.
kindstringAuthoring format.
htmltemplates author a rawhtmlbody; thetextbody is derived from it automatically.markdowntemplates store an emailmd source document inmarkdown;htmlandtextare server-rendered on save. Both kinds exposehtml/textfor read. Immutable once a template exists.One of:
html,markdown.htmlstringPublished HTML body. Up to 256 KB (262 144 bytes).
nulluntil the template is first published.May be null.
textstringPublished plain-text body, up to 64 KB (65 536 bytes). Always machine-derived — from the
htmlbody forkind=html, or rendered forkind=markdown— and never set directly.nulluntil the template is first published.May be null.
markdownstringPublished emailmd markdown source. Only set when
kind=markdown;nullforkind=htmlor until the template is first published.May be null.
has_draftbooleanWhether the template has an unpublished draft pending. Fetch the draft content from
/templates/{id}/draft.published_atstring (date-time)When the template was last published.
nullif it has never been published — such a template holds no sendable content.May be null.
created_atstring (date-time)updated_atstring (date-time)
{
"id": "template_550e8400-e29b-41d4-a716-446655440000",
"name": "Welcome email",
"subject": "Welcome to Anypost!",
"kind": "html",
"html": "string",
"text": "string",
"markdown": "string",
"has_draft": true,
"published_at": "string",
"created_at": "string",
"updated_at": "string"
}Responses
| Status | Description |
|---|---|
201 | Template created. |
401 | Missing or invalid credentials. |
413 | Request body exceeded the 5 MB gateway limit. Rejected at the transport layer before authentication or validation, so the response uses a shorter error shape than application-layer errors. The connection is closed after the response. |
422 | Request validation failed. |
Retrieve a template
GET /v1/templates/{id}
Parameters
idstringin path[required]
Example request
curl https://api.anypost.com/v1/templates/template_550e8400-e29b-41d4-a716-446655440000 \
-H "Authorization: Bearer $ANYPOST_API_KEY"Response body
On success (200), the response body is:
idstringnamestringIdentifier for the template, unique within the team.
subjectstringPublished default subject line.
nulluntil the template is first published.May be null.
kindstringAuthoring format.
htmltemplates author a rawhtmlbody; thetextbody is derived from it automatically.markdowntemplates store an emailmd source document inmarkdown;htmlandtextare server-rendered on save. Both kinds exposehtml/textfor read. Immutable once a template exists.One of:
html,markdown.htmlstringPublished HTML body. Up to 256 KB (262 144 bytes).
nulluntil the template is first published.May be null.
textstringPublished plain-text body, up to 64 KB (65 536 bytes). Always machine-derived — from the
htmlbody forkind=html, or rendered forkind=markdown— and never set directly.nulluntil the template is first published.May be null.
markdownstringPublished emailmd markdown source. Only set when
kind=markdown;nullforkind=htmlor until the template is first published.May be null.
has_draftbooleanWhether the template has an unpublished draft pending. Fetch the draft content from
/templates/{id}/draft.published_atstring (date-time)When the template was last published.
nullif it has never been published — such a template holds no sendable content.May be null.
created_atstring (date-time)updated_atstring (date-time)
{
"id": "template_550e8400-e29b-41d4-a716-446655440000",
"name": "Welcome email",
"subject": "Welcome to Anypost!",
"kind": "html",
"html": "string",
"text": "string",
"markdown": "string",
"has_draft": true,
"published_at": "string",
"created_at": "string",
"updated_at": "string"
}Responses
| Status | Description |
|---|---|
200 | The template. |
404 | Resource not found. |
Update template metadata
PATCH /v1/templates/{id}
Updates the template's name. Body content is draft-versioned
— subject, html, text, markdown (and kind) are
rejected here; use PATCH /templates/{id}/draft instead.
Parameters
idstringin path[required]
Request body
Send as JSON with Content-Type: application/json.
namestring[optional]
Example request
curl https://api.anypost.com/v1/templates/template_550e8400-e29b-41d4-a716-446655440000 \
-X PATCH \
-H "Authorization: Bearer $ANYPOST_API_KEY" \
-H "Content-Type: application/json" \
-d '{}'Response body
On success (200), the response body is:
idstringnamestringIdentifier for the template, unique within the team.
subjectstringPublished default subject line.
nulluntil the template is first published.May be null.
kindstringAuthoring format.
htmltemplates author a rawhtmlbody; thetextbody is derived from it automatically.markdowntemplates store an emailmd source document inmarkdown;htmlandtextare server-rendered on save. Both kinds exposehtml/textfor read. Immutable once a template exists.One of:
html,markdown.htmlstringPublished HTML body. Up to 256 KB (262 144 bytes).
nulluntil the template is first published.May be null.
textstringPublished plain-text body, up to 64 KB (65 536 bytes). Always machine-derived — from the
htmlbody forkind=html, or rendered forkind=markdown— and never set directly.nulluntil the template is first published.May be null.
markdownstringPublished emailmd markdown source. Only set when
kind=markdown;nullforkind=htmlor until the template is first published.May be null.
has_draftbooleanWhether the template has an unpublished draft pending. Fetch the draft content from
/templates/{id}/draft.published_atstring (date-time)When the template was last published.
nullif it has never been published — such a template holds no sendable content.May be null.
created_atstring (date-time)updated_atstring (date-time)
{
"id": "template_550e8400-e29b-41d4-a716-446655440000",
"name": "Welcome email",
"subject": "Welcome to Anypost!",
"kind": "html",
"html": "string",
"text": "string",
"markdown": "string",
"has_draft": true,
"published_at": "string",
"created_at": "string",
"updated_at": "string"
}Responses
| Status | Description |
|---|---|
200 | The updated template. |
401 | Missing or invalid credentials. |
404 | Resource not found. |
422 | Request validation failed. |
Delete a template
DELETE /v1/templates/{id}
Deletes the template and its draft, if any.
Parameters
idstringin path[required]
Example request
curl https://api.anypost.com/v1/templates/template_550e8400-e29b-41d4-a716-446655440000 \
-X DELETE \
-H "Authorization: Bearer $ANYPOST_API_KEY"Responses
| Status | Description |
|---|---|
204 | Deleted. |
404 | Resource not found. |
Duplicate a template
POST /v1/templates/{id}/duplicate
Creates a copy of the template. The copy is a brand-new template that starts unpublished, with a draft seeded from the source's current editable content — the source's draft if it has one, otherwise its published content. The copy must be published before it can be used for sending.
name is optional: when omitted the server names the copy
"<source name> (copy)" (disambiguated with (copy 2),
(copy 3), … when needed). When supplied it must be unique
within the team. The per-team 500-template cap applies —
exceeding it returns 422 validation_error.
Parameters
idstringin path[required]
Request body
Send as JSON with Content-Type: application/json.
namestring[optional]Name for the copy. Defaults to
"<source name> (copy)"when omitted.
Example request
curl https://api.anypost.com/v1/templates/template_550e8400-e29b-41d4-a716-446655440000/duplicate \
-X POST \
-H "Authorization: Bearer $ANYPOST_API_KEY" \
-H "Content-Type: application/json" \
-d '{}'Response body
On success (201), the response body is:
idstringnamestringIdentifier for the template, unique within the team.
subjectstringPublished default subject line.
nulluntil the template is first published.May be null.
kindstringAuthoring format.
htmltemplates author a rawhtmlbody; thetextbody is derived from it automatically.markdowntemplates store an emailmd source document inmarkdown;htmlandtextare server-rendered on save. Both kinds exposehtml/textfor read. Immutable once a template exists.One of:
html,markdown.htmlstringPublished HTML body. Up to 256 KB (262 144 bytes).
nulluntil the template is first published.May be null.
textstringPublished plain-text body, up to 64 KB (65 536 bytes). Always machine-derived — from the
htmlbody forkind=html, or rendered forkind=markdown— and never set directly.nulluntil the template is first published.May be null.
markdownstringPublished emailmd markdown source. Only set when
kind=markdown;nullforkind=htmlor until the template is first published.May be null.
has_draftbooleanWhether the template has an unpublished draft pending. Fetch the draft content from
/templates/{id}/draft.published_atstring (date-time)When the template was last published.
nullif it has never been published — such a template holds no sendable content.May be null.
created_atstring (date-time)updated_atstring (date-time)
{
"id": "template_550e8400-e29b-41d4-a716-446655440000",
"name": "Welcome email",
"subject": "Welcome to Anypost!",
"kind": "html",
"html": "string",
"text": "string",
"markdown": "string",
"has_draft": true,
"published_at": "string",
"created_at": "string",
"updated_at": "string"
}Responses
| Status | Description |
|---|---|
201 | The duplicated template. |
401 | Missing or invalid credentials. |
404 | Resource not found. |
422 | Request validation failed. |
Retrieve the template draft
GET /v1/templates/{id}/draft
Returns the template's unpublished draft content.
Parameters
idstringin path[required]
Example request
curl https://api.anypost.com/v1/templates/template_550e8400-e29b-41d4-a716-446655440000/draft \
-H "Authorization: Bearer $ANYPOST_API_KEY"Response body
On success (200), the response body is:
subjectstringMay be null.
htmlstringMay be null.
textstringDraft plain-text body. Always machine-derived from the draft's
html/markdown; never set directly.May be null.
markdownstringMay be null.
updated_atstring (date-time)
{
"subject": "string",
"html": "string",
"text": "string",
"markdown": "string",
"updated_at": "string"
}Responses
| Status | Description |
|---|---|
200 | The draft content. |
404 | Resource not found. |
Create or update the template draft
PATCH /v1/templates/{id}/draft
Idempotent upsert of the template's draft. Creates the draft if none exists, otherwise updates it. The published content is untouched until the draft is published. Always responds 200.
Parameters
idstringin path[required]
Request body
Send as JSON with Content-Type: application/json.
subjectstring[optional]May be null.
htmlstring[optional]May be null.
markdownstring[optional]May be null.
Example request
curl https://api.anypost.com/v1/templates/template_550e8400-e29b-41d4-a716-446655440000/draft \
-X PATCH \
-H "Authorization: Bearer $ANYPOST_API_KEY" \
-H "Content-Type: application/json" \
-d '{}'Response body
On success (200), the response body is:
subjectstringMay be null.
htmlstringMay be null.
textstringDraft plain-text body. Always machine-derived from the draft's
html/markdown; never set directly.May be null.
markdownstringMay be null.
updated_atstring (date-time)
{
"subject": "string",
"html": "string",
"text": "string",
"markdown": "string",
"updated_at": "string"
}Responses
| Status | Description |
|---|---|
200 | The saved draft. |
401 | Missing or invalid credentials. |
404 | Resource not found. |
413 | Request body exceeded the 5 MB gateway limit. Rejected at the transport layer before authentication or validation, so the response uses a shorter error shape than application-layer errors. The connection is closed after the response. |
422 | Request validation failed. |
Discard the template draft
DELETE /v1/templates/{id}/draft
Deletes the template's draft without affecting the published content. Idempotent — succeeds even when no draft exists.
Parameters
idstringin path[required]
Example request
curl https://api.anypost.com/v1/templates/template_550e8400-e29b-41d4-a716-446655440000/draft \
-X DELETE \
-H "Authorization: Bearer $ANYPOST_API_KEY"Responses
| Status | Description |
|---|---|
204 | Draft discarded. |
404 | Resource not found. |
Publish the template draft
POST /v1/templates/{id}/publish
Promotes the template's draft into the published slot. The previous published content, if any, is overwritten — not archived. The draft is consumed: the template has no pending draft immediately after publishing.
Parameters
idstringin path[required]
Example request
curl https://api.anypost.com/v1/templates/template_550e8400-e29b-41d4-a716-446655440000/publish \
-X POST \
-H "Authorization: Bearer $ANYPOST_API_KEY"Response body
On success (200), the response body is:
idstringnamestringIdentifier for the template, unique within the team.
subjectstringPublished default subject line.
nulluntil the template is first published.May be null.
kindstringAuthoring format.
htmltemplates author a rawhtmlbody; thetextbody is derived from it automatically.markdowntemplates store an emailmd source document inmarkdown;htmlandtextare server-rendered on save. Both kinds exposehtml/textfor read. Immutable once a template exists.One of:
html,markdown.htmlstringPublished HTML body. Up to 256 KB (262 144 bytes).
nulluntil the template is first published.May be null.
textstringPublished plain-text body, up to 64 KB (65 536 bytes). Always machine-derived — from the
htmlbody forkind=html, or rendered forkind=markdown— and never set directly.nulluntil the template is first published.May be null.
markdownstringPublished emailmd markdown source. Only set when
kind=markdown;nullforkind=htmlor until the template is first published.May be null.
has_draftbooleanWhether the template has an unpublished draft pending. Fetch the draft content from
/templates/{id}/draft.published_atstring (date-time)When the template was last published.
nullif it has never been published — such a template holds no sendable content.May be null.
created_atstring (date-time)updated_atstring (date-time)
{
"id": "template_550e8400-e29b-41d4-a716-446655440000",
"name": "Welcome email",
"subject": "Welcome to Anypost!",
"kind": "html",
"html": "string",
"text": "string",
"markdown": "string",
"has_draft": true,
"published_at": "string",
"created_at": "string",
"updated_at": "string"
}Responses
| Status | Description |
|---|---|
200 | The published template. |
401 | Missing or invalid credentials. |
404 | Resource not found. |
422 | Request validation failed. |