Account & Billing
Docs chevron_right Account & Billing chevron_right API

API

EmailFlow AI ships a clean, resource-oriented REST API on every plan. Authenticate with a single token, send and receive JSON, and manage lists, subscribers, campaigns, and automations programmatically — the same endpoints the app itself uses.

Base URL and versioning

Every endpoint lives under the /api/v1/ prefix on your EmailFlow AI host. The current major version is v1; new endpoints are added without breaking existing ones, and any breaking change would ship as a new version alongside v1.

https://emailflow.ai/api/v1/<resource>
dns
Replace emailflow.ai with your own hostname on a self-hosted install (for example a local development server at http://127.0.0.1:8000/api/v1/). The examples below use the hosted base URL.

Authentication

Every request carries a single API token that is unique to your user and inherits your permissions. Generate it from your account: sign in, open your profile menu, and go to Account → API. Treat the token like a password — if it is ever exposed, rotate it from the same screen.

Pass the token in one of two ways. The Authorization header is preferred; the ?api_token= query parameter is supported for legacy clients.

# Preferred: bearer header
curl https://emailflow.ai/api/v1/me \
  -H "Authorization: Bearer YOUR_API_TOKEN"

# Legacy: query parameter
curl "https://emailflow.ai/api/v1/me?api_token=YOUR_API_TOKEN"

If you only have an email and password (for example from a programmatic client), exchange them for a token with POST /user/login, documented under Authentication and identity below. A missing or invalid token returns 401 Unauthorized.

key
API access is included on every plan, including Free. Use a separate token per integration where possible so you can revoke one without disrupting the others.

Requests, responses, and errors

Send parameters as form fields or, where noted, a JSON body. Every response is JSON. Status codes follow REST conventions, so you can branch your client on the code alone.

CodeMeaning
200 OKSuccessful read, update, or action.
201 CreatedResource created.
202 AcceptedWork queued (for example an asynchronous bulk import).
401 UnauthorizedMissing or invalid token.
403 ForbiddenToken valid, but the action is not permitted (validation failure or quota limit).
404 Not FoundThe requested resource does not exist.
500 Server errorSomething went wrong on the server.

Pagination. Index endpoints accept page and per_page (defaults vary by resource — 10 for lists and campaigns, 25 for subscribers). Pass them as query parameters to walk large collections.

Validation errors. When input fails validation the response carries a 403 with a field-keyed map of messages:

{
  "from_email": [
    "The from email must be a valid email address."
  ]
}

Authentication and identity

Endpoints for obtaining a token, verifying it, and reading the current account.

MethodEndpointDescription
POST/user/loginExchange email and password for an API token. Public — no token required.
GET/meReturn the authenticated user record. Use it to verify a 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.
# Get a 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..." }

Lists

Mailing lists are the primary container for subscribers. Each list has a default sender identity and a set of custom fields, which you add with the add-field sub-route.

MethodEndpointDescription
GET/listsPaginated index of lists owned by the token's user.
POST/listsCreate a list. Required: name, from_email, from_name.
GET/lists/{uid}Fetch a single list with its fields and statistics.
POST/lists/{uid}/add-fieldAdd a custom field. type is one of text, number, datetime.
DELETE/lists/{uid}Permanently delete a list and its subscribers.
# Create a list
curl -X POST https://emailflow.ai/api/v1/lists \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -d name="Newsletter" \
  -d from_name="Acme" \
  -d from_email="hi@acme.com" \
  -d contact[company]="Acme Inc." \
  -d contact[address_1]="1 Market St" \
  -d contact[city]="San Francisco" \
  -d contact[zip]="94105" \
  -d contact[phone]="+1 555 0100" \
  -d contact[country_id]=1 \
  -d contact[email]="hi@acme.com"

# Response
{
  "status": 1,
  "message": "List has been created!",
  "list_uid": "ab12cd34ef"
}

Add a custom field to that list:

curl -X POST https://emailflow.ai/api/v1/lists/{uid}/add-field \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -d type=text \
  -d label="First name" \
  -d tag=FIRST_NAME

Subscribers

Subscribers belong to a list and carry custom field values, tags, and a status of subscribed, unsubscribed, or unconfirmed. Custom fields are passed as uppercase parameters (FIRST_NAME, LAST_NAME, …) matching your list's field configuration.

Single subscriber operations

MethodEndpointDescription
GET/subscribers?list_uid={uid}Paginated index for a list. Filter with open=yes|no and click=yes|no.
POST/subscribersCreate a subscriber. Required: list_uid, EMAIL.
GET/subscribers/{id}Fetch a single subscriber by id or email.
PATCH/subscribers/{id}Update fields, tags, or status.
POST/subscribers/{id}/add-tagAdd comma-separated tags.
POST/subscribers/{id}/remove-tagRemove comma-separated tags.
GET/subscribers/email/{email}Find every list containing a subscriber with this email.
PATCH/lists/{list_uid}/subscribers/{id}/subscribeMark the subscriber subscribed.
PATCH/lists/{list_uid}/subscribers/{id}/unsubscribeMark the subscriber unsubscribed.
PATCH/lists/{list_uid}/subscribers/email/{email}/unsubscribeUnsubscribe by email when you do not have the id.
DELETE/subscribers/{id}Permanently delete the subscriber from the list.
# Add a subscriber with custom fields and tags
curl -X POST https://emailflow.ai/api/v1/subscribers \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -d list_uid=ab12cd34ef \
  -d EMAIL=alice@example.com \
  -d FIRST_NAME=Alice \
  -d tag=vip,newsletter \
  -d status=subscribed

Bulk import

Import many subscribers at once. The synchronous endpoint applies rows inline and returns per-row results — ideal for small batches. The asynchronous endpoint queues the work and returns a job you poll for progress — ideal for large files. Write endpoints are rate-limited to 60 requests per minute.

MethodEndpointDescription
POST/lists/{list_uid}/subscribers/bulkSynchronous bulk import. Returns counts and per-row errors.
POST/lists/{list_uid}/subscribers/bulk/asyncQueued bulk import. Accepts a JSON body or a multipart CSV upload. Returns 202 with a job.
GET/lists/{list_uid}/import-jobsList recent bulk-import jobs for a list.
GET/import-jobs/{job_uid}Poll a job for status, progress, and counts.
DELETE/import-jobs/{job_uid}Cancel a queued or running job.
# Synchronous bulk import (JSON body)
curl -X POST "https://emailflow.ai/api/v1/lists/{list_uid}/subscribers/bulk" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "mode": "overwrite",
    "subscribers": [
      { "EMAIL": "alice@example.com", "FIRST_NAME": "Alice", "tags": ["vip"] },
      { "EMAIL": "bob@example.com",   "FIRST_NAME": "Bob",   "status": "subscribed" }
    ]
  }'

