Skip to main content

Wire contract

The server keeps these payloads backwards-compatible; their shape is part of the Costpilot API contract.

POST /v1/session-map​

Sent by the hook on every prompt, and again when the turn ends:

{
"session_id": "<session id of the tool>",
"issue_id": "PROJ-123",
"branch": "feature/PROJ-123-login",
"repo": "owner/name",
"agent": "claude-code",
"project_key": "PLAT",
"reported_at": "2026-10-23T09:12:44.120Z"
}
  • session_id and issue_id are required; everything else is optional. The server answers 200 {} or 400 {}.
  • agent is claude-code, gemini, codex or cursor. session_id is whatever id the tool also puts on its telemetry: Claude Code and Gemini CLI session.id, Codex conversation.id, Cursor conversation_id.
  • event is absent (or prompt) on a prompt report and stop on a turn-end report; unknown values are accepted and create no turn. Each prompt report is stored as one turn of its session; reports for the same session within 5 seconds (by reported_at) count once. A stop report marks the end of a turn and creates none: when it names another branch than the turn started on, the turn and everything recorded for it move to that branch. Agents send stop only to servers whose agent config says turnEndReports: true.
  • reported_at is the reporting machine's clock (ISO). It becomes the turn's time, so prompts and model calls line up even when machine and server disagree about the time. Without it the server uses its own clock.
  • Without a recognisable issue id the hook sends the branch name (cut to 20 characters plus … when longer) as issue_id. The server keeps it as the branch dimension and counts the usage as "No issue".
  • Issue id pattern: the project's issueKeyPattern from the central config when the session belongs to a project that has one, otherwise the server's defaultIssueKeyPattern, otherwise the built-in [A-Z][A-Z0-9]+-\d+(?:\.\d+)*.
  • repo is sent with every mapping, also on a branch without an issue key: the server derives the project from the repository when the issue key matches no project.
  • project_key is sent when the session belongs to a project by repository, and always when --project-key is set (an unknown key is reported as is). It lands in the metadata of the session's calls.
  • When the server sets COSTPILOT_INGEST_TOKEN, the request carries Authorization: Bearer <secret>.
  • The request times out after 1.5 seconds. Errors are swallowed and the hook always exits 0. A hook must never block the tool.

GET /v1/agent-config​

Read by the hook before each report (cached for 5 minutes, 1 second request timeout; on errors the cached answer is used, a 404 from an older server is cached as "no config"). See Central configuration for the payload. GET /v1/projects/:projectKey returns one project in the same shape, 404 for an unknown key.

Telemetry​

The tools themselves send OTLP JSON to POST /v1/logs and POST /v1/metrics. The attributes Costpilot reads per emitter are described in the telemetry data model. A pipeline that runs without the hook passes attribution through OTEL_RESOURCE_ATTRIBUTES instead, see Agents in CI pipelines.