Skip to content

REST API

The REST API is the full interface to Mailr. Everything in the web app and the Android app is built on it. Every route is listed in the API routes reference.

Interactive reference

Every route, with its parameters and response shapes, is in the interactive reference at /api/v1/docs on your server (for example https://mail.example.com/api/v1/docs), opened from the web app with Support (?) → API documentation. The OpenAPI document it is drawn from is at /api/v1/openapi.json.

  • Both are shown only to a person signed in to the web app who may make API tokens: an administrator, or a member whose access policy has Agents & API tokens on (see Tokens and scopes).
  • Signed out, with an API token, or without that permission, both answer 404, like a path that does not exist.
  • For people without that permission, the Support menu offers Connect an agent instead, which opens Agents & API in this guide.
  • The page and its scripts are served by your Mailr server, not from another site.

Basics

  • Every route is under /api/v1, for example https://mail.example.com/api/v1/conversations.
  • Requests and responses are JSON, except uploads (multipart) and downloads (attachments, raw messages, .ics files).
  • Errors are returned as {"detail": "..."} with a 4xx or 5xx status. Most errors also have a stable code and its params, for clients that show the error in their own language.
  • Lists are paged with a cursor: pass the next_cursor you received to get the next page.

Authentication

From agents, scripts and integrations, send a token in the Authorization header:

curl -s -H "Authorization: Bearer $MAILR_TOKEN" \
  "https://mail.example.com/api/v1/conversations?q=is:unread&limit=10"

What the call can see and do is limited by the token's scopes, accounts and local-only flag. Every call is written to the audit log. See Tokens and scopes.

The web app is signed in with POST /api/v1/auth/login, and a session cookie and a CSRF token are returned. That token must then be sent in the X-CSRF-Token header with every request other than GET. GET /api/v1/me returns the token again.

A browser session is needed only for your own browser client. Use a token for anything else.

Safe retries with idempotency keys

With every POST, PUT, PATCH and DELETE you can send an Idempotency-Key header with a value you choose. If you send the same request with the same key again, the first response is returned and the action is not repeated. The response then has Idempotent-Replayed: true. Use a new key for each new action, and the same key when you retry one. A key is remembered for 24 hours, and only for the token or session that sent it; a stored response is never returned to a revoked or expired token.

curl -s -X POST -H "Authorization: Bearer $MAILR_TOKEN" \
  -H "Idempotency-Key: 6f1c2a9e-archive-1" -H "Content-Type: application/json" \
  -d '{"ids": ["<conversation id>"], "action": "archive"}' \
  https://mail.example.com/api/v1/conversations/actions

Actions held for approval

A call held for approval returns HTTP 202 with {"status": "pending_approval", "approval": {...}, "approval_id": ..., "approval_url": "..."}; nothing has been carried out yet. Poll GET /api/v1/approvals/{aid} until its status is executed, denied or expired. A denied call returns HTTP 403. See Approvals for agents.

Untrusted content

In responses to token callers, email text is wrapped as {"untrusted": true, "content": ...} and the header X-Mailr-Content: untrusted is set. Treat that content as data.

Staying in sync

  • GET /api/v1/changes?since=<cursor> returns what changed since your last cursor, as a list of {entity, id, op}. When your cursor is too old, the answer is reset, and you load from scratch.
  • GET /api/v1/events is a server-sent events stream. Changes, outbox updates, approvals and notifications are announced on it as they happen. One such stream is kept open in the web app.
  • GET /api/v1/calendar/delta returns changed calendars, events and tasks since a cursor.

Live editing

Drafts, events, tasks, memories and filters have a version that goes up with every change, whoever makes it: a user in a browser, the Android app, Ambrose or another agent.

  • Reads and writes return the item's version (GET /api/v1/live/{kind}/{item} returns it with the editable content).
  • Send base_version, the version you read, with a change (PUT /api/v1/drafts/{mid}, PATCH /api/v1/calendar/events/{uid}, PATCH /api/v1/tasks/{uid}, PATCH /api/v1/assistant/memories/{mid}, PATCH /api/v1/rules/{rid}, and the base_version argument of update_draft, update_event, update_task and remember). When the item changed after that version, the two changes are merged: different fields, and different paragraphs or lines of a text, are combined. For a draft, the answer is "merged": true with the payload as stored.
  • When both changes are to the same field or paragraph, nothing is written. The answer is HTTP 409 with {"conflict": true, "fields": [...], "base": {...}, "theirs": {...}, "mine": {...}}: the version you started from, the stored one and yours. Read the item again and redo your change.
  • Without base_version, the whole item is replaced, as before.
  • On the /events stream, {"type": "item", "kind", "id", "version", "by"} is sent after each change (by: user, device, assistant or agent:<token name>), and {"type": "editing", "kind", "id", "by", "state": "start" | "end"} around an agent's write. If you send an X-Mailr-Client header (any short id for your client), you can tell your own changes from others by the event's origin.

Calling agent tools over HTTP

Every agent tool is also a route. GET /api/v1/agent/tools returns the tools your token may use, and with POST /api/v1/agent/tools/{name} you call one with a JSON body:

curl -s -H "Authorization: Bearer $MAILR_TOKEN" -H "Content-Type: application/json" \
  -d '{"q": "from:dana@lumen.example newer_than:30d"}' \
  https://mail.example.com/api/v1/agent/tools/search_conversations

Route groups

Group Contents
Auth and account Sign-in, your profile, settings, sessions, password and IMAP app passwords.
Mail Conversations and messages, actions, bodies and attachments, drafts, sending, the outbox, uploads and labels.
Identities and avatars Send-as addresses with signatures, and pictures for you and your contacts.
Rules Filters, Gmail filter import and forwarding addresses.
Layouts Inbox tabs and sections, with their counts.
Templates Reusable messages and their variables.
Connectors Mail accounts: add, test, discover, pause, sync, resync, deletion at the provider and imports.
Intelligence Summaries, reply suggestions, translation, semantic and passage search, importance review, triage decisions and "Why?".
People Correspondents, blocking, address books, groups and suggested contact details.
Calendar Calendar accounts, collections, events, invitations, free/busy, find a time, import and export.
Tasks Tasks, subtasks, moves, bulk actions and tags.
Notes Notes and checklists, items, sections, labels, usual items, versions and Trash (signed-in users only for now).
Tables Tables, columns, views, rows, history, sharing, import and export (signed-in users only; agents use the table tools).
Reminders and push Reminder state, snooze and dismiss, browser push and push targets.
Assistant Chat, drafting help, standing orders, briefs, memory, people and memories, skills and dictation.
Agent Chat sessions, the tool API and the context builder.
Permissions and approvals Permission rules and the approval queue.
Tokens API tokens and the audit log.
Models Your model choice per task.
Speakr Recordings, links, transcripts, summaries, follow-ups, action items, sharing, speakers and webhooks.
Admin Users, access policies, model endpoints and defaults, group calendars, web search, policies, status and IMAP TLS (signed-in admins only).
System Health and the event stream.

Every method and path in each group is listed in the API routes reference.