Home › Documentation › API

The OutcomeDev API

The OutcomeDev API is the desk without a browser. Anything that can hold a key can read the work, act on it, and ask the desk a question — and see exactly the rows a person sees.

OutcomeDev reads a business, works out everything it has to keep running, and works that list. This section is the reference for reaching that desk from code, from an agent, or from a language model through the MCP server.

Base URLhttps://outcomedev.com/api/v1
AuthenticationAuthorization: Bearer od_... — one key, one desk
Success{ "data": ... }
Failure{ "error": { "code", "message", "details"? } }
DescriptionGET /api/v1/openapi.json — no key needed

Who this is for

This reference is written for somebody who is going to write code against the desk, and for somebody who is going to point an agent at it. That is usually one of four things:

  • An integration. A bookkeeping system, a practice-management tool or an internal dashboard that should show the same work the desk shows.
  • An agent. Something that reads the queue, decides, and acts — through this API or through the MCP server, which is a thin wrapper around it.
  • A scheduled job. A nightly script that lists what is overdue and puts it somewhere else.
  • A person checking a claim. Every statement on these pages can be checked against a real response from a real key. Read Quick start and do it.

If the thing needed is understanding the product rather than calling it, the documentation is the better place to start. It explains the desk, the chat companion, connections and the limits, in the same house style as this reference.

The three design principles

These are not marketing. Each of them changes what a caller has to write, and each of them is visible in the shape of a response.

One key, one desk

A key is not an account and it is not a user. It is a desk, and it can reach exactly one. There is no route in this API that takes a desk as a parameter, and that is deliberate rather than unfinished: it means a key that leaks from a log or a repository is a key to one customer, not a key to every customer. It is also why no route here can create another key. Keys are minted from inside the product by somebody signed in, so a leaked key cannot be used to make more keys.

The practical consequence is that a client written for one desk works for any desk by changing one string, and that nothing anywhere in a request carries a tenant identifier.

Nothing sends itself

The desk prepares; a person approves. A message, a filing or an application goes out when the owner of the desk approved that particular piece of work, or when the owner granted the desk permission for that whole class of work in advance. There is no third case, and there is no switch that turns the first two off.

For a caller this shows up as two fields on every work item, permission and allowed, and as one endpoint that can refuse: POST /work/{id}/run answers 403 not_permitted unless the desk was already granted that class of work. Reading the queue never sends anything. Neither does completing a row. Sending happens as the consequence of an act the owner permitted, and the record of it is in Actions.

This is where a person is needed, and why. Some acts are reserved to a human being, by law or by another organisation: a wet signature, a physical inspection, anything sworn before a witness. The desk prepares those completely, attaches the paperwork, books the appointment and stops at the signature. The API reports them as the own action rather than pretending a button finishes them.

The API is the same code the interface runs

No route in this API has an engine of its own. Each one calls the same module the product's own screens call, and returns the shapes those screens read. A row's action, its prepared message, its waiting state and its permissions are computed once, by one function, and handed to both.

That buys agreement: an agent reading GET /work sees what the person at the desk sees, including the label on the button and the sentence explaining why it is that button. It costs stability in one specific way, and it is worth stating plainly: adding a field to the desk's queue changes this API too. The alternative — a second model of what a desk is, kept in step by hand — was rejected because the failure mode is silent disagreement between the screen and the API, which is worse than a new field.

Conventions, applied without exception

  • Bearer key, one desk per key: Authorization: Bearer od_...
  • { "data": ... } on success, { "error": { code, message } } on failure.
  • Timestamps are ISO 8601 UTC. A date that is only a date is YYYY-MM-DD.
  • Money is minor units plus a currency, never a float.
  • Writes take an Idempotency-Key header and are safe to retry with it.
  • Lists take limit and cursor.

GET /openapi.json is the one route that answers without a key. A description of an API is not a secret, and an editor or a generator has to be able to fetch it before it has a key. See OpenAPI.

Contents

Getting a key and calling something

The resource in the middle of everything

Writing a client that behaves

Tools and descriptions

The complete surface

Every route in version 1 — twenty of them, across six groups. Nothing here is aspirational: each one exists and is described in GET /openapi.json.

MethodPathPurpose
GET/The API and which desk the key is for
GET/openapi.jsonThe description. No key needed
GET/meThe desk, plus open / waiting / closed-today counts
GET/deskThe screen's composition — sections[]
GET/workThe queue. limit, cursor, status, kind, arrangement
GET/work/{id}work, messages[], timeline[]
POST/work/{id}/complete{ note?, actor? }
POST/work/{id}/snooze{ days } 1–365
POST/work/{id}/draft{ drafted: true, channel, subject, body, to } or { drafted: false, reason }
POST/work/{id}/run403 not_permitted unless granted. Takes minutes
GET/activityEverything written or sent. limit
GET/eventsThe desk's own log. limit
GET/arrangementsThe things that run longer than a moment
GET/arrangements/{id}One in full
POST/arrangements/{id}/notes{ body, actor?, channel? }, channel note or call
GET/unitsarrangement?, type?
GET/connectionsWhat the desk is wired into
GET/domainsDomains, state, and who holds them
GET/permissionsWhat the desk may do without asking
GET/watchesDates and counts the desk watches
POST/chat{ text }. Slow — allow up to four minutes

Two routes are slow, and neither is a bug. POST /work/{id}/run drives a real portal on the owner's behalf and takes minutes. POST /chat asks a session to answer and can take up to four minutes. Both need a client timeout set accordingly, and both are safe to retry with an Idempotency-Key.

Where to start

Make a key in the product, then follow Quick start. It is five calls, all of them safe, and it ends with a real piece of work completed on a real desk. If the target is an agent rather than a program, the MCP server is four lines of configuration and no code at all.