OAKENMAIL
Generated

HTTP API

The loopback API: authentication, the Host and Origin rules, every operation route, the event stream and the agent job routes, from the OpenAPI document.

The local API core serves on 127.0.0.1. The CLI and the web UI use it, and the OpenAPI document this page is built from is served at GET /v1/openapi.json. How it is kept safe.

1

Reaching it

The MCP server is not in this document. When [api] mcp = true it is a separate door on the same listener, /mcp, with its own token and limits, and with the swarm on, /mcp/agent for agent tokens. See Connect an AI client.

2

Routes

Method Path Auth What it does
GET /v1/health none Liveness. Needs no token and reveals nothing else.
GET /v1/operations API token The operations this caller may call, with their schemas.
GET /v1/openapi.json API token This document.
GET /v1/events API token Server-Sent Events: what core does, as it happens.
POST /v1/agent/jobs/claim agent token Lease the best runnable job of the agent's kinds, or none.
POST /v1/agent/jobs/{job_id}/heartbeat agent token Extend the lease; says whether the job was cancelled.
POST /v1/agent/jobs/{job_id}/complete agent token Finish the job with a result that matches its kind's schema.
POST /v1/agent/jobs/{job_id}/fail agent token Give the job back with an error; core decides whether to retry.
POST /v1/operations/{name} API token Call one operation. 65 exist.
3

Calling an operation

POST /v1/operations/{name} takes input and answers ``request_id, status, output?.

status is ok when the operation ran, or confirmation_required for a mutation that was not confirmed: nothing has changed, and proposal says what would, with a confirmation_token. A person at the CLI or UI may send confirm: true. An agent calls again with the token. Status codes: 422 input or result does not validate, 403 not permitted, 404 unknown, 409 conflict, 429 quota, 502 a plugin or provider failed.

Operation Permission MCP Route
ask read off until turned on POST /v1/operations/ask
authorization_status read never POST /v1/operations/authorization_status
cancel_job mutate never POST /v1/operations/cancel_job
check_account read never POST /v1/operations/check_account
create_account mutate never POST /v1/operations/create_account
create_agent mutate never POST /v1/operations/create_agent
create_folder mutate never POST /v1/operations/create_folder
create_label mutate never POST /v1/operations/create_label
enrich_message mutate never POST /v1/operations/enrich_message
get_account read never POST /v1/operations/get_account
get_enrichment read on by default POST /v1/operations/get_enrichment
get_message read on by default POST /v1/operations/get_message
get_message_rules read on by default POST /v1/operations/get_message_rules
get_raw read never POST /v1/operations/get_raw
get_thread read on by default POST /v1/operations/get_thread
list_accounts read on by default POST /v1/operations/list_accounts
list_agents read never POST /v1/operations/list_agents
list_audit read never POST /v1/operations/list_audit
list_jobs read on by default POST /v1/operations/list_jobs
list_labels read on by default POST /v1/operations/list_labels
list_mailbox read on by default POST /v1/operations/list_mailbox
list_messages read on by default POST /v1/operations/list_messages
list_operations read never POST /v1/operations/list_operations
list_plugins read on by default POST /v1/operations/list_plugins
list_schedules read on by default POST /v1/operations/list_schedules
mailbox_counts read on by default POST /v1/operations/mailbox_counts
mark_read mutate on by default POST /v1/operations/mark_read
mark_unread mutate on by default POST /v1/operations/mark_unread
message_dismissed read never POST /v1/operations/message_dismissed
message_presented mutate never POST /v1/operations/message_presented
move_to_folder mutate never POST /v1/operations/move_to_folder
pause_backfill mutate never POST /v1/operations/pause_backfill
pause_schedule mutate never POST /v1/operations/pause_schedule
pipeline_status read on by default POST /v1/operations/pipeline_status
plugin_health read on by default POST /v1/operations/plugin_health
rebuild_index mutate never POST /v1/operations/rebuild_index
remove_account mutate never POST /v1/operations/remove_account
remove_schedule mutate never POST /v1/operations/remove_schedule
reprocess mutate never POST /v1/operations/reprocess
resume_backfill mutate never POST /v1/operations/resume_backfill
resume_schedule mutate never POST /v1/operations/resume_schedule
retry_job mutate never POST /v1/operations/retry_job
retry_parked mutate never POST /v1/operations/retry_parked
revoke_agent mutate never POST /v1/operations/revoke_agent
savings_summary read on by default POST /v1/operations/savings_summary
search read on by default POST /v1/operations/search
search_keyword read on by default POST /v1/operations/search_keyword
set_account_config mutate never POST /v1/operations/set_account_config
set_account_password mutate never POST /v1/operations/set_account_password
set_flagged mutate off until turned on POST /v1/operations/set_flagged
set_labels mutate never POST /v1/operations/set_labels
set_operation_exposure mutate never POST /v1/operations/set_operation_exposure
set_schedule mutate never POST /v1/operations/set_schedule
sieve_check read never POST /v1/operations/sieve_check
sieve_delete mutate never POST /v1/operations/sieve_delete
sieve_get read never POST /v1/operations/sieve_get
sieve_list read never POST /v1/operations/sieve_list
sieve_save mutate never POST /v1/operations/sieve_save
sieve_test read never POST /v1/operations/sieve_test
start_authorization mutate never POST /v1/operations/start_authorization
status read on by default POST /v1/operations/status
summarize_message mutate on by default POST /v1/operations/summarize_message
sync_now mutate on by default POST /v1/operations/sync_now
undo mutate on by default POST /v1/operations/undo
usage_summary read on by default POST /v1/operations/usage_summary

