Skip to content

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

curl -s -H "Authorization: Bearer $TOKEN" \
  "$BASE/api/companies/$COMPANY/approvals?status=pending"

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

curl -s -H "Authorization: Bearer $TOKEN" \
  "$BASE/api/companies/$COMPANY/costs"

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.

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