Sending
Templates API
5 endpoints under https://api.mailneo.co/api/v2. Every request carries your key in the X-API-Key header. The scopes used here: templates:read, templates:write. Each endpoint below states the one it requires. Start with the guide →
listTemplatesList templates
Cursor-paginated. Pass updated_since with the synced_through value from your previous run to fetch only what changed; you will occasionally re-see a row, so upsert by id. Deletes are not visible to updated_since. The template body is not included here — fetch a single template to get it.
/templatestemplates:readExample request
curl "https://api.mailneo.co/api/v2/templates?limit=25&order=desc&sort=updated_at" \ -H "X-API-Key: $MAILNEO_API_KEY"
Authorization
- Required scope
templates:read. A key without it is refused before the endpoint runs.- Credential
X-API-Key: mk_live_...Authorization: Bearer mk_live_...
Query parameters7
| Name | Type | Required | Notes |
|---|---|---|---|
| limit | integer | No | default 25 · 1–100 |
| cursor | string | No | max 256 chars |
| order | "asc" | "desc" | No | default "desc" |
| updated_since | string · date-time | No | ISO 8601 |
| sort | "updated_at" | "created_at" | No | default "updated_at" |
| category | string | No | max 50 chars |
| search | string | No | max 200 chars |
Response · 200
Success
data[]Each element of the array.
| Field | Type | Always present | Notes |
|---|---|---|---|
| object | "template" | Yes | |
| id | string | Yes | |
| name | string | Yes | |
| description | string · nullable | Yes | |
| subject | string | Yes | |
| category | string · nullable | Yes | |
| created_at | string | Yes | |
| updated_at | string | Yes |
meta
| Field | Type | Always present | Notes |
|---|---|---|---|
| request_id | string | Yes | |
| has_more | boolean | Yes | |
| next_cursor | string · nullable | Yes | |
| synced_through | string | No |
createTemplateCreate a template
Creates one template. name must be unique within the team — a duplicate is a 409 resource_already_exists, not a silent second copy. Templates are private to the team that owns them; there is no way to publish one, and no request field controls visibility.
/templatestemplates:writeExample request
curl -X POST "https://api.mailneo.co/api/v2/templates" \
-H "X-API-Key: $MAILNEO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "<string>",
"subject": "<string>",
"body": "<string>"
}'Authorization
- Required scope
templates:write. A key without it is refused before the endpoint runs.- Credential
X-API-Key: mk_live_...Authorization: Bearer mk_live_...- Idempotency
Idempotency-Keyis optional.
Query parameters1
| Name | Type | Required | Notes |
|---|---|---|---|
| dry_run | boolean | No | Report what this call WOULD do and commit nothing. Returns data: null and a meta.impact block. Requires the resource's :read scope in addition to the scope this endpoint declares. Must be exactly true or false. |
Header parameters1
| Name | Type | Required | Notes |
|---|---|---|---|
| Idempotency-Key | string | No | A caller-chosen unique string, at most 255 characters. Retrying with the same key replays the first response instead of repeating the work; the replay carries Idempotent-Replayed: true. Reusing a key with a different body is a 409 idempotency_key_reused. Keys are remembered for 24 hours. · max 255 chars |
Request body
Body
| Field | Type | Always present | Notes |
|---|---|---|---|
| name | string | Yes | max 100 chars |
| subject | string | Yes | max 200 chars |
| body | string | Yes | max 524288 chars |
| description | string · nullable | No | max 500 chars |
| category | string · nullable | No | max 50 chars |
Response · 200
Success
data
| Field | Type | Always present | Notes |
|---|---|---|---|
| data | object | object · nullable | Yes |
meta
| Field | Type | Always present | Notes |
|---|---|---|---|
| request_id | string | Yes | |
| dry_run | boolean | Yes | |
| impact | object | No | |
| impact.object | "impact" | Yes | |
| impact.would_create | integer | Yes | |
| impact.would_update | integer | Yes | |
| impact.would_delete | integer | Yes | |
| impact.affected_count | integer | Yes | |
| impact.affected_ids | string[] | Yes | |
| impact.quota | object · nullable | Yes | |
| impact.quota.kind | string | Yes | |
| impact.quota.would_consume | integer | Yes | |
| impact.quota.limit | integer · nullable | Yes | |
| impact.quota.current | integer | Yes |
Response · 201
Created
data
| Field | Type | Always present | Notes |
|---|---|---|---|
| data | object | object · nullable | Yes |
meta
| Field | Type | Always present | Notes |
|---|---|---|---|
| request_id | string | Yes | |
| dry_run | boolean | Yes | |
| impact | object | No | |
| impact.object | "impact" | Yes | |
| impact.would_create | integer | Yes | |
| impact.would_update | integer | Yes | |
| impact.would_delete | integer | Yes | |
| impact.affected_count | integer | Yes | |
| impact.affected_ids | string[] | Yes | |
| impact.quota | object · nullable | Yes | |
| impact.quota.kind | string | Yes | |
| impact.quota.would_consume | integer | Yes | |
| impact.quota.limit | integer · nullable | Yes | |
| impact.quota.current | integer | Yes |
getTemplateRetrieve a template
Returns the full template, including the body omitted from the list response.
/templates/{templateId}templates:readExample request
curl "https://api.mailneo.co/api/v2/templates/{templateId}" \
-H "X-API-Key: $MAILNEO_API_KEY"Authorization
- Required scope
templates:read. A key without it is refused before the endpoint runs.- Credential
X-API-Key: mk_live_...Authorization: Bearer mk_live_...
Path parameters1
| Name | Type | Required | Notes |
|---|---|---|---|
| templateId | string | Yes | max 64 chars |
Response · 200
Success
data
| Field | Type | Always present | Notes |
|---|---|---|---|
| object | "template" | Yes | |
| id | string | Yes | |
| name | string | Yes | |
| description | string · nullable | Yes | |
| subject | string | Yes | |
| category | string · nullable | Yes | |
| created_at | string | Yes | |
| updated_at | string | Yes | |
| body | string | Yes |
meta
| Field | Type | Always present | Notes |
|---|---|---|---|
| request_id | string | Yes |
updateTemplateUpdate a template
Merge-patch: fields you omit are left alone, and null clears description or category. name, subject and body cannot be cleared — they are required columns — so sending null for one is a 400. Renaming to a name another template in the team already uses is a 409.
/templates/{templateId}templates:writeExample request
curl -X PATCH "https://api.mailneo.co/api/v2/templates/{templateId}" \
-H "X-API-Key: $MAILNEO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "<string>",
"subject": "<string>",
"body": "<string>",
"description": "<string>",
"category": "<string>"
}'Authorization
- Required scope
templates:write. A key without it is refused before the endpoint runs.- Credential
X-API-Key: mk_live_...Authorization: Bearer mk_live_...- Idempotency
Idempotency-Keyis optional.
Path parameters1
| Name | Type | Required | Notes |
|---|---|---|---|
| templateId | string | Yes | max 64 chars |
Query parameters1
| Name | Type | Required | Notes |
|---|---|---|---|
| dry_run | boolean | No | Report what this call WOULD do and commit nothing. Returns data: null and a meta.impact block. Requires the resource's :read scope in addition to the scope this endpoint declares. Must be exactly true or false. |
Header parameters1
| Name | Type | Required | Notes |
|---|---|---|---|
| Idempotency-Key | string | No | A caller-chosen unique string, at most 255 characters. Retrying with the same key replays the first response instead of repeating the work; the replay carries Idempotent-Replayed: true. Reusing a key with a different body is a 409 idempotency_key_reused. Keys are remembered for 24 hours. · max 255 chars |
Request body
Body
| Field | Type | Always present | Notes |
|---|---|---|---|
| name | string | No | max 100 chars |
| subject | string | No | max 200 chars |
| body | string | No | max 524288 chars |
| description | string · nullable | No | max 500 chars |
| category | string · nullable | No | max 50 chars |
Response · 200
Success
data
| Field | Type | Always present | Notes |
|---|---|---|---|
| data | object | object · nullable | Yes |
meta
| Field | Type | Always present | Notes |
|---|---|---|---|
| request_id | string | Yes | |
| dry_run | boolean | Yes | |
| impact | object | No | |
| impact.object | "impact" | Yes | |
| impact.would_create | integer | Yes | |
| impact.would_update | integer | Yes | |
| impact.would_delete | integer | Yes | |
| impact.affected_count | integer | Yes | |
| impact.affected_ids | string[] | Yes | |
| impact.quota | object · nullable | Yes | |
| impact.quota.kind | string | Yes | |
| impact.quota.would_consume | integer | Yes | |
| impact.quota.limit | integer · nullable | Yes | |
| impact.quota.current | integer | Yes |
deleteTemplateDelete a template
Permanent, and there is no undo — call with ?dry_run=true first. Campaign steps that were built from this template keep their own copy of the subject and body and are unaffected. An automation "send email" step that references the template by id is NOT protected by a foreign key: deleting the template leaves that step with a dangling reference, and it will fail when the automation next runs. Check your automations before deleting a template they use.
/templates/{templateId}templates:writeExample request
curl -X DELETE "https://api.mailneo.co/api/v2/templates/{templateId}" \
-H "X-API-Key: $MAILNEO_API_KEY"Authorization
- Required scope
templates:write. A key without it is refused before the endpoint runs.- Credential
X-API-Key: mk_live_...Authorization: Bearer mk_live_...
Path parameters1
| Name | Type | Required | Notes |
|---|---|---|---|
| templateId | string | Yes | max 64 chars |
Query parameters1
| Name | Type | Required | Notes |
|---|---|---|---|
| dry_run | boolean | No | Report what this call WOULD do and commit nothing. Returns data: null and a meta.impact block. Requires the resource's :read scope in addition to the scope this endpoint declares. Must be exactly true or false. |
Response · 200
Success
dataMay be null.
| Field | Type | Always present | Notes |
|---|---|---|---|
| object | "template" | Yes | |
| id | string | Yes | |
| deleted | true | Yes |
meta
| Field | Type | Always present | Notes |
|---|---|---|---|
| request_id | string | Yes | |
| dry_run | boolean | Yes | |
| impact | object | No | |
| impact.object | "impact" | Yes | |
| impact.would_create | integer | Yes | |
| impact.would_update | integer | Yes | |
| impact.would_delete | integer | Yes | |
| impact.affected_count | integer | Yes | |
| impact.affected_ids | string[] | Yes | |
| impact.quota | object · nullable | Yes | |
| impact.quota.kind | string | Yes | |
| impact.quota.would_consume | integer | Yes | |
| impact.quota.limit | integer · nullable | Yes | |
| impact.quota.current | integer | Yes |