Plans
Proposed work, scored and approved before anything is written.
Base path /api/v1/plans on https://ionwarp.com. Authenticate with Authorization: Bearer $DASH_API_KEY and name the project with the Project-ID header. Writes are validated in declared mode; an operation this resource does not declare answers 405 operation_not_supported.
List plans
GET /api/v1/plans
curl "https://ionwarp.com/api/v1/plans?status=discovered" \
-H "Authorization: Bearer $DASH_API_KEY" \
-H "Project-ID: pr_acme"Which plans are still waiting on my approval?data_query {
"collection": "plans",
"where": {
"status": "discovered"
}
}Returns a paginated list of plan objects, newest first.
{
"object": "list",
"data": [
{
"object": "plan",
"id": "obj_123",
"approval_status": "pending",
"repo_write_status": "not_requested",
"repo_artifact_path": "repo artifact path",
"target_outcome": "One retry ladder serves every webhook path.",
"summary": "Three near-identical retry ladders diverged; collapse them into the shared helper.",
"created_at": "2026-07-25T12:00:00.000Z",
"updated_at": "2026-07-25T12:00:00.000Z"
}
],
"has_more": false,
"next_cursor": null
}Parameters
| Parameter | Type | Kind | Description |
|---|---|---|---|
status | string | filter | Where the plan is in its life: found, proposed, reviewed, approved, being worked, finished, or replaced by a newer plan. One of discovered, proposed, reviewed, approved, active, completed, superseded. |
approval_status | string | filter | Whether a human has signed off on the plan yet. Nothing is written to your repository while this is pending. One of pending, approved, rejected. |
source_kind | string | filter | Where the plan came from: repo (a plan document already in the repository), ionwarp (proposed by a review), or task. One of repo, ionwarp, task. |
repo_write_mode | string | filter | How the plan is allowed to reach your repository. Only draft_pr exists — IonWarp never pushes to a branch directly. One of draft_pr. |
repo_write_status | string | filter | How far the repository write got: never asked for, requested, a draft PR was opened, or it failed. One of not_requested, draft_pr_requested, draft_pr_opened, failed. |
q | string | search | Free-text search across title, summary. |
sort | string | sort | One of created_at, updated_at, simplicity_score; prefix with - to reverse. |
limit | number | page | Rows to return, 1–100. Defaults to 20. |
cursor | string | page | next_cursor from the previous page. |
Retrieve a plan
GET /api/v1/plans/learning-tests-run-under-bun
curl "https://ionwarp.com/api/v1/plans/learning-tests-run-under-bun" \
-H "Authorization: Bearer $DASH_API_KEY" \
-H "Project-ID: pr_acme"Walk me through plan {id} and what it would changedata_get {
"collection": "plans",
"object_id": "learning-tests-run-under-bun"
}Returns the plan object.
{
"object": "plan",
"id": "obj_123",
"approval_status": "pending",
"repo_write_status": "not_requested",
"repo_artifact_path": "repo artifact path",
"target_outcome": "One retry ladder serves every webhook path.",
"summary": "Three near-identical retry ladders diverged; collapse them into the shared helper.",
"created_at": "2026-07-25T12:00:00.000Z",
"updated_at": "2026-07-25T12:00:00.000Z"
}Parameters
| Parameter | Type | Kind | Description |
|---|---|---|---|
id | string | path | The plan's id or slug. |
Append an event to a plan
POST /api/v1/plans/{id}/events
curl -X POST "https://ionwarp.com/api/v1/plans/learning-tests-run-under-bun/events" \
-H "Authorization: Bearer $DASH_API_KEY" \
-H "Project-ID: pr_acme" \
-H "Content-Type: application/json" \
-d '{"event":"Noted by the operator","context":{"source":"api"}}'Add a note to the plan {id}data_event {
"collection": "plans",
"object_id": "learning-tests-run-under-bun",
"event": "Noted by the operator"
}Returns the appended event object.
{
"object": "event",
"id": "evt_123",
"event": "Noted by the operator"
}Parameters
| Field | Type | Required | Description |
|---|---|---|---|
event | string | yes | The human-readable timeline entry. |
context | object | no | Provenance — source, integration, worker_run_id, … |
What comes back (read-only)
Every plan carries the envelope below. The fields under it are computed or stamped by the platform — they are returned, never sent.
| Field | Type | Description |
|---|---|---|
object | string | Always plan. |
id | string | Stable object id. Also accepted in place of slug on any path. |
slug | string | URL-safe name, unique within the collection. |
created_at | string | ISO-8601 timestamp of the first write. |
updated_at | string | ISO-8601 timestamp of the most recent write. The cursor sorts on this. |
title | string | Name of the plan. |
source_kind | string | Where the plan came from: repo (a plan document already in the repository), ionwarp (proposed by a review), or task. |
source_label | string | Human-readable origin of the plan — "Repository", "IonWarp Review", or the reviewer's own label. Falls back to source_kind when unset. |
status | string | Where the plan is in its life: found, proposed, reviewed, approved, being worked, finished, or replaced by a newer plan. |
approval_status | string | Whether a human has signed off on the plan yet. Nothing is written to your repository while this is pending. |
requires_approval | boolean | Whether this plan needs an explicit approval before it may write anything. |
repo_write_mode | string | How the plan is allowed to reach your repository. Only draft_pr exists — IonWarp never pushes to a branch directly. |
repo_write_status | string | How far the repository write got: never asked for, requested, a draft PR was opened, or it failed. |
repo_artifact_path | string | Path of the plan document in the repository (e.g. docs/plans/2026-07-14-liveness.md). This exact path is how a review is dispatched against the plan. |
repo_artifact_url | string | Link to repo_artifact_path on GitHub, once the file exists there. An IonWarp-authored plan has no repo file until its draft PR opens. |
target_outcome | string | What the repository should be true of once this plan is done. |
summary | string | Short markdown summary of the plan. |
simplicity_score | number | Simplicity score the proposing review attached to this plan. The scale is the reviewer's, not the platform's. |
legacy_review_score | number | Legacy-risk score the proposing review attached to this plan. The scale is the reviewer's, not the platform's. |
security_score | number | Security score the proposing review attached to this plan. The scale is the reviewer's, not the platform's. |
review_task_id | string | Task id of the review that proposed this plan. Absent means the plan is not linked to a review yet. |
evidence_anchors | string | Comma-separated references the reviewer cited as its basis, each \<kind>:\<id> (e.g. review:rev_1,learning:lrn_1). A proposal must carry at least two. |
linked_review_ids | string | Comma-separated ids of the reviews this plan was proposed from. Empty when the proposal cited none. |
linked_learning_ids | string | Comma-separated ids of the learnings rows this plan drew on. Empty when the proposal cited none. |
linked_scorecard_ids | string | Comma-separated slugs of the scorecards this plan is meant to improve (e.g. ai-readiness). Empty when the proposal cited none. |
related_fix_count | number | How many separate fixes the reviewer grouped into this plan. A proposal must cover at least two. |
plan_body | string | The plan document itself, as markdown. |
Errors
Failures use { error: { type, code, message, param } }. The full code table is generated at Error Codes.