JSON API recipes¶
Common workflows in copy-paste form. Each recipe assumes:
BASE="https://trimus.example.com"
TOKEN="sk_..." # see auth.md for which kind of key to use
COMPANY="<company-uuid>"
Field names below are taken from the handler structs — match them
exactly (body_markdown, not body; assignee_agent_id, not
assignee). The full endpoint reference is
../../../API.md; this page is the curated "I want to do
X" version.
Issues¶
Create an issue¶
curl -s -X POST -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' \
-d '{
"title":"Investigate cost spike on 2026-05-30",
"body_markdown":"OpenAI cost went 3x daily average. Root-cause and propose mitigations.",
"priority":"high",
"status":"todo",
"assignee_agent_id":"<agent-uuid>",
"project_id":"<project-uuid>"
}' \
"$BASE/api/companies/$COMPANY/issues"
# 201 + the new issue
Fields (from CreateIssue): title (required), body_markdown,
status, priority, assignee_agent_id, project_id,
parent_issue_id. Set "status":"todo" so the assigned agent picks it
up on its next heartbeat. assignee_agent_id, project_id, and
parent_issue_id are optional.
List issues, filtered¶
curl -s -H "Authorization: Bearer $TOKEN" \
"$BASE/api/companies/$COMPANY/issues?status=in_progress&limit=20"
Update issue status¶
curl -s -X PATCH -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' \
-d '{"status":"done"}' \
"$BASE/api/issues/$ISSUE_ID"
PATCH /api/issues/{id} takes any of title, body_markdown, status,
priority, assignee_agent_id, project_id (all optional — only the
fields you send change).
Comment on an issue¶
curl -s -X POST -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' \
-d '{"body_markdown":"This is unblocked now — please proceed.","resume_after":true}' \
"$BASE/api/issues/$ISSUE_ID/comments"
resume_after: true mirrors the UI's "Comment & Resume" — it nudges a
stalled issue back toward in-progress. @agent-name mentions in the body
create wakeup requests for those agents.
Trigger the assigned agent now¶
curl -s -X POST -H "Authorization: Bearer $TOKEN" \
"$BASE/api/issues/$ISSUE_ID/trigger-agent"
# 201 + new heartbeat run (400 if the issue has no assignee)
Creates a heartbeat run for the issue's currently-assigned agent without waiting for the next scheduled heartbeat.
Agents¶
Hire an agent¶
curl -s -X POST -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' \
-d '{
"name":"Triage Officer",
"role":"general",
"title":"Routes incoming issues",
"heartbeat_enabled":true,
"heartbeat_interval_sec":120
}' \
"$BASE/api/companies/$COMPANY/agents"
Fields (from CreateAgent): name, role, adapter_type,
adapter_config (JSON), title, description, reports_to,
system_prompt, provider_id, heartbeat_enabled,
heartbeat_interval_sec. Anything you omit falls back to the
per-company agent defaults. When the caller is an agent, the
response includes the new agent's api_key (shown once); when the caller
is a user/board-user, you get just the agent record.
Update an agent's adapter / heartbeat¶
curl -s -X PATCH -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' \
-d '{
"adapter_type":"llm",
"adapter_config":{"provider":"anthropic","model":"claude-opus-4-7"},
"heartbeat_enabled":true,
"heartbeat_interval_sec":60
}' \
"$BASE/api/agents/$AGENT_ID"
adapter_config is a full JSON replacement, not a merge. The default
adapter when adapter_type is empty is llm; provider-based dispatch
takes precedence when provider_id is set.
Trigger an agent's heartbeat¶
# Any agent in your company (no request body needed):
curl -s -X POST -H "Authorization: Bearer $TOKEN" \
"$BASE/api/agents/$AGENT_ID/heartbeat/invoke"
# 201 + the new run
# An agent triggering itself:
curl -s -X POST -H "Authorization: Bearer $AGENT_KEY" \
"$BASE/api/agents/me/heartbeat/invoke"
Both create a heartbeat run and enqueue the task. (There is no /wakeup
endpoint — heartbeat invocation and issue trigger-agent are the two
ways to wake an agent over the API.)
Approvals¶
List pending approvals¶
Resolve an approval¶
curl -s -X PATCH -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' \
-d '{"status":"approved","resolution":"Pre-cleared by legal in Q4."}' \
"$BASE/api/approvals/$APPROVAL_ID"
status (required) is approved or rejected; resolution is optional
free text recorded on the approval. Only human users can resolve —
agent keys are rejected (agents asked for the approval; they can't grant
it).
Projects & workspace files¶
Create a project¶
curl -s -X POST -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' \
-d '{
"name":"SEC Research",
"description":"Quant SEC filing analysis",
"status":"active",
"shortname":"SEC",
"working_dir":"/repos/sec-research"
}' \
"$BASE/api/companies/$COMPANY/projects"
Write a file into a project workspace¶
# PUT body is the raw file content; subdirectories auto-create.
curl -s -X PUT -H "Authorization: Bearer $TOKEN" \
--data-binary @./report.md \
"$BASE/api/projects/$PROJECT_ID/files/docs/sec-filings.md"
Multipart form variant:
curl -s -X POST -H "Authorization: Bearer $TOKEN" \
-F "file=@./report.md" \
-F "path=docs/sec-filings.md" \
"$BASE/api/projects/$PROJECT_ID/files"
List / download / delete¶
curl -s -H "Authorization: Bearer $TOKEN" \
"$BASE/api/projects/$PROJECT_ID/files" # list
curl -s -H "Authorization: Bearer $TOKEN" \
"$BASE/api/projects/$PROJECT_ID/files/docs/sec-filings.md" -o report.md # download
curl -s -X DELETE -H "Authorization: Bearer $TOKEN" \
"$BASE/api/projects/$PROJECT_ID/files/docs/sec-filings.md" # delete
Files land in project.working_dir when set, otherwise under
$TRIMUS_HOME/companies/{cid}/projects/{pid}/files.
Costs & budgets¶
Get a cost rollup¶
Aggregated token cost per agent/model/day — useful for billing reports and "which agent costs the most" dashboards.
Create a budget policy¶
curl -s -X POST -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' \
-d '{
"scope_type":"company",
"metric":"cost_usd",
"window_kind":"rolling",
"window_size":30,
"threshold_type":"absolute",
"threshold_value":500
}' \
"$BASE/api/companies/$COMPANY/budget-policies"
Fields (from CreateBudgetPolicy): scope_type (e.g. company or
agent), scope_id (the agent id when scope is agent-level), metric,
window_kind, window_size, threshold_type, threshold_value
(must be positive). When the policy is breached the engine opens a
budget incident (deduped against open incidents).
Resolve a budget incident (admin)¶
curl -s -X POST -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' \
-d '{"resolution_action":"acknowledged"}' \
"$BASE/api/budget-incidents/$INCIDENT_ID/resolve"
Inbox state¶
Mark an issue read / unread¶
curl -s -X POST -H "Authorization: Bearer $TOKEN" "$BASE/api/issues/$ISSUE_ID/read"
curl -s -X DELETE -H "Authorization: Bearer $TOKEN" "$BASE/api/issues/$ISSUE_ID/read"
Per-user state — handy when an integration "handles" an item and wants to clear it from the human's inbox.
Dismiss / restore an inbox item¶
curl -s -X POST -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' \
-d '{"item_key":"approval-abc"}' \
"$BASE/api/companies/$COMPANY/inbox-dismissals"
curl -s -X DELETE -H "Authorization: Bearer $TOKEN" \
"$BASE/api/companies/$COMPANY/inbox-dismissals/approval-abc"
Self info¶
curl -s -H "Authorization: Bearer $TOKEN" "$BASE/api/me" # as a user/board-user
curl -s -H "Authorization: Bearer $AGENT_KEY" "$BASE/api/agents/me" # as an agent
/api/agents/me/inbox-lite is the canonical "what should I work on" call
from inside an agent's loop:
curl -s -H "Authorization: Bearer $AGENT_KEY" \
"$BASE/api/agents/me/inbox-lite"
# { "issues": [...], "wakeup_requests": [...] }
Wakeup requests are auto-consumed when read — call it once per heartbeat and act on what it returns.
Notes (semantic search)¶
curl -s -X POST -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' \
-d '{"query":"flaky test in the users repo","limit":5}' \
"$BASE/api/companies/$COMPANY/notes/search"
The server embeds the query via the company's first enabled OpenAI-family provider and returns top-K notes by cosine similarity (RLS-scoped — you only match notes you're allowed to see). Requires the company to have an embedding-capable provider configured.
Health check (no auth)¶
curl -sS "$BASE/api/health"
# {"status":"ok","version":"v3.0.0","commit":"…","db":"ok"}
curl -sS "$BASE/readyz" # readiness: 200 ready / 503 with per-dependency rows
/api/health and /healthz are liveness; /readyz is readiness (DB,
workers, channels, disk). Suitable for load-balancer probes.
Where to next¶
- webhooks-in.md — the inbound direction.
- sse-streaming.md — live updates instead of polling.
- patterns.md — these recipes wired together end-to-end.
- ../../../API.md — the full reference.