# Response
{
  "list_uid": "ab12cd34ef",
  "received": 2,
  "inserted": 1,
  "updated": 1,
  "failed": 0,
  "batch_id": "imp_9f2c1a",
  "errors": []
}

For large or untrusted inputs, queue the job and poll it:

# Queue an async import, then poll
curl -X POST "https://emailflow.ai/api/v1/lists/{list_uid}/subscribers/bulk/async" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -F "file=@subscribers.csv" \
  -F 'mapping={"Email":"EMAIL","First Name":"FIRST_NAME"}' \
  -F "mode=overwrite"

# 202 Accepted
{ "job_uid": "job_77aa", "status": "queued", "status_url": "...", "cancel_url": "..." }

# Poll
curl "https://emailflow.ai/api/v1/import-jobs/job_77aa" \
  -H "Authorization: Bearer YOUR_API_TOKEN"

Campaigns

Campaigns are the unit of sending. Create one with HTML content and tracking flags, move it through run / pause / resume, then download per-event logs as CSV. See the campaigns guide for the full picture.

Managing campaigns

MethodEndpointDescription
GET/campaignsPaginated index. Accepts page and per_page.
POST/campaignsCreate a campaign. Required: list_uid, name, subject, from_email, from_name.
GET/campaigns/{uid}Fetch a single campaign with statistics.
PATCH/campaigns/{uid}Update content, subject, or tracking flags.
POST/campaigns/{uid}/runQueue the campaign for delivery.
POST/campaigns/{uid}/pausePause an in-flight campaign.
POST/campaigns/{uid}/resumeResume a paused campaign.
DELETE/campaigns/{uid}Delete a campaign that is not in progress.
# Create then run a campaign
curl -X POST https://emailflow.ai/api/v1/campaigns \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -d list_uid=ab12cd34ef \
  -d name="Spring sale" \
  -d subject="20% off this week" \
  -d from_email=hi@acme.com \
  -d from_name="Acme" \
  -d track_open=true \
  -d track_click=true \
  --data-urlencode 'html=<p>Hello!</p>'

curl -X POST https://emailflow.ai/api/v1/campaigns/{uid}/run \
  -H "Authorization: Bearer YOUR_API_TOKEN"

Log downloads

Each log endpoint streams a CSV for one event type. See reports and logs for how this data maps to the in-app reports.

MethodEndpointDescription
GET/campaigns/{uid}/tracking-log/downloadCombined tracking log.
GET/campaigns/{uid}/open-log/downloadOpens.
GET/campaigns/{uid}/click-log/downloadClicks.
GET/campaigns/{uid}/bounce-log/downloadBounces.
GET/campaigns/{uid}/feedback-log/downloadSpam and abuse feedback.
GET/campaigns/{uid}/unsubscribe-log/downloadUnsubscribes.

Automations

Automations are visual flows of triggers, conditions, and actions. The API lets you list your automations and fire one for a contact from an external event — pair it with the API trigger node to start a flow from your own system.

MethodEndpointDescription
GET/automationsPaginated index of automations the token's user owns.
POST/automations/{uid}/executeTrigger an automation. Useful for transactional flows.
curl -X POST https://emailflow.ai/api/v1/automations/{uid}/execute \
  -H "Authorization: Bearer YOUR_API_TOKEN"

# Response
{ "success": true }

Notifications

If you operate your own delivery pipeline, push delivery feedback back into EmailFlow AI so reports and suppression stay accurate. Report hard bounces and spam or abuse complaints against the original message id.

MethodEndpointDescription
POST/notification/bounceRecord a hard bounce. Parameters: message_id, description.
POST/notification/feedbackRecord a feedback report. Parameters: message_id, type (spam or abuse), description.
curl -X POST https://emailflow.ai/api/v1/notification/bounce \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -d message_id="2016374...@example.com" \
  -d description="550 mailbox not found"

Frequently asked questions

Do I need the API to use EmailFlow AI? No — everything works from the app. The API is for teams who want to connect their own apps and systems and automate data flow.

Which token format should I use? Prefer the Authorization: Bearer header. The ?api_token= query parameter still works for legacy clients but may appear in logs, so avoid it for sensitive calls.

How do I keep my keys safe? Treat API tokens like passwords: store them as secrets, never commit them to code or client-side bundles, use a separate token per integration, and rotate any token that is ever exposed from Account → API.

Are there rate limits? Bulk subscriber write endpoints are limited to 60 requests per minute. Other endpoints run against your own send and quota limits — see plans and quotas.