Organarium API
Everything an agent can do in Organarium over MCP is also available as a plain JSON API, for agents and scripts that don't have an MCP client. If yours does, prefer MCP: point it at https://mcp.organarium.com/mcp and it handles login for you.
- Base URL:
https://api.organarium.com - OpenAPI 3.0 document: https://app.organarium.com/openapi.json
- This page as markdown: https://app.organarium.com/docs/api.md
Quick start
curl https://api.organarium.com/v1/projects \
-H "Authorization: Bearer $ORGANARIUM_TOKEN"
curl -X POST https://api.organarium.com/v1/projects/$PROJECT_ID/tasks \
-H "Authorization: Bearer $ORGANARIUM_TOKEN" \
-H "Content-Type: application/json" \
-d '{"title": "Write the launch post", "bucket": "up_next", "agent": "my-agent"}'
Authentication
Send an OAuth 2.0 access token as Authorization: Bearer <token>. It's the same kind of token the MCP server uses, and it acts as the person who approved it, with access to the projects they belong to.
A person has to approve access once in a browser, using an Organarium account with an active subscription or invite (sign up). API keys and login without a browser aren't available yet.
To get a token, follow standard OAuth discovery:
- Fetch
https://api.organarium.com/.well-known/oauth-protected-resourceand read the authorization server fromauthorization_servers. - Fetch
<authorization server>/.well-known/oauth-authorization-serverfor its endpoints. - Register your client at
registration_endpoint(RFC 7591). - Run the authorization code flow with PKCE (
S256). Request theoffline_accessscope to also get a refresh token. - Exchange the code at
token_endpoint, and userefresh_tokenthere when the access token expires.
Conventions
- Requests and responses are JSON, with camelCase field names.
- Timestamps are ISO 8601. Filters must be in UTC, e.g.
2026-01-31T12:00:00Z. PATCHonly changes the fields you send. Sendnullto clear a nullable field.- Unknown fields and query parameters are rejected, so typos fail loudly.
- List endpoints return up to 50 results by default and 200 at most, set with
limit. There's no pagination cursor: narrow a list with the date filters. - Task buckets are
backlog,up_next,in_progressanddone. Priorities arelow,midandhigh. - Pass
agenton writes that accept it, so the task's updates record which agent made the change.
Errors
Errors look like this; validation errors also list issues:
{
"error": "invalid_request",
"error_description": "Validation failed.",
"issues": [{ "path": "body.title", "message": "Required" }]
}
| Status | Meaning |
|---|---|
400 |
The path, query or body failed validation. |
401 |
The token is missing, invalid or expired. Refresh it and retry. |
403 |
The account has no active subscription or invite. |
404 |
Not found, or you don't have access to it. Also returned when an assigneeId isn't a member of the project. |
409, 410 |
An invite code was already used, or has expired. |
Projects
GET /v1/projects
List the projects you belong to, with your role in each.
Returns 200 with ProjectWithRole[].
POST /v1/projects
Create a project. You become its owner.
JSON body:
| Field | Type | Required | Description |
|---|---|---|---|
name |
string |
yes | |
description |
string | null |
no | Free-text description. Pass null to clear it. |
extraData |
object | null |
no | Application-specific JSON object. Not for ordinary task or project information. Pass null to clear it. |
Returns 201 with Project.
GET /v1/projects/{projectId}
Get a project, including its pinned links.
Returns 200 with ProjectDetail.
PATCH /v1/projects/{projectId}
Update a project. Omitted fields are left unchanged.
JSON body:
| Field | Type | Required | Description |
|---|---|---|---|
name |
string |
no | |
description |
string | null |
no | Free-text description. Pass null to clear it. |
extraData |
object | null |
no | Application-specific JSON object. Not for ordinary task or project information. Pass null to clear it. |
Returns 200 with Project.
POST /v1/projects/{projectId}/links
Pin a useful link (docs, repo, dashboard) to a project.
JSON body:
| Field | Type | Required | Description |
|---|---|---|---|
url |
url |
yes | An http(s) URL. |
label |
string | null |
no | Optional display label. |
Returns 201 with ProjectLink.
GET /v1/projects/{projectId}/members
List a project's members. Use userId as an assigneeId.
Returns 200 with Member[].
Invites
POST /v1/projects/{projectId}/invites
Create a single-use invite code that expires after 24 hours.
Returns 201 with Invite.
POST /v1/invites/accept
Join a project with an invite code. Responds 404 for an unknown code, 410 for an expired one and 409 for one already used.
JSON body:
| Field | Type | Required | Description |
|---|---|---|---|
code |
string |
yes |
Returns 200 with InviteAcceptance.
Tasks
GET /v1/projects/{projectId}/tasks
List a project's tasks, most recently updated first.
Query parameters:
| Field | Type | Required | Description |
|---|---|---|---|
bucket |
backlog | up_next | in_progress | done |
no | |
priority |
low | mid | high |
no | |
tags |
string[] |
no | Only tasks with at least one of these tags. Repeat to pass several. |
createdAfter |
timestamp |
no | ISO 8601 UTC timestamp. Only tasks created after this time. |
createdBefore |
timestamp |
no | ISO 8601 UTC timestamp. Only tasks created before this time. |
updatedAfter |
timestamp |
no | ISO 8601 UTC timestamp. Only tasks updated after this time. |
updatedBefore |
timestamp |
no | ISO 8601 UTC timestamp. Only tasks updated before this time. |
limit |
integer |
no | Maximum results to return (1-200, default 50). |
Returns 200 with Task[].
GET /v1/projects/{projectId}/tasks/done
List a project's completed tasks, most recently completed first.
Query parameters:
| Field | Type | Required | Description |
|---|---|---|---|
priority |
low | mid | high |
no | |
tags |
string[] |
no | Only tasks with at least one of these tags. Repeat to pass several. |
completedAfter |
timestamp |
no | ISO 8601 UTC timestamp. Only tasks completed after this time. |
completedBefore |
timestamp |
no | ISO 8601 UTC timestamp. Only tasks completed before this time. |
limit |
integer |
no | Maximum results to return (1-200, default 50). |
Returns 200 with Task[].
POST /v1/projects/{projectId}/tasks
Create a task. Defaults to mid priority in the backlog.
JSON body:
| Field | Type | Required | Description |
|---|---|---|---|
title |
string |
yes | |
description |
string | null |
no | Free-text description. Pass null to clear it. |
priority |
low | mid | high |
no | |
bucket |
backlog | up_next | in_progress | done |
no | |
assigneeId |
uuid | null |
no | userId of a project member. Pass null to unassign. |
tags |
string[] |
no | Labels. Lowercased and deduplicated; replaces any existing tags. |
extraData |
object | null |
no | Application-specific JSON object. Not for ordinary task or project information. Pass null to clear it. |
agent |
string |
no | Name of the agent making this call (e.g. "instinct"). Shown in the project's activity feed. |
Returns 201 with Task.
GET /v1/tasks/{taskId}
Get a task, including its subtasks, links and updates.
Returns 200 with TaskDetail.
PATCH /v1/tasks/{taskId}
Update a task. Omitted fields are left unchanged. Moving it to the done bucket records completedAt; moving it out clears it.
JSON body:
| Field | Type | Required | Description |
|---|---|---|---|
title |
string |
no | |
description |
string | null |
no | Free-text description. Pass null to clear it. |
priority |
low | mid | high |
no | |
bucket |
backlog | up_next | in_progress | done |
no | |
assigneeId |
uuid | null |
no | userId of a project member. Pass null to unassign. |
tags |
string[] |
no | Labels. Lowercased and deduplicated; replaces any existing tags. |
extraData |
object | null |
no | Application-specific JSON object. Not for ordinary task or project information. Pass null to clear it. |
agent |
string |
no | Name of the agent making this call (e.g. "instinct"). Shown in the project's activity feed. |
Returns 200 with Task.
DELETE /v1/tasks/{taskId}
Permanently delete a task and its subtasks, links and updates.
Returns 204 with no body.
Subtasks
POST /v1/tasks/{taskId}/subtasks
Add a subtask to a task.
JSON body:
| Field | Type | Required | Description |
|---|---|---|---|
text |
string |
yes | |
assigneeId |
uuid | null |
no | userId of a project member. Pass null to unassign. |
extraData |
object | null |
no | Application-specific JSON object. Not for ordinary task or project information. Pass null to clear it. |
agent |
string |
no | Name of the agent making this call (e.g. "instinct"). Shown in the project's activity feed. |
Returns 201 with Subtask.
PATCH /v1/subtasks/{subtaskId}
Update a subtask's text, done state or extraData.
JSON body:
| Field | Type | Required | Description |
|---|---|---|---|
text |
string |
no | |
done |
boolean |
no | |
extraData |
object | null |
no | Application-specific JSON object. Not for ordinary task or project information. Pass null to clear it. |
agent |
string |
no | Name of the agent making this call (e.g. "instinct"). Shown in the project's activity feed. |
Returns 200 with Subtask.
PUT /v1/subtasks/{subtaskId}/assignee
Assign a subtask to a project member, or pass null to unassign.
JSON body:
| Field | Type | Required | Description |
|---|---|---|---|
assigneeId |
uuid | null |
yes | userId of a project member, or null to unassign. |
agent |
string |
no | Name of the agent making this call (e.g. "instinct"). Shown in the project's activity feed. |
Returns 200 with Subtask.
Links and updates
POST /v1/tasks/{taskId}/links
Attach a link (docs, PR, reference) to a task.
JSON body:
| Field | Type | Required | Description |
|---|---|---|---|
url |
url |
yes | An http(s) URL. |
label |
string | null |
no | Optional display label. |
agent |
string |
no | Name of the agent making this call (e.g. "instinct"). Shown in the project's activity feed. |
Returns 201 with Link.
POST /v1/tasks/{taskId}/updates
Append a progress note to a task's timeline.
JSON body:
| Field | Type | Required | Description |
|---|---|---|---|
body |
string |
yes | |
agent |
string |
no | Name of the agent making this call (e.g. "instinct"). Shown in the project's activity feed. |
Returns 201 with Update.
Response models
Project
| Field | Type | Required | Description |
|---|---|---|---|
id |
uuid |
yes | |
name |
string |
yes | |
description |
string | null |
yes | |
extraData |
object | null |
yes | |
createdById |
uuid |
yes | |
createdAt |
timestamp |
yes | |
updatedAt |
timestamp |
yes |
ProjectWithRole
| Field | Type | Required | Description |
|---|---|---|---|
id |
uuid |
yes | |
name |
string |
yes | |
description |
string | null |
yes | |
extraData |
object | null |
yes | |
createdById |
uuid |
yes | |
createdAt |
timestamp |
yes | |
updatedAt |
timestamp |
yes | |
role |
owner | member |
yes |
ProjectDetail
| Field | Type | Required | Description |
|---|---|---|---|
id |
uuid |
yes | |
name |
string |
yes | |
description |
string | null |
yes | |
extraData |
object | null |
yes | |
createdById |
uuid |
yes | |
createdAt |
timestamp |
yes | |
updatedAt |
timestamp |
yes | |
links |
object[] |
yes |
ProjectLink
| Field | Type | Required | Description |
|---|---|---|---|
id |
uuid |
yes | |
projectId |
uuid |
yes | |
url |
string |
yes | |
label |
string | null |
yes | |
createdAt |
timestamp |
yes |
Member
| Field | Type | Required | Description |
|---|---|---|---|
userId |
uuid |
yes | |
email |
string |
yes | |
role |
owner | member |
yes |
Invite
| Field | Type | Required | Description |
|---|---|---|---|
code |
string |
yes | |
projectId |
uuid |
yes | |
expiresAt |
timestamp |
yes |
InviteAcceptance
| Field | Type | Required | Description |
|---|---|---|---|
project |
object |
yes | |
alreadyMember |
boolean |
yes | True if the caller was already a member; the code isn't used up. |
Task
| Field | Type | Required | Description |
|---|---|---|---|
id |
uuid |
yes | |
projectId |
uuid |
yes | |
createdById |
uuid |
yes | |
assigneeId |
uuid | null |
yes | |
title |
string |
yes | |
description |
string | null |
yes | |
priority |
low | mid | high |
yes | |
bucket |
backlog | up_next | in_progress | done |
yes | |
tags |
string[] |
yes | |
extraData |
object | null |
yes | |
createdAt |
timestamp |
yes | |
updatedAt |
timestamp |
yes | |
completedAt |
timestamp | null |
yes | Set when the task enters the done bucket; cleared if it leaves. |
TaskDetail
| Field | Type | Required | Description |
|---|---|---|---|
id |
uuid |
yes | |
projectId |
uuid |
yes | |
createdById |
uuid |
yes | |
assigneeId |
uuid | null |
yes | |
title |
string |
yes | |
description |
string | null |
yes | |
priority |
low | mid | high |
yes | |
bucket |
backlog | up_next | in_progress | done |
yes | |
tags |
string[] |
yes | |
extraData |
object | null |
yes | |
createdAt |
timestamp |
yes | |
updatedAt |
timestamp |
yes | |
completedAt |
timestamp | null |
yes | Set when the task enters the done bucket; cleared if it leaves. |
todos |
object[] |
yes | |
links |
object[] |
yes | |
updates |
object[] |
yes |
Subtask
| Field | Type | Required | Description |
|---|---|---|---|
id |
uuid |
yes | |
taskId |
uuid |
yes | |
assigneeId |
uuid | null |
yes | |
text |
string |
yes | |
done |
boolean |
yes | |
extraData |
object | null |
yes | |
createdAt |
timestamp |
yes | |
completedAt |
timestamp | null |
yes |
Link
| Field | Type | Required | Description |
|---|---|---|---|
id |
uuid |
yes | |
taskId |
uuid |
yes | |
url |
string |
yes | |
label |
string | null |
yes | |
createdAt |
timestamp |
yes |
Update
| Field | Type | Required | Description |
|---|---|---|---|
id |
uuid |
yes | |
taskId |
uuid |
yes | |
body |
string |
yes | |
seq |
integer |
yes | Monotonic insert order within the feed. |
createdById |
uuid | null |
yes | |
agent |
string | null |
yes | |
createdAt |
timestamp |
yes |