> For the complete documentation index, see [llms.txt](https://help.aximo.autify.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://help.aximo.autify.com/api-reference/triggers-plans.md).

# Triggers – Plans

Trigger test plan runs and poll their status.

## List plan runs across a project

> Lists a workspace's plan runs across all of its plans, newest first,\
> each carrying its plan's \`id\` and \`title\`. Archived (soft-deleted)\
> runs are excluded. Use this for run history; use\
> \`GET /api/triggers/plans/{planId}/runs/{planRunId}\` for one run's\
> per-case breakdown. A run's \`status\` is execution state, not the test\
> verdict: read \`passedCases\`/\`failedCases\` to judge outcomes. Paginate\
> by passing the previous page's \`nextCursor\` as \`cursor\`.<br>

```json
{"openapi":"3.0.3","info":{"title":"Aximo API","version":"1.0.0"},"tags":[{"name":"Triggers – Plans","description":"Trigger test plan runs and poll their status."}],"servers":[{"url":"/","description":"Current environment"}],"security":[{"ApiKeyAuth":[]}],"components":{"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"x-api-key","description":"Organization API key generated from Settings → API Keys."}},"schemas":{"ProjectPlanRunItem":{"allOf":[{"$ref":"#/components/schemas/PlanRunSummary"},{"type":"object","required":["planId","plan"],"properties":{"planId":{"type":"string","format":"uuid"},"plan":{"type":"object","required":["id","title"],"properties":{"id":{"type":"string","format":"uuid"},"title":{"type":"string"}}}}}]},"PlanRunSummary":{"type":"object","required":["id","status","triggerSource","executionMode","totalCases","completedCases","passedCases","failedCases","createdAt"],"properties":{"id":{"type":"string","format":"uuid"},"status":{"type":"string","enum":["created","running","completed","failed","cancelled"]},"triggerSource":{"type":"string","enum":["manual","scheduled","api"]},"executionMode":{"type":"string","enum":["parallel","sequential"],"description":"The effective mode this run executed with."},"totalCases":{"type":"integer"},"completedCases":{"type":"integer"},"passedCases":{"type":"integer"},"failedCases":{"type":"integer"},"startedAt":{"type":"string","format":"date-time","nullable":true},"completedAt":{"type":"string","format":"date-time","nullable":true},"createdAt":{"type":"string","format":"date-time"}}},"Error":{"type":"object","required":["error"],"properties":{"error":{"type":"string"}}}},"responses":{"Unauthorized":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"RateLimited":{"description":"Rate limit exceeded — e.g. the daily session limit was reached for the\norganization, or too many API requests were sent in a short window\n(retry after the number of seconds in the `Retry-After` header).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"InternalError":{"description":"Unexpected server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"paths":{"/api/plan-runs":{"get":{"operationId":"listProjectPlanRuns","summary":"List plan runs across a project","description":"Lists a workspace's plan runs across all of its plans, newest first,\neach carrying its plan's `id` and `title`. Archived (soft-deleted)\nruns are excluded. Use this for run history; use\n`GET /api/triggers/plans/{planId}/runs/{planRunId}` for one run's\nper-case breakdown. A run's `status` is execution state, not the test\nverdict: read `passedCases`/`failedCases` to judge outcomes. Paginate\nby passing the previous page's `nextCursor` as `cursor`.\n","tags":["Triggers – Plans"],"parameters":[{"name":"projectId","in":"query","required":true,"schema":{"type":"string","format":"uuid"},"description":"UUID of the workspace (project) to list runs for."},{"name":"planId","in":"query","required":false,"schema":{"type":"string","format":"uuid"},"description":"Restrict to a single plan's runs. A plan id from a different\nproject yields an empty list, not an error.\n"},{"name":"status","in":"query","required":false,"schema":{"type":"string","enum":["created","running","completed","failed","cancelled"]},"description":"Restrict to runs with this execution status."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":50,"default":10}},{"name":"cursor","in":"query","required":false,"schema":{"type":"string","format":"date-time"},"description":"Pagination cursor — the `nextCursor` value from the previous page\n(the `createdAt` of its last run, ISO 8601).\n"}],"responses":{"200":{"description":"Plan runs for the project, newest first.","content":{"application/json":{"schema":{"type":"object","required":["items"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/ProjectPlanRunItem"}},"nextCursor":{"type":"string","format":"date-time","description":"Present when more runs exist; pass it as `cursor` to fetch the next page."}}}}}},"400":{"description":"Invalid query parameters.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"description":"Project not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}}}}
```

## Trigger a plan run

> Starts a new run for the specified test plan. The plan must have \*\*API access enabled\*\*\
> in its settings.\
> \
> Cases run in parallel or one at a time according to the plan's Execution setting;\
> the optional \`executionMode\` body field overrides that setting for this run only,\
> and the response echoes the effective mode.\
> \
> The optional \`variables\` body field supplies per-run values for \`{{NAME}}\`\
> placeholders, overriding the plan's stored variables for this run only.\
> \
> Returns a \`planRunId\` — poll \`GET /api/triggers/plans/{planId}/runs/{planRunId}\`\
> to track overall progress.<br>

```json
{"openapi":"3.0.3","info":{"title":"Aximo API","version":"1.0.0"},"tags":[{"name":"Triggers – Plans","description":"Trigger test plan runs and poll their status."}],"servers":[{"url":"/","description":"Current environment"}],"security":[{"ApiKeyAuth":[]}],"components":{"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"x-api-key","description":"Organization API key generated from Settings → API Keys."}},"schemas":{"RunRequestError":{"type":"object","required":["error"],"properties":{"error":{"type":"string"},"availableModels":{"type":"array","items":{"type":"string"},"description":"Present when the request was rejected for its `model`: the models this\norganization can run, the same list `GET /api/models` returns.\n"}}},"Error":{"type":"object","required":["error"],"properties":{"error":{"type":"string"}}}},"responses":{"Unauthorized":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"RateLimited":{"description":"Rate limit exceeded — e.g. the daily session limit was reached for the\norganization, or too many API requests were sent in a short window\n(retry after the number of seconds in the `Retry-After` header).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"InternalError":{"description":"Unexpected server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"paths":{"/api/triggers/plans/{planId}/run":{"post":{"operationId":"triggerPlanRun","summary":"Trigger a plan run","description":"Starts a new run for the specified test plan. The plan must have **API access enabled**\nin its settings.\n\nCases run in parallel or one at a time according to the plan's Execution setting;\nthe optional `executionMode` body field overrides that setting for this run only,\nand the response echoes the effective mode.\n\nThe optional `variables` body field supplies per-run values for `{{NAME}}`\nplaceholders, overriding the plan's stored variables for this run only.\n\nReturns a `planRunId` — poll `GET /api/triggers/plans/{planId}/runs/{planRunId}`\nto track overall progress.\n","tags":["Triggers – Plans"],"parameters":[{"name":"planId","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"UUID of the test plan to run."}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"model":{"type":"string","enum":["default","haiku","sonnet","kimi","gpt-5.4","gpt-5.4-mini","gpt-5.5","auto"],"description":"Model to use for all cases in this plan run. Call `GET /api/models` for\nthe values your organization can run — anything else is rejected with\n`400`, and the error carries the usable list in `availableModels`. When\nomitted, the `defaultModel` from that endpoint applies.\n"},"executionMode":{"type":"string","enum":["parallel","sequential"],"description":"Override the plan's stored Execution setting for this run only.\n`parallel` runs cases concurrently up to the organization's concurrency\nlimit; `sequential` runs one case at a time in plan order. When omitted,\nthe plan's setting applies (plans default to `parallel`). The plan's\nstop-on-failure option takes effect only when the effective mode is\n`sequential`.\n"},"mobileConfig":{"type":"object","description":"Override mobile device configuration for this run.","required":["deviceArn","deviceName"],"properties":{"deviceArn":{"type":"string","description":"Encrypted device token from `GET /api/devices`."},"deviceName":{"type":"string"},"platform":{"type":"string","enum":["ANDROID","IOS"]},"uploadArn":{"type":"string","description":"Encrypted upload token from `GET /api/uploads/{id}`."},"uploadType":{"type":"string","enum":["own_app","existing","sample"]},"appName":{"type":"string"},"apps":{"type":"array","maxItems":3,"description":"Up to 3 apps to install for mobile cases. Takes precedence over\nthe single-app fields (`uploadArn`/`uploadType`/`appName`); the\nfirst entry is the primary app.\n","items":{"type":"object","required":["uploadArn","uploadType","appName"],"properties":{"uploadArn":{"type":"string","description":"Encrypted upload token from `GET /api/uploads/{id}`."},"uploadType":{"type":"string","enum":["own_app","existing","sample"]},"appName":{"type":"string","nullable":true},"bundleId":{"type":"string"}}}}}},"desktopConfig":{"type":"object","description":"BYOD desktop devices to run this plan's desktop cases on; overrides\nthe plan's stored desktop configuration for this run. Device\nmetadata (name, platform, OS) is re-resolved server-side from the\ndevice registry, and each device's availability is checked before\nthe run starts. Requires the BYOD feature to be enabled for your\norganization. All devices must be desktop devices (`windows`,\n`macos`, or `linux`) registered via `POST /api/devices/register`.\n","required":["devices"],"properties":{"devices":{"type":"array","minItems":1,"items":{"type":"object","required":["userDeviceId"],"properties":{"userDeviceId":{"type":"string","format":"uuid","description":"ID of a registered device from `GET /api/devices/user`."}}}}}},"variables":{"type":"array","maxItems":100,"description":"Variable values for this run only — never persisted on the plan.\nEach entry is merged over the plan's stored variables by name and\nfills the matching `{{NAME}}` placeholder in case scenarios;\nnames not referenced by any case in the plan are ignored. See\n`GET /api/plans/{planId}` for the plan's stored variables.\n\nIf a name is registered as a **secret** in the workspace (or is a\nstored secret plan variable), the supplied value is encrypted at\nrest, handled as a secret during the run, and never echoed back.\nSending the literal mask `***` for such a name keeps the current\nsecret value (the plan's stored override, or the workspace secret\nwhen no override is stored).\n","items":{"type":"object","required":["name","value"],"properties":{"name":{"type":"string","maxLength":128,"pattern":"^[A-Z][A-Z0-9_]*$","description":"Variable name — uppercase, starts with a letter, letters/\ndigits/underscores only. Duplicate names are rejected.\n"},"value":{"type":"string","maxLength":10000}}}}}}}}},"responses":{"201":{"description":"Plan run triggered.","content":{"application/json":{"schema":{"type":"object","required":["success","planRunId","totalCases","executionMode"],"properties":{"success":{"type":"boolean"},"planRunId":{"type":"string","format":"uuid"},"totalCases":{"type":"integer","description":"Number of test cases in this plan run."},"executionMode":{"type":"string","enum":["parallel","sequential"],"description":"The effective mode this run executes with (the request override if given, otherwise the plan's stored setting)."}}}}}},"400":{"description":"Invalid request body — including a `model` this organization cannot run\n(the response then carries `availableModels`), or `desktopConfig` devices\nthat do not belong to the organization or are not desktop devices. The\ndevice checks also apply to the plan's stored desktop configuration when\n`desktopConfig` is omitted (e.g. a bound device that was since\nunregistered).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RunRequestError"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"API access is not enabled for this plan; BYOD desktop devices were\nrequested (in the body or via the plan's stored desktop configuration)\nwhile BYOD is not enabled for the organization; or the plan contains\nmulti-device test cases while that feature is not enabled.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Test plan not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"412":{"description":"One or more requested BYOD desktop devices are not currently\navailable. `details.unavailableDevices` lists each one with a\n`reason` of `offline` (device agent not connected) or `unknown`\n(device status could not be determined). Also applies when the\nplan's stored desktop configuration references unavailable devices.\n","content":{"application/json":{"schema":{"type":"object","required":["error","details"],"properties":{"error":{"type":"string"},"details":{"type":"object","required":["unavailableDevices"],"properties":{"unavailableDevices":{"type":"array","items":{"type":"object","required":["userDeviceId","name","reason"],"properties":{"userDeviceId":{"type":"string","format":"uuid"},"name":{"type":"string"},"reason":{"type":"string","enum":["offline","unknown"]}}}}}}}}}}},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}}}}
```

## List plan runs

> Lists a plan's runs, newest first, without per-case detail. Use\
> \`GET /api/triggers/plans/{planId}/runs/{planRunId}\` for the per-case\
> breakdown of a single run. Paginate by passing the previous page's\
> \`nextCursor\` as \`cursor\`. Archived (soft-deleted) runs are excluded;\
> they remain readable via the by-id endpoint, flagged by \`archivedAt\`.<br>

```json
{"openapi":"3.0.3","info":{"title":"Aximo API","version":"1.0.0"},"tags":[{"name":"Triggers – Plans","description":"Trigger test plan runs and poll their status."}],"servers":[{"url":"/","description":"Current environment"}],"security":[{"ApiKeyAuth":[]}],"components":{"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"x-api-key","description":"Organization API key generated from Settings → API Keys."}},"schemas":{"PlanRunSummary":{"type":"object","required":["id","status","triggerSource","executionMode","totalCases","completedCases","passedCases","failedCases","createdAt"],"properties":{"id":{"type":"string","format":"uuid"},"status":{"type":"string","enum":["created","running","completed","failed","cancelled"]},"triggerSource":{"type":"string","enum":["manual","scheduled","api"]},"executionMode":{"type":"string","enum":["parallel","sequential"],"description":"The effective mode this run executed with."},"totalCases":{"type":"integer"},"completedCases":{"type":"integer"},"passedCases":{"type":"integer"},"failedCases":{"type":"integer"},"startedAt":{"type":"string","format":"date-time","nullable":true},"completedAt":{"type":"string","format":"date-time","nullable":true},"createdAt":{"type":"string","format":"date-time"}}},"Error":{"type":"object","required":["error"],"properties":{"error":{"type":"string"}}}},"responses":{"Unauthorized":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"RateLimited":{"description":"Rate limit exceeded — e.g. the daily session limit was reached for the\norganization, or too many API requests were sent in a short window\n(retry after the number of seconds in the `Retry-After` header).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"InternalError":{"description":"Unexpected server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"paths":{"/api/triggers/plans/{planId}/runs":{"get":{"operationId":"listPlanRuns","summary":"List plan runs","description":"Lists a plan's runs, newest first, without per-case detail. Use\n`GET /api/triggers/plans/{planId}/runs/{planRunId}` for the per-case\nbreakdown of a single run. Paginate by passing the previous page's\n`nextCursor` as `cursor`. Archived (soft-deleted) runs are excluded;\nthey remain readable via the by-id endpoint, flagged by `archivedAt`.\n","tags":["Triggers – Plans"],"parameters":[{"name":"planId","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"UUID of the test plan."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":50,"default":10},"description":"Maximum number of runs to return."},{"name":"cursor","in":"query","required":false,"schema":{"type":"string","format":"date-time"},"description":"Pagination cursor — the `nextCursor` value from the previous page\n(the `createdAt` of its last run, ISO 8601).\n"}],"responses":{"200":{"description":"Runs for the plan, newest first.","content":{"application/json":{"schema":{"type":"object","required":["items"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/PlanRunSummary"}},"nextCursor":{"type":"string","format":"date-time","description":"Present when more runs exist; pass it as `cursor` to fetch the next page."}}}}}},"400":{"description":"Invalid query parameters.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"description":"Test plan not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}}}}
```

## Get plan run status

> Returns the overall status and per-case breakdown of a plan run.

```json
{"openapi":"3.0.3","info":{"title":"Aximo API","version":"1.0.0"},"tags":[{"name":"Triggers – Plans","description":"Trigger test plan runs and poll their status."}],"servers":[{"url":"/","description":"Current environment"}],"security":[{"ApiKeyAuth":[]}],"components":{"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"x-api-key","description":"Organization API key generated from Settings → API Keys."}},"schemas":{"PlanRun":{"type":"object","required":["id","status","triggerSource","executionMode","totalCases","completedCases","passedCases","failedCases","createdAt","cases"],"properties":{"id":{"type":"string","format":"uuid"},"status":{"type":"string","enum":["created","running","completed","failed","cancelled"]},"triggerSource":{"type":"string","enum":["manual","scheduled","api"]},"executionMode":{"type":"string","enum":["parallel","sequential"],"description":"The effective mode this run executed with."},"totalCases":{"type":"integer"},"completedCases":{"type":"integer"},"passedCases":{"type":"integer"},"failedCases":{"type":"integer"},"startedAt":{"type":"string","format":"date-time","nullable":true},"completedAt":{"type":"string","format":"date-time","nullable":true},"createdAt":{"type":"string","format":"date-time"},"archivedAt":{"type":"string","format":"date-time","nullable":true,"description":"Set when the run was archived (soft-deleted). Archived runs are excluded from the runs list but stay readable by id."},"cases":{"type":"array","items":{"$ref":"#/components/schemas/PlanRunCase"}}}},"PlanRunCase":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"caseId":{"type":"string","format":"uuid"},"title":{"type":"string","nullable":true},"type":{"type":"string","nullable":true},"status":{"type":"string","enum":["pending","running","passed","failed","skipped","cancelled"]},"startedAt":{"type":"string","format":"date-time","nullable":true},"completedAt":{"type":"string","format":"date-time","nullable":true}}},"Error":{"type":"object","required":["error"],"properties":{"error":{"type":"string"}}}},"responses":{"Unauthorized":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"RateLimited":{"description":"Rate limit exceeded — e.g. the daily session limit was reached for the\norganization, or too many API requests were sent in a short window\n(retry after the number of seconds in the `Retry-After` header).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"InternalError":{"description":"Unexpected server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"paths":{"/api/triggers/plans/{planId}/runs/{planRunId}":{"get":{"operationId":"getPlanRunStatus","summary":"Get plan run status","description":"Returns the overall status and per-case breakdown of a plan run.","tags":["Triggers – Plans"],"parameters":[{"name":"planId","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"UUID of the test plan."},{"name":"planRunId","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"UUID of the plan run returned by the trigger endpoint."}],"responses":{"200":{"description":"Plan run details.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PlanRun"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"description":"Plan run not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}}}}
```
