Every API here is available over the APIs.io API and to AI agents over MCP.
openapi: 3.2.0
info:
title: Sendraven Ai Templates API
version: 1.0.0
description: 'Operations tagged Templates across 2 of this provider''s published API definitions: sendraven-ai-api-openapi.json, sendraven-ai-openapi.json. Each path carries the servers of the definition it was published in.'
servers:
- url: https://api.sendraven.ai
security:
- bearerAuth: []
tags:
- name: Templates
paths:
/v1/templates:
get:
summary: List templates and their required variables
description: 'Every template, sorted by name, each with variables: the placeholder names a render or send must supply. Not paged (cap 500).'
x-required-scope: templates:read
responses:
'200':
description: Templates.
content:
application/json:
schema:
type: object
required:
- object
- data
- has_more
- next_cursor
properties:
object:
type: string
enum:
- list
data:
type: array
items:
$ref: '#/components/schemas/Template'
has_more:
type: boolean
description: 'Not paged: true only when the list hit its cap, meaning there is more than this endpoint can return.'
next_cursor:
type:
- string
- 'null'
description: Always null; this list is not paged.
'401':
description: 'unauthorized: no Bearer token, or the key or token is invalid, revoked or expired.'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'403':
description: 'forbidden: the key lacks the templates:read scope. The message names it.'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'429':
description: 'rate_limited: more requests than the per-key rate (600 a minute by default). Wait the seconds in the Retry-After header and retry.'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'503':
description: 'service_unavailable: the API is under heavy load and could not get a database connection in time. Usually nothing was done; a send that was already under way may have been, so check GET /v1/emails before retrying one. Wait the seconds in the Retry-After header.'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
tags:
- Templates
operationId: getV1Templates
x-operation-id-source: derived
post:
summary: Create or update a template
description: 'Creates the template, or updates the one with this slug (201 new, 200 updated); variables is recomputed from the copy either way. On an update name, subject and html are replaced; text is replaced when given as a string, kept when left out, and removed when null; "" is refused with 422 (send null). Placeholders are {{name}}: letters, digits, underscores and dots (a dot is part of the name, not a path). Values are HTML-escaped into html and go into subject and text as given. Changing a template changes every later send that uses it, including automation steps already scheduled; a new placeholder makes those steps fail unless enrolments carry a value.'
x-required-scope: templates:write
requestBody:
required: true
content:
application/json:
schema:
type: object
required:
- slug
- name
- subject
- html
properties:
slug:
type: string
pattern: ^[a-z0-9-]+$
description: Lower-case letters, digits and hyphens.
name:
type: string
minLength: 1
maxLength: 200
subject:
type: string
minLength: 1
maxLength: 998
description: May contain placeholders.
html:
type: string
minLength: 1
description: May contain placeholders.
text:
type:
- string
- 'null'
minLength: 1
description: Plain-text body. May contain placeholders. On an update, left out keeps the stored one and null removes it. An empty string is refused.
responses:
'200':
description: 'Updated: the stored template, with updated_at set.'
content:
application/json:
schema:
$ref: '#/components/schemas/Template'
'201':
description: Created.
content:
application/json:
schema:
$ref: '#/components/schemas/Template'
'400':
description: 'invalid_json: the request body is not valid JSON.'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'401':
description: 'unauthorized: no Bearer token, or the key or token is invalid, revoked or expired.'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'403':
description: 'forbidden: the key lacks the templates:write scope. The message names it.'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'409':
description: 'idempotency_in_progress: a request with the same Idempotency-Key was still running on this path after waiting up to 8 seconds for it (a retry that finds it finished receives its response instead). Retry after a short wait.'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'413':
description: 'payload_too_large: the body is larger than this endpoint accepts (5 MB unless stated).'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'422':
description: 'invalid_request: text is an empty string (the message says to send null to remove the text body), or the body failed validation (details lists each field). Also idempotency_key_reused: this Idempotency-Key was already used on this path with a different request body (checked right after the scope, so a credential without the scope gets 403 instead, and answered at once even while the first request is still running). Do not retry; send the new request under a new key.'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'429':
description: 'rate_limited: more requests than the per-key rate (600 a minute by default). Wait the seconds in the Retry-After header and retry.'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'503':
description: 'service_unavailable: the API is under heavy load and could not get a database connection in time. Usually nothing was done; a send that was already under way may have been, so check GET /v1/emails before retrying one. Wait the seconds in the Retry-After header.'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
parameters:
- name: Idempotency-Key
in: header
schema:
type: string
description: 'Replaying the same key on the same path in this workspace within 24 hours returns the stored response, with an Idempotent-Replay: true header, instead of acting again. Only successful responses are stored, so a failed request can be fixed and retried under the same key. The body is compared (key order ignored): the same key with a different body is 422 idempotency_key_reused, so use a new key for every new request. Use an unguessable value such as a UUID.'
tags:
- Templates
operationId: postV1Templates
x-operation-id-source: derived
servers:
- url: https://api.sendraven.ai
/v1/templates/{slug}:
get:
summary: Retrieve a template
description: One template by slug, with its variables.
x-required-scope: templates:read
parameters:
- name: slug
in: path
required: true
schema:
type: string
description: The template's slug. Templates are addressed by slug, never by id.
responses:
'200':
description: The template.
content:
application/json:
schema:
$ref: '#/components/schemas/Template'
'401':
description: 'unauthorized: no Bearer token, or the key or token is invalid, revoked or expired.'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'403':
description: 'forbidden: the key lacks the templates:read scope. The message names it.'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'404':
description: 'not_found: no template with this slug in the workspace.'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'429':
description: 'rate_limited: more requests than the per-key rate (600 a minute by default). Wait the seconds in the Retry-After header and retry.'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'503':
description: 'service_unavailable: the API is under heavy load and could not get a database connection in time. Usually nothing was done; a send that was already under way may have been, so check GET /v1/emails before retrying one. Wait the seconds in the Retry-After header.'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
tags:
- Templates
operationId: getV1TemplatesBySlug
x-operation-id-source: derived
delete:
summary: Delete a template
description: Deletes the template. Refused with 409 while an active or paused automation has a step using it (the message lists them), so a live sequence cannot lose a step's body; delete those automations or set them to draft first. Campaigns carry their own html and never block it. Once deleted, a later send naming it is refused, and a draft automation step naming it fails each enrolment that reaches it after the automation is activated.
x-required-scope: templates:write
parameters:
- name: slug
in: path
required: true
schema:
type: string
description: The template's slug. Templates are addressed by slug, never by id.
responses:
'200':
description: Deleted.
content:
application/json:
schema:
type: object
required:
- slug
- deleted
properties:
slug:
type: string
deleted:
type: boolean
enum:
- true
'401':
description: 'unauthorized: no Bearer token, or the key or token is invalid, revoked or expired.'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'403':
description: 'forbidden: the key lacks the templates:write scope. The message names it.'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'404':
description: 'not_found: no template with this slug in the workspace, or it was deleted by another request meanwhile.'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'409':
description: 'invalid_state: an active or paused automation still uses the template; the message names each one. Nothing was deleted. Retrying will not help until those automations are deleted or set to draft.'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'429':
description: 'rate_limited: more requests than the per-key rate (600 a minute by default). Wait the seconds in the Retry-After header and retry.'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'503':
description: 'service_unavailable: the API is under heavy load and could not get a database connection in time. Usually nothing was done; a send that was already under way may have been, so check GET /v1/emails before retrying one. Wait the seconds in the Retry-After header.'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
tags:
- Templates
operationId: deleteV1TemplatesBySlug
x-operation-id-source: derived
servers:
- url: https://api.sendraven.ai
/v1/templates/{slug}/render:
post:
summary: Render a template without sending
description: 'Check the copy reads correctly before mailing a real person. Follows the send rules exactly: values are HTML-escaped into html, and every name in the template''s variables must have a value. An empty string counts as a value; a missing key or null does not. Nothing is sent or stored.'
x-required-scope: templates:read
parameters:
- name: slug
in: path
required: true
schema:
type: string
description: The template's slug. Templates are addressed by slug, never by id.
- name: Idempotency-Key
in: header
schema:
type: string
description: 'Replaying the same key on the same path in this workspace within 24 hours returns the stored response, with an Idempotent-Replay: true header, instead of acting again. Only successful responses are stored, so a failed request can be fixed and retried under the same key. The body is compared (key order ignored): the same key with a different body is 422 idempotency_key_reused, so use a new key for every new request. Use an unguessable value such as a UUID.'
requestBody:
required: false
content:
application/json:
schema:
type: object
properties:
variables:
type: object
default: {}
additionalProperties:
oneOf:
- type: string
- type: number
- type: boolean
- type: 'null'
description: Placeholder name to value. Numbers and booleans become their string form; null counts as no value; an object or array is refused. Names the template does not use are ignored.
responses:
'200':
description: The rendered subject and bodies.
content:
application/json:
schema:
$ref: '#/components/schemas/TemplateRenderResult'
'400':
description: 'invalid_json: the request body is not valid JSON.'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'401':
description: 'unauthorized: no Bearer token, or the key or token is invalid, revoked or expired.'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'403':
description: 'forbidden: the key lacks the templates:read scope. The message names it.'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'404':
description: 'not_found: no template with this slug in the workspace.'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'409':
description: 'idempotency_in_progress: a request with the same Idempotency-Key was still running on this path after waiting up to 8 seconds for it (a retry that finds it finished receives its response instead). Retry after a short wait.'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'413':
description: 'payload_too_large: the body is larger than this endpoint accepts (5 MB unless stated).'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'422':
description: 'missing_variables: one or more of the template''s variables has no value; the error carries missing, the names. invalid_request: variables is not an object, or a value is an object or array (the message names it, e.g. variables.plan). Also idempotency_key_reused: this Idempotency-Key was already used on this path with a different request body (checked right after the scope, so a credential without the scope gets 403 instead, and answered at once even while the first request is still running). Do not retry; send the new request under a new key.'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'429':
description: 'rate_limited: more requests than the per-key rate (600 a minute by default). Wait the seconds in the Retry-After header and retry.'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'503':
description: 'service_unavailable: the API is under heavy load and could not get a database connection in time. Usually nothing was done; a send that was already under way may have been, so check GET /v1/emails before retrying one. Wait the seconds in the Retry-After header.'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
tags:
- Templates
operationId: postV1TemplatesBySlugRender
x-operation-id-source: derived
servers:
- url: https://api.sendraven.ai
/v1/templates/{slug}/duplicate:
post:
summary: Duplicate a template
description: Copies subject, html and text under a new slug, as an independent template with its own id and created_at. The source is looked up before the body is validated.
x-required-scope: templates:write
parameters:
- name: slug
in: path
required: true
schema:
type: string
description: The slug of the template to copy.
- name: Idempotency-Key
in: header
schema:
type: string
description: 'Replaying the same key on the same path in this workspace within 24 hours returns the stored response, with an Idempotent-Replay: true header, instead of acting again. Only successful responses are stored, so a failed request can be fixed and retried under the same key. The body is compared (key order ignored): the same key with a different body is 422 idempotency_key_reused, so use a new key for every new request. Use an unguessable value such as a UUID.'
requestBody:
required: true
content:
application/json:
schema:
type: object
required:
- slug
properties:
slug:
type: string
pattern: ^[a-z0-9-]+$
description: The new template's slug; must be unused in the workspace.
name:
type: string
minLength: 1
maxLength: 200
description: Trimmed, then 1 to 200 characters; an empty or whitespace-only name is 422. Left out, it is the source's name followed by " copy".
responses:
'201':
description: The copy.
content:
application/json:
schema:
$ref: '#/components/schemas/Template'
'400':
description: 'invalid_json: the request body is not valid JSON.'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'401':
description: 'unauthorized: no Bearer token, or the key or token is invalid, revoked or expired.'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'403':
description: 'forbidden: the key lacks the templates:write scope. The message names it.'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'404':
description: 'not_found: no template with the source slug in the workspace.'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'409':
description: 'conflict: a template with the new slug already exists. Pick another slug; retrying the same one will not help. Also idempotency_in_progress: a request with the same Idempotency-Key was still running on this path after waiting up to 8 seconds for it (a retry that finds it finished receives its response instead). Retry after a short wait.'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'413':
description: 'payload_too_large: the body is larger than this endpoint accepts (5 MB unless stated).'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'422':
description: 'invalid_request: slug missing or not lower-case letters, digits and hyphens, or name empty (after trimming) or over 200 characters. The message names each field and details lists them. Also idempotency_key_reused: this Idempotency-Key was already used on this path with a different request body (checked right after the scope, so a credential without the scope gets 403 instead, and answered at once even while the first request is still running). Do not retry; send the new request under a new key.'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'429':
description: 'rate_limited: more requests than the per-key rate (600 a minute by default). Wait the seconds in the Retry-After header and retry.'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'503':
description: 'service_unavailable: the API is under heavy load and could not get a database connection in time. Usually nothing was done; a send that was already under way may have been, so check GET /v1/emails before retrying one. Wait the seconds in the Retry-After header.'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
tags:
- Templates
operationId: postV1TemplatesBySlugDuplicate
x-operation-id-source: derived
servers:
- url: https://api.sendraven.ai
components:
schemas:
Error:
type: object
required:
- error
properties:
error:
type: object
required:
- type
- message
properties:
type:
type: string
description: 'Stable and safe to branch on, and the same status on every route: invalid_request (422), invalid_json (400), payload_too_large (413), unauthorized (401), forbidden (403), not_found (404), conflict (409, an identifier already taken), invalid_state (409, the resource''s current state does not allow this), plan_limit_reached (402), payment_method_required (402), billing_past_due (402), budget_exceeded (402), no_verified_identity (422), missing_variables (422), unknown_topic (422), idempotency_in_progress (409), idempotency_key_reused (422), approval_in_progress (409), rate_limited (429), daily_limit (429), recipient_not_allowed (403), invalid_schedule (422), warmup_limit (422), no_postal_address (422), workspace_suspended (422), gone (410), ses_error (502), internal_error (500), service_unavailable (503).'
message:
type: string
description: For people; may change.
details:
type: array
items:
type: object
additionalProperties: true
description: 'On many 422 invalid_request answers: one entry per field that failed validation.'
missing:
type: array
items:
type: string
description: 'Only on missing_variables, and always there: the names of the template variables that were not supplied.'
TemplateRenderResult:
type: object
required:
- subject
- html
- text
properties:
subject:
type: string
description: Values substituted as given (the subject is not HTML).
html:
type: string
description: Values HTML-escaped on substitution.
text:
type:
- string
- 'null'
description: null when the template has no text body. Values substituted as given.
Template:
type: object
description: A template. Every field is always present, null when it has no value.
required:
- id
- slug
- name
- subject
- html
- text
- variables
- created_at
- updated_at
properties:
id:
type: string
format: uuid
description: Not used by any endpoint; templates are addressed by slug.
slug:
type: string
pattern: ^[a-z0-9-]+$
description: Unique within the workspace.
name:
type: string
subject:
type: string
description: The subject line, with {{name}} placeholders.
html:
type: string
description: The HTML body, with placeholders. Values substituted here are HTML-escaped.
text:
type:
- string
- 'null'
description: The plain-text body; null when the template has none. An empty string counts as no text body when rendering.
variables:
type: array
items:
type: string
description: Every placeholder name in the subject and both bodies, sorted, without duplicates. All are required to render or send.
created_at:
type: string
format: date-time
updated_at:
type:
- string
- 'null'
format: date-time
description: null until the template is first updated.
securitySchemes:
bearerAuth:
type: http
scheme: bearer
description: An API key of the form sk_live_…, created at /developers, or an OAuth access token (srv_oat_…). An OAuth token carries its grant's scopes but none of an API key's guardrails, and cannot decide approvals.
x-refined-from:
- sendraven-ai-api-openapi.json
- sendraven-ai-openapi.json