Developers · 04

REST API

JSON under /api/v1. Read the workspace, write documentation, tasks and meetings. Spec: /developers/openapi.json.

Raw markdown

Conventions

  • Base URL: https://<your-host>/api/v1
  • JSON. POST bodies: Content-Type: application/json
  • Success: 200 {"ok":true,"data":…}
  • Error: 4xx/5xx {"ok":false,"error":"<code>","message":"…"}
  • Lists: data is an array
  • Path IDs are slugs, not UUIDs
  • Machine-readable spec: OpenAPI (also GET /api/v1/openapi.json, no token)

Endpoints

MethodPathScopeReturns
GET/meany valid tokenOrg + token scopes
GET/projectsprojects:readProjects in this org
GET/projects/:slugprojects:readOne project (includes id)
GET/projects/:slug/specsspecs:readSpec lineages + latest published version
GET/projects/:slug/componentscomponents:readComponent lineages + latest version
GET/projects/:slug/milestonesmilestones:readMilestones
GET/projects/:slug/taskstasks:readTasks
GET/projects/:slug/pagespages:readDocumentation page tree, without bodies
GET/pages/:page_idpages:readOne page, body as plain text
GET/documentsdocuments:readTeam-level document library
GET/projects/:slug/documentsdocuments:readA project's library
GET/meetingsmeetings:readMeetings you may see
GET/projects/:slug/meetingsmeetings:readA project's meetings
GET/meetings/:meeting_idmeetings:readOne meeting, minutes as text
GET/meetings/:meeting_id/transcriptmeetings:readVerbatim transcript
POST/webhooks/pingwebhooks:manageTest delivery to a registered webhook

/documents and /meetings without a project segment cover the team-level library and every meeting in the organisation. Both accept filters: ?category=documentation|research on documents, ?from= and ?to= as ISO date-times on meetings.

Page, document and meeting ids are UUIDs. Projects are still addressed by slug.

Write endpoints

Four scopes write. Everything else on this API reads.

MethodPathScopeDoes
POST/projects/:slug/pagespages:writeCreate a documentation page
PATCH/pages/:page_idpages:writeRetitle or rewrite a page
POST/documentsdocuments:writeAdd a team-level link
POST/projects/:slug/documentsdocuments:writeAdd a link to a project
PATCH/documents/:document_iddocuments:writeRetitle or redescribe an entry
POST/projects/:slug/taskstasks:writeCreate a task
PATCH/tasks/:task_idtasks:writeUpdate a task, including its status
POST/meetings/:meeting_id/minutesmeetings:writeSet or extend minutes
POST/meetings/:meeting_id/notesmeetings:writeReplace transcript notes

A PATCH touches only the fields you send. Send null to clear a date or a blocked reason; omit the field to leave it alone.

Page bodies and minutes are written as markdown. Headings, bullet lists and numbered lists convert to the app's rich text. Tables and images do not, yet.

POST to minutes and PATCH on a page both take mode. replace is the default and discards what is there; append adds below a divider. Read the page first if you mean to keep any of it.

Who a write is attributed to

Every write records the person the token belongs to: whoever authorized the OAuth grant, or whoever minted the token by hand. Their name appears on the page, task or minutes, and page edits land in the revision history like any other edit.

A token with no user behind it can read but is refused every write with invalid_request. That happens when the person who created it has been removed from the organisation. Mint a new token to fix it.

Assigning a task takes a user id from your organisation, not a name. An id from anywhere else is refused.

What this API will not do

Publish a specification or a component version. Publishing marks every dependent stale and can route an approval, so it keeps one path through the app. Read a spec here, write your reasoning into a document, and let a person publish it.

Reach a private project. Projects with visibility: private are invisible on /api/v1 whatever scopes a token holds, and a request for one is a 404, the same answer as a project that does not exist. Connected assistants at /api/mcp do reach them, for the member who connected them. See the connector docs.

Upload a file. documents:write files links. A file needs a signed upload, which stays in the app.

Delete anything. There is no delete scope and no delete endpoint.

List projects

bash
curl -s \
  -H "Authorization: Bearer $PROTOTYPE_TOKEN" \
  "$PROTOTYPE_URL/api/v1/projects"
javascript
const res = await fetch(`${process.env.PROTOTYPE_URL}/api/v1/projects`, {
  headers: { Authorization: `Bearer ${process.env.PROTOTYPE_TOKEN}` },
});
const json = await res.json();
if (!json.ok) throw new Error(json.error);
console.log(json.data);
python
import json, os, urllib.request

req = urllib.request.Request(
    f"{os.environ['PROTOTYPE_URL']}/api/v1/projects",
    headers={"Authorization": f"Bearer {os.environ['PROTOTYPE_TOKEN']}"},
)
print(json.load(urllib.request.urlopen(req)))
json
{
  "ok": true,
  "data": [
    {
      "slug": "aurc-2026",
      "name": "AURC 2026",
      "status": "active",
      "visibility": "org",
      "description": null,
      "startDate": "2025-09-01",
      "targetDate": "2026-07-12"
    }
  ]
}

Specs and components

GET /projects/:slug/specs returns the latest published version only. Drafts are not in the API.

json
{
  "ok": true,
  "data": [
    {
      "slug": "dry-mass",
      "name": "Dry mass",
      "kind": "mass",
      "units": "kg",
      "valueType": "number",
      "latest": {
        "version": "3",
        "status": "published",
        "value": 4.2,
        "publishedAt": "2026-08-22T05:12:00.000Z"
      }
    }
  ]
}

GET /projects/:slug/components carries latest.healthStatus: ok, stale, under-rated, or blocked.

Nested routes use the project slug. GET /projects/:slug is the one response that also includes id (uuid).

Milestones and tasks

GET /projects/:slug/milestones:

json
{
  "ok": true,
  "data": [
    {
      "name": "Static fire",
      "kind": "test",
      "status": "planned",
      "targetDate": "2026-10-01",
      "actualDate": null,
      "description": null
    }
  ]
}

GET /projects/:slug/tasks:

json
{
  "ok": true,
  "data": [
    {
      "title": "Torque check on the injector plate",
      "status": "in_progress",
      "priority": "high",
      "targetDate": "2026-09-14",
      "description": null
    }
  ]
}

Errors

CodeHTTPMeaning
invalid_token401Missing, malformed, revoked, or expired
insufficient_scope403Token is valid but missing that scope
not_found404Unknown path, or slug not in this org
invalid_request400Query or body failed validation, or a write was refused for a stated reason
rate_limited429Too many requests on this token

A 400 on a write carries a message you can act on: which field failed, that the body was too large, that the assignee is not in this organisation, or that the token has no author behind it.