Skip to content

REST API overview

The SDKs cover most needs, but everything they do is plain HTTPS + JSON you can call from any language. The full, generated reference for every endpoint is in the REST API reference.

https://api.frontmail.dev

All endpoints are versioned under /v1. The EmailJS-compatible aliases POST /api/v1.0/email/send and POST /api/v1.0/email/send-form behave like /v1/send and /v1/send-form.

Key Send as Allowed endpoints
Public key pk_… X-Frontmail-Public-Key: pk_… header, or user_id in the body POST /v1/send, POST /v1/send-form, POST /v1/uploads, GET /v1/messages/:id with the X-Frontmail-Status-Token header
Private key sk_… Authorization: Bearer sk_… header, or accessToken in the body – from servers only (a request with an Origin header gets 403 private_key_in_browser) all endpoints

Public-key requests without Origin and Referer (servers, curl, native apps) need Allow mobile apps; otherwise they get 403 origin_not_allowed.

GET /v1/health and GET /v1/public-config need no key. See Public and private keys for the security model.

Method & path Purpose
POST /v1/send Send one email from a template (JSON)
POST /v1/send-form Send one email from multipart/form-data (files become attachments)
POST /v1/send-batch Send up to 100 emails (private key)
POST /v1/uploads Get a presigned URL for a large attachment
GET /v1/messages/:id Status and events of a message
GET /v1/history Paginated message history (private key)
GET /v1/templates, GET /v1/templates/:id Templates with param schemas (private key)
GET /v1/public-config Public configuration, no key needed – Frontmail’s mobile Turnstile site key and page URL, used by @frontmail/react-native (cacheable for 1 hour)
GET /v1/health Health check
Header Direction Meaning
Idempotency-Key request Deduplicates retries for 24 h (≤ 255 chars) – see Retries and idempotency
X-Frontmail-Client request SDK name and version, e.g. @frontmail/browser/0.3.1 (optional, helps support)
X-Frontmail-Status-Token request status_token from the send response, for GET /v1/messages/:id with a public key. The older ?token= query parameter still works but ends up in access logs – prefer the header
Retry-After response Seconds to wait, on 429
Terminal window
curl https://api.frontmail.dev/v1/send \
-H 'Content-Type: application/json' \
-H 'X-Frontmail-Public-Key: pk_4f2a…' \
-H 'Origin: https://example.com' \
-H 'Idempotency-Key: 5f0c6f8e-1d2a-4c55-9f6b-2d7c1f4a9e10' \
-d '{
"service_id": "svc_01J9…",
"template_id": "tpl_01J9…",
"template_params": { "name": "Jana", "email": "jana@example.com", "message": "Hi!" },
"turnstile_token": "0.AbCd…"
}'
{ "message_id": "msg_01J9Z3K7Q2", "status": "queued", "status_token": "st_…" }

status is queued or held (out of credits in hold mode). Both mean the message was accepted – the response code is 202.

All errors share one shape:

{ "error": { "code": "origin_not_allowed", "message": "…", "docs_url": "https://docs.frontmail.dev/reference/errors/#origin-not-allowed", "details": {} } }

Possible statuses: 400, 401, 402 (only in reject mode), 403, 404, 409, 413, 422, 429, 451, 5xx. Every code is explained in Error codes.

  • Params: 256 kB of JSON per message; strings 50,000 characters unless the schema says otherwise.
  • Batch: 100 messages per request.
  • Attachments: per plan, see Plans.
  • Requests per second: per plan, see Rate limits.