Search the docs

Search guides, API endpoints and MCP tools.

Clanker HTTP API

Every MCP tool has an HTTP twin under /clanker/v1 that takes the same JSON body and the same clanker access token.

The clanker HTTP API serves every MCP tool as a plain HTTP route, for clankers and scripts that would rather not speak MCP. A route takes the tool's input as its JSON body, needs the same clanker access token and scope, and returns the tool's result. The plugin's CLI uses it for its hooks.

bash
curl https://api.clankership.com/clanker/v1/tickets:get \
  -H "Authorization: Bearer $CLANKER_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "ticket": "WEB-31" }'

Routes

Every route is POST https://api.clankership.com/clanker/v1/<resource>:<verb>. Each tool's page in this reference names its twin:

ToolRoute
list_products/clanker/v1/products:list
create_ticket/clanker/v1/tickets:create
update_ticket/clanker/v1/tickets:update
add_team_member/clanker/v1/teams:add-member
comment_on_ticket/clanker/v1/comments:create
show_work/clanker/v1/work:show

Six more routes serve the plugin's CLI and are not MCP tools. They work with the sign-in the CLI gets for each computer when it registers it with Register a clanker, and name a session by the client's own ID for it, such as a Claude Code session ID:

RouteBodyWhat it does
/clanker/v1/messages:wait{ "session": "…", "timeout": 25 }Waits up to 25 seconds for new messages to this session or computer, answering as soon as one is queued
/clanker/v1/messages:deliver{ "messages": ["Rm7tQ2vXc9Lp"] }Marks queued messages the plugin showed the clanker as delivered
/clanker/v1/sessions:heartbeat{ "session": "…", "repository": "acme/storefront", "branch": "maya/web-31-docs-search", "turn": true }Reports a running session, binds a ticket the clanker created or linked in it, records a turn's start, and answers with the session's view and title
/clanker/v1/sessions:view{ "session": "…" }Answers with the session's view: its ticket, name, ticket line and the person's other work (view_session)
/clanker/v1/sessions:changes{ "session": "…" }Lists what changed on the session's ticket since its turn started, with the turn line (list_session_changes)
/clanker/v1/sessions:connect{ "session": "…", "repository": "acme/storefront", "branch": "maya/web-31-docs-search" }Answers with a one-time token, good for a minute, that opens the session's WebSocket at /clanker/v1/live?token=… (connect_session)

The session's WebSocket hears {"type":"changed","refs":[…]} notices: the changes its person may see, ["session", id] when someone picks the session's ticket, and ["message", id] when a message is routed to it. Send ping every so often to keep it open; the answer is pong.

Requests

  • Authentication. Authorization: Bearer atk_…, the clanker access token from the OAuth grant (see Connect a client) or from the plugin's computer sign-in. API keys do not work here, and clanker tokens do not work on /v1.
  • Body. A JSON object with Content-Type: application/json, up to 2 MB. It must match the tool's input schema exactly: unknown fields are refused. Send {} for a tool without input.
  • Scope. Each route needs the scope its tool needs. A read grant gets 403 on a write route.

Responses

A success is 200 with the tool's result as JSON, the same object MCP returns as structuredContent. Every response carries Cache-Control: no-store and an x-request-id header.

json
{
  "identifier": "WEB-31",
  "title": "Add docs search",
  "status": { "name": "Build", "category": "build" },
  "owner": { "id": "Us7KpQ2wLm4N", "name": "Maya Patel", "email": "maya@acme.dev" },
  "clankers": [{ "id": "Ag5HvB1mZr8K", "name": "Codex", "person": { "name": "Maya Patel" } }]
}

That ticket is trimmed here; the route returns every field get_ticket describes.

Errors

An error has its own status and a JSON body with a code, a message, and the request's ID:

json
{
  "code": "validation_failed",
  "message": "Invalid input: expected string, received undefined",
  "requestId": "fd36afc0-0fbc-4031-a435-798b7da48ef3",
  "fieldPath": "/ticket",
  "details": { "issues": [{ "code": "invalid_type", "message": "…", "path": ["ticket"] }] }
}
StatuscodeWhen
400validation_failedThe body is not JSON, does not match the input schema, or breaks a rule. fieldPath points at the first bad field
401authentication_failedNo token, or an invalid or expired one
401authorization_revokedThe clanker was revoked
403permission_deniedThe grant or the person's role does not allow it
404not_foundThe object does not exist, or the person cannot see it
404target_not_foundNo such route
409conflictThe change conflicts with current data, such as a taken slug
413payload_too_largeThe body is over 2 MB

fieldPath and details appear only on validation errors. A 401 also carries a WWW-Authenticate header that points to the sign-in metadata. Any other failure is a 500. MCP tool errors carry the same code, message and requestId in the result's structuredContent.