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 other local clients 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. 94 exist.
3

Calling an operation

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

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
approve_action mutate never POST /v1/operations/approve_action
cache_stats read never POST /v1/operations/cache_stats
cancel_job mutate never POST /v1/operations/cancel_job
check_plugin_config read never POST /v1/operations/check_plugin_config
check_settings read never POST /v1/operations/check_settings
check_workspace read never POST /v1/operations/check_workspace
clear_cache mutate never POST /v1/operations/clear_cache
config_get read never POST /v1/operations/config_get
config_reload mutate never POST /v1/operations/config_reload
config_save mutate never POST /v1/operations/config_save
config_validate read never POST /v1/operations/config_validate
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
events_tail read never POST /v1/operations/events_tail
get_account read never POST /v1/operations/get_account
get_action read on by default POST /v1/operations/get_action
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_plugin_config read never POST /v1/operations/get_plugin_config
get_raw read never POST /v1/operations/get_raw
get_settings read never POST /v1/operations/get_settings
get_thread read on by default POST /v1/operations/get_thread
get_triage read on by default POST /v1/operations/get_triage
get_workspace read off until turned on POST /v1/operations/get_workspace
list_accounts read on by default POST /v1/operations/list_accounts
list_actions read off until turned on POST /v1/operations/list_actions
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
list_workspaces read off until turned on POST /v1/operations/list_workspaces
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_disable mutate never POST /v1/operations/plugin_disable
plugin_enable mutate never POST /v1/operations/plugin_enable
plugin_health read on by default POST /v1/operations/plugin_health
plugin_reload mutate never POST /v1/operations/plugin_reload
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
remove_workspace mutate never POST /v1/operations/remove_workspace
reprocess mutate never POST /v1/operations/reprocess
reset_usage mutate never POST /v1/operations/reset_usage
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_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_pipeline_limits mutate never POST /v1/operations/set_pipeline_limits
set_plugin_config mutate never POST /v1/operations/set_plugin_config
set_schedule mutate never POST /v1/operations/set_schedule
set_settings mutate never POST /v1/operations/set_settings
set_workspace mutate never POST /v1/operations/set_workspace
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
status read on by default POST /v1/operations/status
storage_info read never POST /v1/operations/storage_info
summarize_message mutate on by default POST /v1/operations/summarize_message
sync_now mutate on by default POST /v1/operations/sync_now
trace_set mutate never POST /v1/operations/trace_set
trace_status read never POST /v1/operations/trace_status
trace_tail read never POST /v1/operations/trace_tail
triage_message mutate never POST /v1/operations/triage_message
try_triage read on by default POST /v1/operations/try_triage
undo mutate on by default POST /v1/operations/undo
usage_summary read on by default POST /v1/operations/usage_summary
vacuum mutate never POST /v1/operations/vacuum

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
MessageTriaged The gate enricher stored its result; result is that result, for triggers (CORE_51). ts, event_id, account_id, message_id, result
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
TraceEvent One line of the trace, which holds mail text. It is published with publish_nowait, so the persistent handlers (the event log, the SSE ring) never see it, and EventBus.stream leaves it out unless a stream asks for TraceEvent by name. Only oaken trace -f (through the authenticated API) subscribes. ts, event_id, kind, data
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.