> ## Documentation Index
> Fetch the complete documentation index at: https://docs.productbrain.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Iterations

> List, create, update, close, and reorder phases.

Phases are thematic delivery slices: bundles of work that ship together. They are not sprints (no fixed timebox) and not releases (no deployment coupling). The API calls them `iterations`; the product UI calls the same thing a phase.

## List phases

```
GET /api/v1/iterations?projectId={projectId}
```

### Parameters

| Parameter | Required | Description |
| - | - | - |
| `projectId` | Yes | The project to query |
| `status` | No | Filter: `active` or `done` |
| `current` | No | Set to `true` to get only the current phase |

### Get all phases

```bash theme={null}
curl -s "https://productbrain.com/api/v1/iterations?projectId=my-project" \
  -H "Authorization: Bearer pb_..."
```

```json theme={null}
{
  "iterations": [
    { "name": "Later", "status": "active", "system": true, "createdAt": 1789687185603, "sortOrder": 0 },
    { "name": "MVP", "status": "active", "system": false, "createdAt": 1789687336371, "sortOrder": 1, "gitTags": ["v0.3.0"] }
  ],
  "_meta": { "_tip": "Add &current=true for just the active iteration ..." }
}
```

### Get the current phase

The current phase is the first active non-system phase by sort order. Use this when the user says "add it to the current phase".

```bash theme={null}
curl -s "https://productbrain.com/api/v1/iterations?projectId=my-project&current=true" \
  -H "Authorization: Bearer pb_..."
```

```json theme={null}
{
  "iteration": { "name": "MVP", "status": "active", "system": false, "createdAt": 1789687336371, "sortOrder": 1 }
}
```

When no non-system phase is active, `iteration` is `null` and `_meta._tip` explains how to list or create one.

### Phase fields

| Field | Type | Description |
| - | - | - |
| `name` | string | Unique within the project |
| `status` | string | `active` or `done` |
| `system` | boolean | System phases (`Later`) cannot be deleted |
| `sortOrder` | number | Display order |
| `createdAt` | number | Unix milliseconds |
| `completedAt` | number | Unix milliseconds, present once the phase is done |
| `gitTags` | string\[] | Present only when tags have been attached |

## Create a phase

```bash theme={null}
curl -X POST "https://productbrain.com/api/v1/mutate" \
  -H "Authorization: Bearer pb_..." \
  -H "Content-Type: application/json" \
  -d '{
    "action": "addIteration",
    "projectId": "my-project",
    "iteration": { "name": "Self-serve onboarding" }
  }'
# → { "success": true, "iteration": { "name": "Self-serve onboarding", "status": "active", "system": false, "sortOrder": 2 } }
```

Name a phase by the user value it delivers, not a dev milestone. The names `Later`, `Backlog`, `Polish` and `Catch-all` are rejected (case-insensitive) with `400 "'Backlog' is a forbidden phase name ..."`. A duplicate name returns `400 "Iteration 'X' already exists"`.

To fit existing unassigned jobs into phases, prefer the `phase-assign` [workflow](/api-reference/workflow); it groups by theme and reuses phases where a job fits.

## Update a phase

PATCH semantics. Use this to rename, close, describe, reorder, or attach git tags.

```bash theme={null}
curl -X POST "https://productbrain.com/api/v1/mutate" \
  -H "Authorization: Bearer pb_..." \
  -H "Content-Type: application/json" \
  -d '{
    "action": "updateIteration",
    "projectId": "my-project",
    "iterationName": "MVP",
    "data": { "status": "done" }
  }'
# → { "success": true }
```

Fields accepted in `data`: `name`, `status`, `description`, `gitTags`, `sortOrder`, `completedAt`. Marking a phase `done` sets `completedAt` automatically. Done phases are hidden from the UI dropdown and the matrix. Renaming a phase updates the `iteration` field on every job and task assigned to it.

The `addIteration` shape is accepted too: `{ "action": "updateIteration", "iteration": { "name": "MVP", "status": "done" } }`.

### Closing a phase that still has open jobs

A closed phase cannot hold open work. If the phase has open jobs, closing it returns:

```json theme={null}
{
  "success": false,
  "error": "phase_has_open_jobs",
  "openJobs": [{ "id": "job-1", "label": "Scan returns a price" }],
  "_meta": { "_tip": "Phase 'MVP' has 1 open job(s): job-1. ..." }
}
```

HTTP `409`. Either mark the jobs done first, or retry with `"ejectOpenJobs": true` to move them to `Later` and close the phase in one call. The response then lists them:

```json theme={null}
{ "success": true, "ejectedToLater": ["job-1"], "_meta": { "_tip": "Closed 'MVP' and moved 1 open job(s) to Later: job-1." } }
```

## Delete a phase

```bash theme={null}
curl -X POST "https://productbrain.com/api/v1/mutate" \
  -H "Authorization: Bearer pb_..." \
  -H "Content-Type: application/json" \
  -d '{
    "action": "deleteIteration",
    "projectId": "my-project",
    "iterationName": "Phase 2"
  }'
# → { "success": true }
```

System phases cannot be deleted (`400 "Cannot delete system iterations"`). An unknown name returns `404`. Move or close the phase's jobs before deleting it; the delete itself does not reassign them.

## Reorder phases

Pass the full ordered list of phase names.

```bash theme={null}
curl -X POST "https://productbrain.com/api/v1/mutate" \
  -H "Authorization: Bearer pb_..." \
  -H "Content-Type: application/json" \
  -d '{
    "action": "reorderIterations",
    "projectId": "my-project",
    "order": ["MVP", "Phase 2", "Phase 3", "Later"]
  }'
# → { "success": true }
```

## Webhook events

`addIteration`, `updateIteration` and `deleteIteration` fire `iteration.added`, `iteration.updated` and `iteration.deleted`. Reordering does not fire an event. See [Webhooks](/api-reference/webhooks).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.