Docs

Trunk's business operations are declared in one registry that drives the HTTP API, generated references, MCP tools and TypeScript client. Protocol surfaces such as delegated MCP OAuth intentionally live outside the /v1 operation registry and are documented alongside those generated surfaces.

One registry, four surfaces

Each business operation is declared once, in src/api/operations.ts, with its schema, its handler and the name it takes as an MCP tool. The HTTP route table, the OpenAPI document, the tool definitions and the TypeScript client are all derived from that declaration. Protocol endpoints such as OAuth discovery, authorization and token exchange stay outside this business-operation registry on purpose.

SurfaceWhat it isWhere
HTTP API49 operations under /v1, JSON in and out.openapi.json
MCP server27 of those operations as tools an agent can call directly. The other 22 are human-only.mcp.json
TypeScript clientGenerated from the same schemas, with the response types the server is compile-checked to return.trunk-client.ts
This UIA client of the API like any other. It has no privileged path into the system.you are here

The API reference is grouped the way the system is: identity, changes, the decision queue, repositories, policy, source, the trunk log, agents, api keys, events, statistics, accounts and sessions, externalci, deployments, checks.

Credentials

Most /v1 calls use human session tokens or agent API keys; sign-up and sign-in are the public business-operation exceptions. Remote MCP clients may instead use a delegated OAuth bearer bound to /mcp, which is not generic /v1 authority.

Authorization: Bearer <agent-key-or-session-token>
  • Agent keys are issued when an agent is registered and shown exactly once. Trunk stores a digest, so a lost key is replaced, never recovered.
  • Session tokens come from POST /v1/auth/signin and expire. The browser holds one in a cookie, which is why the dashboard API console works without you pasting anything.
  • Delegated MCP OAuth lets a compatible remote client authorize through Trunk sign-in and consent instead of receiving an agent key. The resulting bearer is resource-bound to /mcp and is deliberately separate from generic /v1 authority. See Remote OAuth clients.
  • Agent scopes constrain the operations that explicitly enforce repository, service, path and action authority. They do not replace the tenant/repository boundary used by ordinary repository and source reads. Registering agents, granting scope, setting budgets and issuing keys remain human-only operations.
  • Most business operations require authenticated authority. POST /v1/auth/signup and POST /v1/auth/signin are the public /v1 exceptions. OAuth discovery, registration, authorization, token and revocation are separate protocol routes with their own OAuth validation; OAuth access tokens are accepted only by the protected /mcp resource.

Connect an agent

Over HTTP against this deployment, or over stdio against a checkout you run yourself. Both transports feed the same dispatcher, so the tools behave identically.

# against this deployment with an existing agent key
claude mcp add --transport http trunk https://app.trunk.dev/mcp \
  --header "Authorization: Bearer $AGENT_KEY"

# against a local checkout, over stdio
# run from the repository root; AGENT_KEY and DATABASE_URL are already set
claude mcp add \
  --env TRUNK_API_KEY="$AGENT_KEY" \
  --env DATABASE_URL="$DATABASE_URL" \
  --transport stdio trunk \
  -- npm --prefix "$PWD" run mcp

Run the local command from the repository root. Your shell expands $PWD while registering the server, so Claude stores the exact checkout path and later MCP starts do not depend on Claude's working directory. The root npm entrypoint delegates to the dashboard MCP server. DATABASE_URL selects the Trunk Postgres database. The stdio process can start without TRUNK_API_KEY, but tool calls require a valid agent key.

OAuth-capable remote MCP clients can instead connect to https://app.trunk.dev/mcp through discovery and Trunk's sign-in/consent flow without a pre-created agent key. The MCP OAuth guide explains the delegated authority boundaries.

Prefer plain HTTP? The generated client takes an agent key or session token — new TrunkClient({ baseUrl, apiKey }) — and every operation is a method on it. Delegated OAuth bearers are intentionally not generic client credentials for /v1.

How a change lands

There is no pull request to open and no queue to sit in. A Change is proposed complete onto a branch of its own; policy, author readiness and required evidence then independently determine when that exact revision may land.

  1. Ask what you may do. trunk_whoami returns your scopes, your remaining budget and your measured record per service — the same numbers policy is about to use.
  2. Propose the whole change. Intent, the spec you worked to, the diff, the results you observed and your session trace, in one call to POST /v1/changes. Name a branch or let Trunk derive one; either way the Change lives there until it lands. A proposal may intentionally hold its exact current revision as Draft; non-Draft work keeps the ordinary automatic-landing behavior.
  3. Trunk derives its own evidence. It parses the diff and runs its verifiers over it rather than taking your word for what changed. Anything you reported is recorded as self-reported and weighted as such.
  4. Policy routes it. Risk is scored against your track record in that service; the repo's rules decide between landing unattended, a human review, the service owner, or a block.
  5. Draft does not stop evidence. Verification, required checks, CI and Preview may continue while the exact current revision is Draft. The author-controlled hold only prevents that Draft revision from receiving new landing authority.
  6. Ready releases only the author's hold. Only the exact author may mark the exact current Draft revision Ready. Ready does not approve the Change or bypass policy, checks, Preview, freshness, verification or repository publication; it simply lets that revision re-enter the ordinary landing lifecycle.
  7. Revise on the same branch. Propose again with the same branch and you revise the one Change — same id, same thread of evidence and decisions — instead of opening a second one beside it. Each revision is its own immutable candidate for CI to fetch, and a new content revision does not inherit Ready authority from the revision before it.
  8. A decision is bound to the evidence. Approval cites an evidence digest; if the diff moves, the approval goes stale rather than silently covering something nobody read.

When a call fails

Errors are JSON, with a stable code and — for a schema failure — the exact paths that did not validate.

StatusCodeMeans
400invalid_requestThe body or query did not match the operation schema. `details` lists each path and message.
400invalid_jsonThe body was not JSON.
401unauthenticatedNo credential, or one Trunk could not resolve.
403forbiddenOut of scope for this actor — a path, a service, or an operation reserved for humans.
403suspendedThe actor exists but is suspended.
404not_foundNo such operation, or no such record.
409conflictStale evidence, a missing approval, or a change already blocked or landed.