Auth & API keys
Authenticate with scoped, named API keys — create as many as your plan allows, grant each one only the permissions it needs, and revoke any one of them without disturbing the others. The original account-wide token keeps working for existing integrations.
Scoped API keys
An API key is a credential of the form efa_ followed by 40 random characters. Create keys under Account → API: give each one a name (so you can tell integrations apart), pick its scopes, and optionally set an expiry date. The plaintext key is shown exactly once, at creation — only a hash is stored, so copy it immediately and keep it in your secrets manager. The number of active keys is a plan quota.
Pass the key on every request in one of two headers — Authorization: Bearer is preferred:
# Preferred: bearer header curl https://emailflow.ai/api/v1/me \ -H "Authorization: Bearer efa_YOUR_KEY" # Alternative: X-API-Key header curl https://emailflow.ai/api/v1/me \ -H "X-API-Key: efa_YOUR_KEY"
A revoked or expired key returns 401 with an INVALID_API_KEY error envelope. Each key records last_used_at (updated at most once a minute) so you can spot abandoned integrations before revoking them.
Scopes
Scopes follow the principle of least privilege: grant only what an integration needs. Broad scopes include their narrower scopes — the “Includes” column below — while granular scopes grant only themselves. A key that lacks the required scope receives 403 INSUFFICIENT_PERMISSIONS, and the envelope names the missing scope so the fix is obvious.
| Scope | Grants | Includes |
|---|---|---|
all |
Everything, including admin endpoints | every scope |
contacts |
Lists and subscribers; includes Audiences | audiences |
audiences |
Read audience segments | — |
emails |
Email content; includes Domains, Sends and Templates | domains, sends, templates |
domains |
Sending domains | — |
sends |
Campaigns and sending | — |
templates |
Email templates | — |
automations |
Automation workflows; includes Triggers | triggers |
triggers |
Trigger automation runs | — |
webhooks |
Webhook subscriptions | — |
analytics |
Event analytics feed | — |
usage |
Usage and quota meters | — |
brand |
Brand profile | — |
all.The legacy account token
Before scoped keys, every account had a single token (visible under Account → API → Legacy token) with full access. It continues to work exactly as before — including the ?api_token= query parameter — and keeps its original response shapes, so nothing you built against it breaks. New integrations should use scoped efa_ keys instead: they are individually revocable, permission-scoped, and receive the canonical error envelope.
# Legacy token — header or query parameter curl https://emailflow.ai/api/v1/me \ -H "Authorization: Bearer YOUR_LEGACY_TOKEN" curl "https://emailflow.ai/api/v1/me?api_token=YOUR_LEGACY_TOKEN"
If you only have an email and password (for example from a programmatic client), exchange them for the legacy token with POST /user/login:
# Get the legacy token from email + password
curl -X POST https://emailflow.ai/api/v1/user/login \
-d email=you@example.com \
-d password=YOUR_PASSWORD
# Response
{ "api_token": "9f2c1ab4e5..." }
Identity endpoints
Endpoints for verifying a credential and reading the current account. GET /me is the canonical “is this key valid?” probe.
| Method | Endpoint | Description |
|---|---|---|
| POST | /user/login | Exchange email and password for the legacy API token. Public — no credential required. |
| GET | /me | Return the authenticated user record. Use it to verify a key or token. |
| GET | /user/info | Return the user profile: email, first and last name, and profile image URL. |
| GET | /dashboard | Return account summary counts: campaigns, lists, and subscriber usage against quota. |
| POST | /login-token | Generate a one-time URL that logs the user in when visited. |
Keeping credentials safe
Treat API keys like passwords: store them as secrets, never commit them to code or ship them in client-side bundles, use a separate key per integration, and revoke any key that is ever exposed from Account → API. Prefer the Authorization header over the legacy query parameter — query strings can end up in proxy and server logs. Setting an expiry on keys for short-lived projects means forgotten credentials shut themselves off.