API reference
Loading....Authentication
Authenticate every request with your secret API key. Keys are created per app in your dashboard and carry that app's permissions. Never expose a secret key in client-side code.
x-api-key: lum_sk_your_api_key_herex-api-key for integrations and onboarding. The API also accepts Authorization: Bearer ... for compatibility. Missing or invalid keys return 401.Errors
Lumora uses conventional HTTP status codes. Error bodies include a stable error code and an optional message.
{
"error": "sender_domain_not_verified",
"message": "Sender domain is not verified or does not belong to this tenant"
}Send email
Send a transactional email. The from.email domain must be verified and configured with DKIM in your portal.
| name | type | description |
|---|---|---|
| from | object | Sender object: { email, name }. If omitted, uses app default sender. |
| to | string[] | Recipients. Required. |
| subject | string | Email subject. Required. |
| html | string | Inline HTML body. Optional if template sending exists. |
| text | string | Plain text body. Optional. |
| variables | object | First-class shared template variables. Available as {{token}} across subject, html, and text. |
| perRecipientVariables | object | Optional object keyed by recipient email. Each entry overrides shared variables for that recipient only. |
| metadata | object | Optional legacy metadata. metadata.variables and top-level metadata keys still render as {{token}} placeholders for backward compatibility. |
Rendering precedence is variables, then legacy metadata, then recipient-specific overrides from perRecipientVariables or inline recipient variables. System tokens {{name}}, {{email}}, and {{unsubscribe_url}} always render per recipient.
curl /v1/email/send \
-H "x-api-key: lum_sk_..." \
-H "Content-Type: application/json" \
-d '{
"from": { "email": "hello@mail.acme.com", "name": "Acme" },
"to": [
{
"email": "jordan@globex.com",
"name": "Jordan",
"variables": { "cta_label": "Confirm account" }
},
{
"email": "avery@globex.com",
"name": "Avery"
}
],
"subject": "Welcome to {{company}}",
"html": "<p>Hello {{name}}</p><p><a href=\"{{link}}\">{{cta_label}}</a></p><p><a href=\"{{unsubscribe_url}}\">Unsubscribe</a></p>",
"variables": {
"company": "Acme",
"link": "https://acme.com/confirm",
"cta_label": "Get started"
},
"perRecipientVariables": {
"avery@globex.com": {
"cta_label": "Activate workspace"
}
},
"metadata": {
"campaign": "welcome-sequence"
}
}'{
"messageId": "msg_9f3a21",
"status": "queued",
"idempotentReplay": false
}Retrieve email
Fetch the current status and delivery detail for a single message.
{
"message": {
"id": "msg_9f3a21",
"status": "delivered",
"subject": "Welcome to Acme",
"createdAt": "2026-04-21T14:32:08Z"
},
"recipients": [],
"events": []
}Email logs
List delivery events for the authenticated application.
curl /v1/emails/logs \
-H "x-api-key: lum_sk_..."Email stats
Get aggregate stats for the authenticated application.
curl /v1/emails/stats \
-H "x-api-key: lum_sk_..."Add domain (portal)
Register a sending domain from the portal (session-authenticated). This is the flow used by the Add domain wizard.
{
"domain": "mail.acme.com"
}Verify DNS (portal)
Verifies SPF/DKIM/DMARC records for a portal domain. Use this after adding DNS records.
Create template
Create a reusable email template. Reference it later by slug when sending.
{
"id": "tpl_71xV",
"slug": "welcome-email",
"name": "Welcome email",
"status": "active"
}Create API key (portal)
Creates an API key for an app. The secret is returned once.
{
"name": "Server key",
"rateLimitPerMinute": 60,
"scopes": { "email:send": true }
}List API keys (portal)
Lists keys for an app, including prefixes and status.