API reference contents
API reference
Documentation
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 URL | https://outcomedev.com/api/v1 |
|---|---|
| Authentication | Authorization: Bearer od_... — one key, one desk |
| Success | { "data": ... } |
| Failure | { "error": { "code", "message", "details"? } } |
| Description | GET /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-Keyheader and are safe to retry with it. - Lists take
limitandcursor.
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
- Authentication Creating a key in the product, the header, one-time display, and revocation.
- Quick start Five minutes: root, list work, read one item, complete it.
- Code examples The same four calls in curl, JavaScript, Python and Go.
The resource in the middle of everything
- Work The full shape of a work item, all eight action types, permissions and drafts.
- Actions Complete, snooze, draft, run and notes — and what each can refuse.
- Arrangements The things that run longer than a moment, their notes, and their units.
- The desk Composition, connections, domains, permissions, watches and chat.
Writing a client that behaves
- Errors Six codes, six statuses, and what to do about each one.
- Pagination limit, cursor, next_cursor, open_total — stable and unstable.
- Idempotency Why a retried approve is two emails, and the honest limit of the record.
Tools and descriptions
- OpenAPI The 3.1 description, and how to point a generator or an editor at it.
- MCP server @outcomedev/mcp, configuration for four clients, and fifteen tools.
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.
| Method | Path | Purpose |
|---|---|---|
GET | / | The API and which desk the key is for |
GET | /openapi.json | The description. No key needed |
GET | /me | The desk, plus open / waiting / closed-today counts |
GET | /desk | The screen's composition — sections[] |
GET | /work | The 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}/run | 403 not_permitted unless granted. Takes minutes |
GET | /activity | Everything written or sent. limit |
GET | /events | The desk's own log. limit |
GET | /arrangements | The 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 | /units | arrangement?, type? |
GET | /connections | What the desk is wired into |
GET | /domains | Domains, state, and who holds them |
GET | /permissions | What the desk may do without asking |
GET | /watches | Dates 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.