Each operation's input and output are in Reference: Operations, and as JSON Schema in the OpenAPI document and in GET /v1/operations.

4

Events

GET /v1/events is server-sent events. Each frame has an id (a number), an event (the type below) and data (one line of JSON: ids and counts, never message text). Send Last-Event-ID to resume from the in-memory ring. If that id is older than the ring, or from before core restarted, a gap event comes first, meaning fetch state again. A quiet stream sends : heartbeat comments.

Event type Meaning Fields
AttachmentQuarantined Flagged attachments of a message were written to the quarantine folder (never opened). ts, event_id, account_id, message_id, count
IndexRebuildProgress A rebuild of index.db is under way. total is the live messages in scope when it started; done counts the ones looked at (changed or not). finished is the last event. ts, event_id, account_id, done, total, indexed, failed, finished
JobStateChanged Job state changed. ts, event_id, job_id, kind, status, account_id
LargeMessageStored A message was too big for raw.db and went to the LFS folder, whole. oversize is set when it is also past storage.max_message_bytes (worth a warning in a UI). ts, event_id, account_id, message_id, size_bytes, oversize
MessageEmbedded Message embedded. ts, event_id, account_id, message_id, model
MessageEnriched Message enriched. ts, event_id, account_id, message_id, enricher
MessageFiltered Sieve ran on a message and its organization attributes were written. ts, event_id, account_id, message_id, disposition
MessageIndexed Message indexed. ts, event_id, account_id, message_id
MessageParsed Message parsed. ts, event_id, account_id, message_id
MessageReadChanged Message read changed. ts, event_id, account_id, message_id, read, reason, audit_id, local_only, error
MessageStarChanged A message was starred or unstarred (the \Flagged flag). Same local-first, written-back shape as MessageReadChanged: local_only while no provider can write it, with error. ts, event_id, account_id, message_id, starred, reason, audit_id, local_only, error
MessageStored is_new: first time seen. changed: an existing message got different bytes (or came back after a delete), so anything derived from it is stale. A no-op put publishes nothing. ts, event_id, account_id, message_id, is_new, changed
PluginEvent Base for events a plugin defines itself: subclass it, add plain-data fields, and publish with ctx.publish(...). plugin names the sender (the host fills it in). ts, event_id, plugin
PluginHealthChanged Plugin health changed. ts, event_id, plugin, healthy, detail
SyncFinished Sync finished. ts, event_id, account_id, new_messages, error, quiet, folder
SyncPaused An account's scheduled sync stopped until the user acts (for example, the password was refused). quiet is as on SyncFinished. ts, event_id, account_id, reason, quiet
SyncProgress Sync progress. ts, event_id, account_id, done, total
SyncScheduleChanged A sync schedule was added, edited, paused, resumed or removed (change says which). ts, event_id, account_id, folder, change
SyncStarted Sync started. ts, event_id, account_id
gap That id is no longer available; fetch state again. first_available
5

Agent job routes

Authenticated by an agent token, never by the API token. See the swarm.

POST /v1/agent/jobs/claim

Lease the best runnable job of the agent's kinds, or none.

POST /v1/agent/jobs/{job_id}/heartbeat

Extend the lease; says whether the job was cancelled.

POST /v1/agent/jobs/{job_id}/complete

Finish the job with a result that matches its kind's schema.

POST /v1/agent/jobs/{job_id}/fail

Give the job back with an error; core decides whether to retry.