FromlyDocumentation
Get started

Documentation

Everything Fromly does through its interface, it does through an API: reading contacts and events, drafting emails, and sending. The same key works for the HTTP API, the CLI and the MCP server.

Authentication

Every request carries an API key as a bearer token. Keys are created in Settings → API and shown once.

curl https://api.fromly.io/v1/automations \
  -H "Authorization: Bearer fk_live_…"

A key that is absent, malformed, unknown, revoked or expired gets the same 401 with the same body. That is deliberate: distinguishing them would tell someone probing which of their guesses was closest.

Permission levels

A key is given one of three levels when it is created. Each one contains everything the level below it can do.

LevelWhat it can do
Read onlyCan read everything. Cannot change or send anything.
Read and draftCan also create and edit contacts, emails, campaigns and flows, and record events. Cannot send.
Full accessCan also send campaigns and transactional emails, activate flows, tag contacts and change their lists, send test emails and delete emails.
Transactional onlyCan send transactional emails and read templates, sent emails and domains. Cannot send campaigns or change anything.

Four things put mail in someone’s inbox, and only the highest level can do any of them: sending a campaign, activating a flow, sending a test email, and tagging a contact. That last one is the least obvious — writing a tag records a tag.added event, which can enrol the contact into a flow that is already live.

Permissions in full

Each level is stored as the list of permissions it grants, so a key keeps working unchanged when a new permission appears — it simply does not have it.

PermissionGrantsRead onlyRead and draftFull accessTransactional only
contacts:readRead contacts and their attributes.✓✓✓—
contacts:writeCreate and update contacts.—✓✓—
contacts:tagAdd or remove tags and list memberships, which can enrol a contact into a live flow.——✓—
events:readRead the event stream.✓✓✓—
events:writeRecord product events. These can trigger live automations.—✓✓—
emails:readRead the email library.✓✓✓✓
emails:writeCreate and edit emails.—✓✓—
emails:deleteDelete an email from the library.——✓—
emails:testSend a test email to an arbitrary address.——✓—
broadcasts:readRead campaigns and their results.✓✓✓—
messages:readRead sent emails and what became of them: delivered, opened, bounced.✓✓✓✓
domains:readRead the sending domains and their senders.✓✓✓✓
workspace:readRead the workspace this key or connection reaches.✓✓✓✓
broadcasts:writeCreate and edit campaign drafts.—✓✓—
broadcasts:sendSend, schedule or resume a campaign.——✓—
transactional:sendSend a transactional email to one address.——✓✓
automations:readRead flows, their figures and who is in them.✓✓✓—
automations:writeCreate and edit flows, including live ones.—✓✓—
automations:activateTurn a flow on, after which it sends on its own.——✓—

A request missing a permission gets 403, and the reply names the one it needed — unlike the 401 above, the caller is already known by then, so saying so costs nothing and saves a support ticket.

Rate limits

Counted per key rather than per workspace, so two keys in one workspace never spend each other’s budget.

RequestsLimit
Ordinary requests600 per minute
Sending a campaign, activating a flow10 per minute

Over the limit is 429 with a Retry-After header in seconds.

Paging

Lists take limit (1–100, default 25) and return a nextCursor. Pass it back as cursor to continue; a nextCursor of null means the last page.

{ "data": [ … ], "nextCursor": "clx…" }

Errors

StatusMeaning
401The key is missing, unusable, revoked or expired.
403The key lacks a permission. The reply names it.
404No such record in this workspace.
409Understood, but the current state refuses it.
429Too many requests. See Retry-After.

Where to go next

  • API reference — every endpoint and the permission it needs.
  • MCP — connect an AI assistant to a workspace.