API reference contents
API reference
Documentation
Arrangements, notes and units
An arrangement is the thing that runs longer than a moment: a tenancy, a placement, a fleet, a contract, a production. Work items come and go; an arrangement is what they belong to.
What an arrangement is
A work item is one thing to do — a renewal, a filing, a chase. An arrangement is the relationship that keeps producing them. Each one carries a single sentence saying where it stands, which is usually all anybody needs to read.
The word matters because the API does not use a domain word for this. A business that manages tenancies, one that manages artists, and one that manages fleets all get arrangements, and each desk names its own units. The endpoints are the same; the nouns are the business's.
GET /arrangements
Every arrangement on the desk, most in need of attention first. The list is built when it is read, so it reflects the register rather than a stale copy.
curl -s "https://outcomedev.com/api/v1/arrangements" \
-H "Authorization: Bearer $OD_KEY"
{
"data": {
"items": [
{
"id": 12,
"title": "Riverside - 14 Ash Lane",
"state": "running",
"sentence": "Running since March, next date in 22 days.",
"subject": "14 Ash Lane",
"open": 4,
"waiting": 1,
"closed": 9,
"next_date": "2026-11-04",
"pending": 0
},
{
"id": 18,
"title": "Calderway contract",
"state": "behind",
"sentence": "Behind on the second instalment since 2 September.",
"subject": "Calderway Ltd",
"open": 3,
"waiting": 2,
"closed": 5,
"next_date": "2026-10-20",
"pending": 1
}
]
}
}
| Field | Meaning |
|---|---|
id | The arrangement. This is the id the notes endpoint takes. |
title | What the arrangement is called on the desk. |
state | Where it stands: behind, running or settled. |
sentence | One sentence saying where it stands. Written for a person, safe to display. |
subject | The unit this arrangement is about, when it has one. |
open, waiting, closed | Counts of the work attached to it. |
next_date | The next date anything on this arrangement falls due. |
pending | Inbound items waiting on a decision. Non-zero means somebody answered and nobody has read it. |
Where an arrangement has money against it, the read includes arrears, outstanding, paid and due-to-date totals and a per-instalment schedule. Money is minor units with a currency, never a float.
GET /arrangements/{id}
One arrangement in full: the arrangement itself, its unit, its commitments or schedule, its payments, its notes, and the work attached to it. This is the endpoint to call when somebody opens an arrangement and the page has to show everything on it.
curl -s "https://outcomedev.com/api/v1/arrangements/18" \
-H "Authorization: Bearer $OD_KEY"
{
"data": {
"id": 18,
"title": "Calderway contract",
"status": "running",
"started_on": "2026-04-01",
"subject": { "id": 7, "type": "site", "name": "Calderway Ltd" },
"work": [
{ "id": 61, "title": "Confirm the second instalment", "status": "waiting", "due_date": "2026-10-20" },
{ "id": 66, "title": "Send the updated schedule", "status": "open", "due_date": "2026-11-02" }
],
"commitments": [
{
"id": 4,
"label": "Twelve monthly instalments",
"status": "running",
"total": 240000,
"instalments": 12,
"cadence_days": 30,
"started_on": "2026-04-01",
"standing": { "state": "behind", "arrears": 20000, "outstanding": 160000, "paid": 80000 },
"schedule": [
{ "id": 31, "due_on": "2026-04-01", "amount": 20000, "paid": 20000, "paid_on": "2026-04-02", "note": null, "state": "paid", "fallen_due": true }
]
}
],
"notes": [
{
"id": 88,
"body": "Called the agent. They will confirm the certificate by Friday.",
"actor": "sam",
"channel": "call",
"created_at": "2026-10-09T15:41:07.220Z"
}
]
}
}
Money amounts here are in minor units, so 20000 is two hundred units of the
currency. A schedule entry carries state of paid,
part or unpaid, and fallen_due, which is a fact
about the calendar rather than about the person.
The exact set of keys depends on what the arrangement has. An arrangement with no commitments has no money block; one with no notes has an empty array rather than a missing key. A client should read what is there rather than assuming a fixed shape.
POST /arrangements/{id}/notes
The place unstructured knowledge goes. A note is not a comment: the desk reads these when it works the arrangement, so writing one down changes what the desk does next.
curl -s -X POST "https://outcomedev.com/api/v1/arrangements/18/notes" \
-H "Authorization: Bearer $OD_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: note-18-2026-10-13" \
-d '{"body":"Called the agent. They will confirm the certificate by Friday.","actor":"sam","channel":"call"}'
{
"data": {
"id": 88,
"outcome_id": 18,
"direction": "internal",
"channel": "call",
"subject": null,
"body": "Called the agent. They will confirm the certificate by Friday.",
"status": "sent",
"actor": "sam",
"created_at": "2026-10-09T15:41:07.220Z",
"sent_at": "2026-10-09T15:41:07.220Z"
}
}
| Field | Required | Meaning |
|---|---|---|
body | Yes | The note. Trimmed, and truncated at 4,000 characters. Empty is refused. |
actor | No | Who wrote it. Defaults to api. |
channel | No | note or call. Anything other than call is stored as note. |
A note is stored as an activity on the arrangement. That is why the
response carries direction internal and status
sent: it is part of the record, not a side table. It will therefore also
appear in GET /activity alongside the messages the desk sent.
The channel is not validated, it is defaulted. Sending
channel: "call" is stored as a call. Sending "phone" or
"Call" is stored as a plain note, silently. If the distinction matters to a
client, send the two exact values.
What can go wrong: 400 bad_request for an empty body or a missing one,
404 not_found when the arrangement is not on this desk. Nothing is written in
either case.
GET /units
The things the desk looks after. A fleet operator sees vehicles, a manager sees artists, a landlord sees tenancies — the shape is the same and the vocabulary is the business's own.
curl -s "https://outcomedev.com/api/v1/units?type=site" \
-H "Authorization: Bearer $OD_KEY"
{
"data": {
"items": [
{
"id": 7,
"type": "site",
"name": "Calderway Ltd",
"fields": { "reference": "CW-118", "contact": "Accounts" },
"arrangement_id": 18
},
{
"id": 9,
"type": "site",
"name": "14 Ash Lane",
"fields": { "reference": "AL-14" },
"arrangement_id": 12
}
]
}
}
| Query | Effect |
|---|---|
arrangement | Only the units belonging to that arrangement. Takes precedence over type. |
type | Only units of that type, as the desk names it. A filter for a type this desk does not have returns an empty list rather than an error. |
| neither | Every unit on the desk. |
fields is free-form: each desk records whatever its units need. Do not
assume a key exists inside it. The valid values for type are the ones that
come back from an unfiltered call, and GET /desk says which of them a given
desk shows as a block.
Honest limits
- There is no write endpoint for arrangements. They cannot be created, renamed or closed through version 1. They are produced by the desk and managed in the product. Notes are the exception, deliberately: a note is a thing a person knows, and the API is a reasonable place for it to enter.
-
/unitsdoes not page. It returns everything that matches. A desk with thousands of units gets thousands back. The list endpoints that page are/work,/activityand/events. -
The list is built on read.
GET /arrangementsrecomputes from the register on every call rather than serving a cached index, which is why it is slower than a table read and always current.