Skip to content

Create a test plan

POST
/v1/plans
curl --request POST \
--url https://beta-api.plune.ai/v1/plans \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '{ "title": "Release regression", "description": "Everything under checkout, plus every critical case wherever it lives.", "kind": "mixed", "collections": [ "suiteId=6f1c2b3a-0000-4000-8000-0000000000a1", "priority=critical" ] }'

A title, a kind and one to twenty collections. Each collection is a case filter as a query string; it is read through the filter contract, so an unknown priority or state is refused with the filter’s own sentence (400), and written back canonical. The title is unique within the project (409 otherwise).

Media type application/json
object
title
required
string
>= 1 characters <= 200 characters
description
string
nullable
kind
required
string
Allowed values: manual automated mixed
asManual
boolean
collections
required
Array<string>
>= 1 items <= 20 items
Example
{
"title": "Release regression",
"description": "Everything under checkout, plus every critical case wherever it lives.",
"kind": "mixed",
"collections": [
"suiteId=6f1c2b3a-0000-4000-8000-0000000000a1",
"priority=critical"
]
}

Created

Media type application/json

A titled collection of case filters. A plan is a query, not a list of ids: what it collects is resolved when asked (GET /v1/plans/{id}/cases), and a launch turns that into a run.

object
id
required
string format: uuid
projectId
required
string
title
required

Unique within the project.

string
>= 1 characters <= 200 characters
description
required

Up to 16 384 bytes.

string
nullable
kind
required

Who executes it and which cases it may collect: manual takes manual cases, automated automated ones, mixed both. Evals belong to no plan.

string
Allowed values: manual automated mixed
asManual
required

The one exception to the strict mapping: a manual plan that also takes automated cases, to be walked by a person.

boolean
collections
required

Each item is a case filter in its query-string form (suiteId=…&tag=…&priority=…&priorityMin=…&type=…&state=…&q=…, ADR 0001) — AND between its dimensions, OR within one, OR between collections. Written back canonical, so two spellings of one filter are one string. An empty string is every case.

Array<string>
>= 1 items <= 20 items
createdAt
required
string format: date-time
updatedAt
required
string format: date-time
Example
{
"id": "6f1c2b3a-0000-4000-8000-0000000000f3",
"projectId": "u-shop::default",
"title": "Release regression",
"description": "Everything under checkout, plus every critical case wherever it lives.",
"kind": "mixed",
"asManual": false,
"collections": [
"suiteId=6f1c2b3a-0000-4000-8000-0000000000a1",
"priority=critical"
],
"createdAt": "2026-09-16T09:12:04.151Z",
"updatedAt": "2026-09-16T09:12:04.151Z"
}

Invalid body — a missing title, no collections, or a filter value outside its vocabulary

Media type application/json
object
error
required
string
Example
{
"error": "validation failed — collections.1: unknown priority \"urgent\" — priorities are low, normal, important, high, critical"
}

No / invalid token or session

A plan of that title exists

Media type application/json
object
error
required
string
Example
{
"error": "a plan titled 'Release regression' already exists"
}

Rate-limited: either the per-route throttle or a tenant quota. Retry-After carries the seconds until the window rolls over.

Media type application/json
object
error
required
string
Example generated
{
"error": "example"
}
Retry-After
integer

Seconds until the window rolls over