API-first transactional sends with dashboard-saved message templates.
Send one-off transactional emails (password resets, OTPs, receipts, order confirmations, and more) via the REST API. Design reusable email templates in the dashboard and integrate them into your existing application or workflow.
Your contacts remain in your own system — only the template ID and merge variables are required for each send request.
Email templates must be created and managed in Transactional → Email Templates. Once a template is created, send emails using POST /api/v1/transactional/send by providing the template ID and required parameters.
key
Authentication
check_circleTransport: Authorization: Bearer <api_key> or X-Api-Key.
check_circleAPI key permission: transactional.
check_circlePlan: the tenant’s active plan must have transactional_enabled.
Common errors:
Error Response
{ "status": "error", "reason": "Your current plan does not include Transactional Email." }
Error Response
{ "status": "error", "reason": "API key does not have transactional permission." }
All tenant routes are under /api/v1/transactional and use the api-v1-transactional limiter (60 requests/min per API key). Failed validation on these routes returns HTTP 422 with { "status": "error", "reason": "<first error>" }.
article
Templates
Open Transactional → Email Templates (/transactional/message-types; /transactional/messages redirects there). Each row is a transactional_messages record used for send content and analytics grouping.
Dashboard save stores:
check_circlename (required)
check_circlesubject (required, max 998 characters) — merge tokens allowed
check_circlebody_html (required) — HTML template; merge tokens allowed
check_circlebody_text (optional) — if omitted, the dashboard derives plaintext from the HTML
check_circleenabled — disabled templates cannot be sent
check_circletrack_opens / track_clicks — dashboard-created templates set both to true
check_circlesource — dashboard creates manual
check_circleslug — dashboard creates null; send and list identify templates by numeric id
check_circlerequired_variables — dashboard create stores []. The send API still enforces this list when it is non-empty
A template is sendable only when subject is non-empty and the HTML has visible text or an <img> tag. Otherwise send returns HTTP 422: This message has no saved template.
GET /api/v1/transactional/messages returns metadata including subject. It does not return body_html or body_text.
article
Send
POST /api/v1/transactional/send
Queues delivery through a mailbox you own. Subject, HTML, and optional plaintext are taken from the saved template after {{token}} substitution.
Required
Field
Type
Rules
transactional_message_id
integer
Must exist for this tenant, be enabled, and have a sendable template
to.email
string
Recipient address. Not stored as a contact
from.email
string
Must match a mailbox on the tenant (case-insensitive)
Optional
Field
Type
Rules
to.name
string
Display name on the recipient
from.name
string
If omitted, the mailbox display_name is used
variables
object
Key/value map for {{token}} in subject, HTML, and plaintext
reply_to
string
Valid email, max 255
headers
object
Only names starting with X- / x- are kept; others are dropped silently. Values max 2000 characters
idempotency_key
string
Max 191. Client-chosen unique key per logical send (e.g. order-42-welcome or a UUID). Same tenant + key + same payload returns the original outbound (idempotent_replay: true). Same key with a different payload returns HTTP 409. Omit the field to always create a new send. Never use a human description as the key.
Prohibited (HTTP 422): subject, message, text. Content cannot be overridden on the send call.
Statuses
check_circle202 — new send queued (idempotent_replay: false)
check_circle200 — existing send returned for the same idempotency_key and matching payload (idempotent_replay: true); the outbound job is not dispatched again
check_circle409 — idempotency_key was already used for a different send (different template, recipient, from, reply-to, variables, or X-* headers)
data.status reflects queue/SMTP acceptance (queued → sending → sent, or failed / bounced). Inbox confirmation is separate: check delivered_at and delivery_events (populated by provider delivery webhooks).
Creates a typed registry entry. Duplicate key returns HTTP 409 unless overwrite=true (then HTTP 200). New keys return HTTP 201. source on the record is api.
Matched delivered events set outbound_emails.delivered_at once; deferred updates last_deferred_at. Unknown message ids are logged and ignored. These fields and a summarized delivery_events list are exposed on GET /api/v1/transactional/sends/{id} and on the send response from POST /send.
article
Admin analytics
Admins can open /admin/transactional/analytics for cross-tenant funnel, tenant breakdown, templates, recent sends, and CSV/JSON export.
build
MCP tools
On the MailAPI MCP server (transactional permission + plan entitlement):
Same validation as REST send. Also requires write. Args: transactional_message_id, to_email, from_email, optional to_name, from_name, variables, reply_to, headers, idempotency_key (unique per logical send; omit to always create a new outbound). Returns idempotent_replay. Same key with a different payload returns an error. Does not accept attachments. Do not pass subject, message, or text
article
SMTP vs REST
The SMTP submission gateway authenticates with the same API key but sends the MIME subject and body as submitted. It does not load dashboard templates. Use REST when you want template IDs and variables; use SMTP when the client already builds the full message.