Developer Platform
Docs chevron_right Developer Platform chevron_right Auth & API keys

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.

emailflow.ai/rui/account/api
The Account API page showing the API keys table: each key with its name, scopes, masked prefix, last-used time, expiry, and a revoke action, plus a New API key button
Account → API — named keys with scopes, last-used tracking, and one-click revocation.

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.

emailflow.ai/rui/account/api
The create API key modal with a name field, a checkbox grid of permission scopes such as contacts, emails, automations and webhooks, and an optional expiry date picker
Creating a key — name it, grant only the scopes the integration needs, optionally set an expiry.

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.

ScopeGrantsIncludes
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
key
API access is included on every plan, including Free. Use a separate key per integration so you can revoke one without disrupting the others, and prefer granular scopes over 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.

MethodEndpointDescription
POST/user/loginExchange email and password for the legacy API token. Public — no credential required.
GET/meReturn the authenticated user record. Use it to verify a key or token.
GET/user/infoReturn the user profile: email, first and last name, and profile image URL.
GET/dashboardReturn account summary counts: campaigns, lists, and subscriber usage against quota.
POST/login-tokenGenerate 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.