Documentation v1

From zero to first delivered email in minutes.

Complete API reference — authentication, /v1/send, templates, themes, error codes, and troubleshooting. Everything you need to integrate with EmailFlare.

Quickstart

#quickstart

Get to a working send in four steps — from a fresh deploy to a delivered email.

1
Deploy EmailFlare — via Docker Compose or Cloudflare Workers. See the Cloudflare Workers guide or the self-hosting docs.
2
Add a sending domain — go to the Domains page in the admin UI, enter your domain, and complete the DNS verification steps Cloudflare provides.
3
Create an API key — go to the Keys page in the admin UI, click New key, and choose a scope. Copy the key — it won't be shown again.
4
Send your first emailPOST /v1/send with your key in the Authorization: Bearer header. Start with a test key and eftest_ prefix to skip Cloudflare credentials.

Authentication

#authentication

All /v1/send requests must include a bearer token in the Authorization header.

Authorization: Bearer eflive_xxxxxxxxxxxxxxxx

Key types

⚗ test key

Prefix: eftest_. Sends go through SMTP — no Cloudflare credentials required. Set ENABLE_TEST_MODE=true to start the built-in Mailpit catcher at /mailpit/ (auth: root / ADMIN_TOKEN by default, override with MAILPIT_USER / MAILPIT_PASS).

✓ live key

Prefix: eflive_. Sends go through Cloudflare Email Sending. Requires valid CF_API_TOKEN and verified domain.

💡 Domain-scoped keys can only send from domains listed in that key's permissions. Requests with an unauthorized domain return 403.

POST /v1/send

#api-send

The single endpoint for all transactional sends. Use templateSlug / templateId for stored templates, or pass raw html / text directly.

Request fields

Field Type Required Description
from string required Sender email address. Must match a verified domain authorized for your key.
fromName string optional Display name shown in the From header, e.g. Acme Inc.
to string or string[] required Recipient address or array of up to 50 addresses. Duplicates are deduplicated.
subject string optional Overrides the template subject. Required for raw html/text sends.
templateSlug string conditional Stable slug-based template reference. Preferred for application code.
templateId string conditional Internal ID-based template reference. Use templateSlug when possible.
themeId string optional Applies a built-in colour theme to layout-based templates. See theme list below. Defaults to default.
variables object optional Key/value map for {{variable}} interpolation in subject and body.
html string conditional Raw HTML body. Used when not referencing a template.
text string conditional Plain-text body. Can be combined with html.
replyTo string optional Reply-to address for the recipient.
At least one of templateSlug, templateId, html, or text must be provided.

cURL

curl -X POST https://your-emailflare.com/v1/send \ -H "Authorization: Bearer eflive_xxx" \ -H "Content-Type: application/json" \ -d ' "from": "hello@yourdomain.com", "fromName": "Acme", "to": "alex@example.com", "templateSlug": "welcome", "themeId": "ocean", "variables": { "name": "Alex", "appName": "Acme" } '}

fetch (JavaScript)

const res = await fetch('https://your-emailflare.com/v1/send', { method: 'POST', headers: { 'Authorization': 'Bearer eflive_xxx', 'Content-Type': 'application/json', }, body: JSON.stringify({ from: 'hello@yourdomain.com', to: 'alex@example.com', templateSlug: 'welcome', themeId: 'ocean', variables: { name: 'Alex', appName: 'Acme' }, }), }); const data = await res.json();

Response (200)

{ "results": [{ "to": "alex@example.com", "cfId": "cf_msg_xxxxxxxxxxxxxxxxxx" }] }

Templates & themes

#templates

EmailFlare ships 50 layout-based templates built with React Email. Reference them by their templateSlug. Pass themeId to switch colour palettes per send — no CSS edits needed.

Available themes

default
ocean
forest
violet
slate
💡 Use the admin Playground to preview any template with any theme before sending to real recipients.

Template reference tips

  • Prefer templateSlug over templateId — slugs are stable across restores.
  • Variable names follow the {{camelCase}} convention used in the template body and subject.
  • If a variable is missing from the payload, it renders as the literal {{variableName}} placeholder.
  • themeId only applies to layout-based templates. Custom HTML templates ignore it.

Error responses

#errors
Status Meaning Common cause
401 Unauthorized Missing or invalid Authorization header.
403 Forbidden Key scope does not authorize the sender domain.
404 Not found templateSlug or templateId does not exist.
422 Validation error Missing required fields or invalid email format.
429 Rate limited Per-key send limit reached. Check X-RateLimit-Reset header.
502 All recipients failed Downstream delivery failed for every address in the request.
500 Server error Unexpected backend error — check container logs.

Rate limiting headers returned on every /v1/send response:

X-RateLimit-Limit: 100 X-RateLimit-Remaining: 97 X-RateLimit-Reset: 1746403200

Troubleshooting

#troubleshooting

401 on /v1/send

Confirm the header is exactly Authorization: Bearer <key> with no extra spaces. Verify the key is marked active on the Keys page.

403 with a domain-scoped key

The from address domain must be included in the key's allowed domains. Create a global scoped key to bypass domain restrictions while debugging.

Template not found (404)

Copy the slug exactly from the Templates page — it is case-sensitive. System templates use slugs like welcome, magic-link, otp.

Theme not applied to email

themeId only works with layout-based (built-in) templates. For custom HTML templates the field is ignored — you control the styles directly in the HTML body.

Sends succeed in test mode but fail in live mode

Test keys (eftest_) use SMTP and don't require Cloudflare credentials. Live keys use Cloudflare Email Sending — ensure CF_API_TOKEN has the correct permissions and the sender domain is verified. See the Cloudflare token guide →

To test with the built-in Mailpit catcher, set ENABLE_TEST_MODE=true — Mailpit will be available at /mailpit/ on the same port as the admin UI.

Database errors in logs

If you see "This SQL statement is not allowed on /query endpoint", upgrade to the latest EmailFlare image — this was a bug fixed in the backend send route.

📋 Always check container logs first: docker compose logs -f emailflare. Most issues are visible in the startup or request output.