Get a plan
Returns one plan with its tasks in order. Once the plan runs, each task shows the ticket it became and the run working on it (run_id), which you can follow with GET /api/runs/{run_id}.
api_key viewAuthorizationBearer <token>A team API key, made by an admin under Settings, API keys. Send it as Authorization: Bearer chk_....
Scope: view
plan_id*stringThe plan's id.
The plan and its tasks.
application/json- response
A plan with its tasks.
chat_id?|The plan chat it came from.
"01JB8TZ6C8E0G2J4L6N8Q0S2U4"created_at?|When it was made (RFC 3339).
"2026-10-22T13:40:00+00:00"description?|More about it, in Markdown.
"Brute-force attempts are showing up in the auth logs."destination?|github or jira: where its tasks become tickets.
"github"executed_at?|When it started running (RFC 3339).
"2026-10-22T13:55:00+00:00"executed_by?|Who started it running.
"octocat"mcp_servers?array<string>|MCP servers used while planning.
[ "docs-search"]plan_id?|The plan's id.
"01JB8V0K3M5P7R9T1W3Y5A7C9E"repo?|The repository its tasks work in, owner/name.
"acme/web"status?|draft, executing or completed.
"draft"task_count*integerHow many tasks it has.
int640 <= value3title?|What the plan is for.
"Rate-limit the login form"tokens_in?|Input tokens its runs used so far.
int640 <= value412300tokens_out?|Output tokens its runs used so far.
int640 <= value38120updated_at?|When it last changed (RFC 3339).
"2026-10-22T13:55:00+00:00"tasks*array<>The plan's tasks, in order.
curl -X GET 'https://api.coderhelm.com/api/plans/01JB8V0K3M5P7R9T1W3Y5A7C9E' \ -H "Authorization: Bearer $CODERHELM_API_KEY"{ "chat_id": "01JB8TZ6C8E0G2J4L6N8Q0S2U4", "created_at": "2026-10-22T13:40:00+00:00", "description": "Brute-force attempts are showing up in the auth logs.", "destination": "github", "executed_at": "2026-10-22T13:55:00+00:00", "executed_by": "octocat", "mcp_servers": [ "docs-search" ], "plan_id": "01JB8V0K3M5P7R9T1W3Y5A7C9E", "repo": "acme/web", "status": "draft", "task_count": 3, "title": "Rate-limit the login form", "tokens_in": 412300, "tokens_out": 38120, "updated_at": "2026-10-22T13:55:00+00:00", "tasks": [ { "acceptance_criteria": "The 11th attempt within 15 minutes gets 429 and a Retry-After header.", "approved_at": "2026-10-22T13:54:10+00:00", "approved_by": "octocat", "created_at": "2026-10-22T13:40:00+00:00", "depends_on": null, "description": "Allow 10 attempts per IP per 15 minutes; answer 429 after that.", "destination": "github", "issue_number": 412, "issue_url": "https://github.com/acme/web/issues/412", "jira_project": null, "jira_ticket_key": null, "jira_ticket_url": null, "order": 0, "plan_id": "01JB8V0K3M5P7R9T1W3Y5A7C9E", "pr_url": "https://github.com/acme/web/pull/318", "rejected_at": null, "rejected_by": null, "repo": "acme/web", "run_id": "01JB8X6F4M2C9QZ3T7V5W1K0HA", "status": "queued", "task_id": "01JB8V0P8Q2S4U6W8Y0A2C4E6G", "title": "Limit login attempts per IP" } ]}Create a plan POST
Creates a plan, with its tasks if you send them. The plan and its tasks start as `draft`; nothing runs until the plan is executed. Not idempotent: sending the same request twice makes two plans.
Approve and run a plan POST
Approves every `draft` task of the plan and runs the plan: each approved task becomes a GitHub issue or Jira ticket and is queued as a run, in task order. The plan becomes `executing`. Rejected tasks are skipped. Answers `400` when no task is left to run, so calling it again after a successful call does not run anything twice.