# Workflow

Part of AppEngine API Documentation. Full index: https://appengine.appmint.io/documentation.md
## POST /workflow/fire

**Fire a record into a workflow**

`operationId: WorkflowController_fire`

The generic entry point: takes any record and starts a Task for it on a pipeline. This is how check-in puts a Reservation on `reservation-checkin-pipeline` and how POS puts an order on `prep-pipeline`.

Identify the pipeline with **either** `workflowId` (an existing definition's `sk`) **or** `workflowName`. The name form auto-bootstraps the definition from a registered template if the org does not have it yet, so a first call in a fresh org works without setup.

#### Signature

```http
POST /workflow/fire (body) -> The created Task
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `POST /workflow/definition/from-template/{name}`
- `GET /workflow/task`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |

### Request body

The record to fire and the pipeline to put it on.

```json
{
  "datatype": "reservation",
  "id": "RES-771",
  "workflowName": "reservation-checkin-pipeline"
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `201` | The created Task |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## GET /workflow/for/{datatype}

**Which workflow takes a datatype, and why**

`operationId: WorkflowController_explain`

Explains what happens when a record of this datatype fires a workflow: the collection's own `workflow` choice and its Enable Workflow switch, every definition that lists the datatype in `collections`, the one that wins (`effective`), whether it will run (`active`), and a one-line `reason` — e.g. `off: the collection has Enable Workflow switched off`, `none: no workflow names this collection`, `runs "access-approval": it lists this collection`.

#### Signature

```http
GET /workflow/for/{datatype} (datatype: string) -> { datatype, collection, effective, chosen, listing, active, reason }
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `POST /workflow/fire`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `datatype` | path | string | yes | Collection / datatype name. |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | { datatype, collection, effective, chosen, listing, active, reason } |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

Example response:

```json
{
  "datatype": "access_request",
  "collection": {
    "sk": "COL-9",
    "workflow": null,
    "enableWorkflow": true
  },
  "effective": {
    "sk": "WF-12",
    "name": "access-approval",
    "title": "Access approval",
    "enabled": true
  },
  "chosen": null,
  "listing": [
    {
      "sk": "WF-12",
      "name": "access-approval",
      "title": "Access approval",
      "enabled": true
    }
  ],
  "active": true,
  "reason": "runs \"access-approval\": it lists this collection"
}
```

## GET /workflow/stations

**Get the kitchen board scope**

`operationId: WorkflowController_stations`

What a prep/kitchen board shows: the `prep-pipeline` workflow (when the org has one) and the station names from the `prepStation` product attribute's options, de-duplicated.

#### Signature

```http
GET /workflow/stations () -> { names, pipeline, stations }
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | { names, pipeline, stations } |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

Example response:

```json
{
  "names": [
    "prep-pipeline"
  ],
  "pipeline": {
    "id": "WF-3",
    "name": "prep-pipeline",
    "title": "Kitchen prep"
  },
  "stations": [
    "Grill",
    "Fryer",
    "Bar"
  ]
}
```

## GET /workflow/definition

**List workflow definitions**

`operationId: WorkflowController_listDefinitions`

The pipelines defined for the org. Optionally filter by name.

#### Signature

```http
GET /workflow/definition (name?: string) -> Definitions (first 200)
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Notes

- Capped at 200 definitions; there is no paging on this route.

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `GET /workflow/definition/{id}`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `name` | query | string | — | Exact definition name. |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | Definitions (first 200) |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## POST /workflow/definition

**Create a workflow definition**

`operationId: WorkflowController_createDefinition`

Creates a pipeline from a payload — stages in order, plus optional SLA escalation tiers. Use the template route instead for the standard pipelines.

#### Signature

```http
POST /workflow/definition (body) -> The created definition
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `POST /workflow/definition/from-template/{name}`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |

### Request body

The definition.

```json
{
  "name": "onboarding-pipeline",
  "title": "Customer onboarding",
  "stages": [
    {
      "name": "Received"
    },
    {
      "name": "In review"
    },
    {
      "name": "Approved"
    }
  ]
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `201` | The created definition |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## GET /workflow/definition/{id}

**Get a workflow definition**

`operationId: WorkflowController_getDefinition`

Fetches one definition with its stages and escalation tiers.

#### Signature

```http
GET /workflow/definition/{id} (id: string) -> The definition
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `PATCH /workflow/definition/{id}`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `id` | path | string | yes | Definition `sk`. |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | The definition |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## DELETE /workflow/definition/{id}

**Delete a workflow definition**

`operationId: WorkflowController_deleteDefinition`

Deletes a pipeline definition. Tasks already created against it are **not** deleted and keep their `workflowId`, leaving them pointing at a definition that no longer exists — stage names and SLA no longer resolve. Drain or cancel the tasks first.

#### Signature

```http
DELETE /workflow/definition/{id} (id: string) -> The delete result
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Notes

- Orphans any in-flight tasks on this definition.

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `POST /workflow/task/{taskId}/cancel`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `id` | path | string | yes | Definition `sk`. |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | The delete result |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## PATCH /workflow/definition/{id}

**Update a workflow definition**

`operationId: WorkflowController_updateDefinition`

Updates title, description, stages or escalations. Every top-level key in the body is written to `data.<key>`, so sending `stages` replaces the whole array rather than merging into it.

**Tasks already in flight keep their numeric `stageId`.** Reordering or removing stages therefore silently re-points running tasks at whatever now sits at that index. Add stages at the end, or drain the pipeline first.

#### Signature

```http
PATCH /workflow/definition/{id} (id: string, body) -> The update result
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Notes

- `stageId` on in-flight tasks is an index — reordering stages moves those tasks.

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `GET /workflow/task`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `id` | path | string | yes | Definition `sk`. |

### Request body

Fields to change.

```json
{
  "title": "Kitchen prep",
  "escalations": [
    {
      "afterMinutes": 15,
      "notify": [
        "manager@example.com"
      ]
    }
  ]
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `200` | The update result |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## POST /workflow/definition/from-template/{name}

**Create a workflow from a template**

`operationId: WorkflowController_createFromTemplate`

Creates one of the registered pipelines for this org if it does not already exist: `prep-pipeline`, `reservation-checkin-pipeline`, `pickup-pipeline`, `application-processing-pipeline`, `service-appointment-pipeline`, `renewal-pipeline`.

Idempotent — if the org already has the definition, the existing one is returned untouched, so it is safe to call on every boot or before firing.

#### Signature

```http
POST /workflow/definition/from-template/{name} (name: string) -> The new or existing definition
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Notes

- Idempotent — will not overwrite an existing definition of the same name.

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `POST /workflow/fire`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `name` | path | string | yes | Template name. |

### Responses

| Status | Meaning |
| --- | --- |
| `201` | The new or existing definition |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## GET /workflow/task

**List tasks**

`operationId: WorkflowController_listTasks`

The live queue. By default returns **active** tasks (`new`, `pending`, `inprogress`, `blocked`) plus tasks completed in the last 24 hours, excluding archived ones — which is what an operations board wants to show.

Two ways to widen it: `recentDoneHours` changes the completed window (`0` drops completed tasks entirely, `-1` returns every completed task ever), and an explicit `status` overrides the whole default and is used as-is.

#### Signature

```http
GET /workflow/task (workflowId?: string, ownerDatatype?: string, ownerId?: string, stageId?: integer, status?: string, assignTo?: string, pageSize?: integer, recentDoneHours?: number, includeArchived?: boolean) -> Matching tasks
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Notes

- Always page 1 — use `pageSize` to widen, there is no page parameter.

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `GET /workflow/task/{taskId}`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `workflowId` | query | string | — |  |
| `ownerDatatype` | query | string | — | Owning record type. |
| `ownerId` | query | string | — |  |
| `stageId` | query | integer | — | Exact stage index. |
| `status` | query | string | — | Comma-separated. Overrides the active/recent-done default entirely. |
| `assignTo` | query | string | — |  |
| `pageSize` | query | integer | — | Default 200. |
| `recentDoneHours` | query | number | — | Rolling window for completed tasks. Default 24. `0` excludes all completed; `-1` returns all completed forever. |
| `includeArchived` | query | boolean | — | Default false. |
| `station` | query | string | yes |  |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | Matching tasks |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## POST /workflow/task/{taskId}/archive

**Archive a task**

`operationId: WorkflowController_archiveTask`

Hides a task from the default list without changing its status — the task is not completed or canceled, just out of the way. `GET /workflow/task?includeArchived=true` still returns it.

#### Signature

```http
POST /workflow/task/{taskId}/archive (taskId: string) -> The archived task
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Notes

- A display flag, not a status change.

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `POST /workflow/task/{taskId}/unarchive`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `taskId` | path | string | yes | Task id (`sk`). |

### Responses

| Status | Meaning |
| --- | --- |
| `201` | The archived task |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## POST /workflow/task/{taskId}/unarchive

**Unarchive a task**

`operationId: WorkflowController_unarchiveTask`

Returns an archived task to the default list.

#### Signature

```http
POST /workflow/task/{taskId}/unarchive (taskId: string) -> The unarchived task
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `POST /workflow/task/{taskId}/archive`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `taskId` | path | string | yes | Task id (`sk`). |

### Responses

| Status | Meaning |
| --- | --- |
| `201` | The unarchived task |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## GET /workflow/task/{taskId}

**Get a task**

`operationId: WorkflowController_getTask`

Fetches one task with its stage, status, assignment and comments.

#### Signature

```http
GET /workflow/task/{taskId} (taskId: string) -> The task
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `GET /workflow/task/{taskId}/history`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `taskId` | path | string | yes | Task id (`sk`). |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | The task |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## GET /workflow/task/{taskId}/history

**Get a task's stage history**

`operationId: WorkflowController_getHistory`

The stage-transition history — when the task entered each stage. Operator notes are deliberately kept out of this list so time-in-stage analytics stay clean. Returns an empty array for an unknown task id.

#### Signature

```http
GET /workflow/task/{taskId}/history (taskId: string) -> Stage transitions, oldest first
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `POST /workflow/task/{taskId}/note`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `taskId` | path | string | yes | Task id (`sk`). |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | Stage transitions, oldest first |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

Example response:

```json
[
  {
    "stageId": 0,
    "at": "2026-08-30T09:00:00.000Z"
  },
  {
    "stageId": 1,
    "at": "2026-08-30T09:04:12.000Z"
  }
]
```

## POST /workflow/task/{taskId}/advance

**Advance a task one stage**

`operationId: WorkflowController_advance`

Moves the task to the next stage (`stageId + 1`) and fires the stage-change hooks — alerts, assignments and SLA timers for the new stage.

The increment is **not bounded by the definition's stage count**: repeated calls will push `stageId` past the last stage, where it resolves to no stage at all. Use `complete` to finish a task.

#### Signature

```http
POST /workflow/task/{taskId}/advance (taskId: string, body) -> The advanced task
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Notes

- Returns HTTP 200 with a `null` body when the task id does not exist — check for `null` rather than relying on a 404.
- Not bounded by the stage count — use `complete` to terminate.
- Kitchen station gate: a prep ticket (`data.payload.station`) can only be moved by someone cleared for that station — 423 `readiness_block` (`taskId`, `station`); resend with `override`. Tickets without a station are never gated.
- Workforce Readiness: with no requirement rules this endpoint behaves exactly as before. `warn` never stops anything — it comes back as `readiness.warnings` in the response.

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `423` | READINESS_BLOCK | <name> can't work the <station> station: <requirement titles>. | A requirement rule whose `enforcement.kitchenStation` effect is block (or override-with-reason) is unmet for this person, and no override is active. | Show `message` and `reasons`. A location manager or HR can resend the same request with `override: { reasonCode, reason, expiresAt }` — it is written to the readiness ledger with the approver and expiry. The person’s own override is refused. |
| `400` | OVERRIDE_INVALID | An override needs reasonCode, reason, expiresAt. | `override` is missing a field, has an unknown reason code, or an expiry in the past. | — |
| `403` | OVERRIDE_FORBIDDEN | Sign in as a location manager or HR to override. | The caller may not approve an override (no caller, the person themselves, or only their own supervisor). | — |

Plus the standard platform errors: `401`, `429`, `500`.

#### See also

- `POST /workflow/task/{taskId}/complete`
- `POST /workflow/task/{taskId}/move-to/{stageId}`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `taskId` | path | string | yes | Task id (`sk`). |

### Request body

### Responses

| Status | Meaning |
| --- | --- |
| `201` | The advanced task |
| `400` | An override needs reasonCode, reason, expiresAt. — `override` is missing a field, has an unknown reason code, or an expiry in the past. |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | Sign in as a location manager or HR to override. — The caller may not approve an override (no caller, the person themselves, or only their own supervisor). |
| `423` | <name> can't work the <station> station: <requirement titles>. — A requirement rule whose `enforcement.kitchenStation` effect is block (or override-with-reason) is unmet for this person, and no override is active. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## POST /workflow/task/{taskId}/move-to/{stageId}

**Move a task to a specific stage**

`operationId: WorkflowController_moveTo`

Jumps a task to any stage, forwards or backwards, firing the stage-change hooks. Backwards moves are allowed — that is how a task is sent back for rework — but the history keeps both transitions, so time-in-stage figures count the stage twice.

#### Signature

```http
POST /workflow/task/{taskId}/move-to/{stageId} (taskId: string, stageId: string, body) -> The moved task
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Notes

- Returns HTTP 200 with a `null` body when the task id does not exist — check for `null` rather than relying on a 404.
- The stage index is not validated against the definition.
- Kitchen station gate — same as advance.
- Workforce Readiness: with no requirement rules this endpoint behaves exactly as before. `warn` never stops anything — it comes back as `readiness.warnings` in the response.

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `423` | READINESS_BLOCK | <name> can't work the <station> station: <requirement titles>. | A requirement rule whose `enforcement.kitchenStation` effect is block (or override-with-reason) is unmet for this person, and no override is active. | Show `message` and `reasons`. A location manager or HR can resend the same request with `override: { reasonCode, reason, expiresAt }` — it is written to the readiness ledger with the approver and expiry. The person’s own override is refused. |
| `400` | OVERRIDE_INVALID | An override needs reasonCode, reason, expiresAt. | `override` is missing a field, has an unknown reason code, or an expiry in the past. | — |
| `403` | OVERRIDE_FORBIDDEN | Sign in as a location manager or HR to override. | The caller may not approve an override (no caller, the person themselves, or only their own supervisor). | — |

Plus the standard platform errors: `401`, `429`, `500`.

#### See also

- `POST /workflow/task/{taskId}/advance`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `taskId` | path | string | yes | Task id (`sk`). |
| `stageId` | path | string | yes | Target stage index (zero-based). |

### Request body

### Responses

| Status | Meaning |
| --- | --- |
| `201` | The moved task |
| `400` | An override needs reasonCode, reason, expiresAt. — `override` is missing a field, has an unknown reason code, or an expiry in the past. |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | Sign in as a location manager or HR to override. — The caller may not approve an override (no caller, the person themselves, or only their own supervisor). |
| `423` | <name> can't work the <station> station: <requirement titles>. — A requirement rule whose `enforcement.kitchenStation` effect is block (or override-with-reason) is unmet for this person, and no override is active. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## POST /workflow/task/{taskId}/complete

**Complete a task**

`operationId: WorkflowController_complete`

Terminates the task — advances it to the terminal stage and marks it done. This is the correct way to finish a task; it stamps the completion time the recent-done window in `GET /workflow/task` filters on.

#### Signature

```http
POST /workflow/task/{taskId}/complete (taskId: string, body) -> The completed task
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Notes

- Kitchen station gate — same as advance.
- Workforce Readiness: with no requirement rules this endpoint behaves exactly as before. `warn` never stops anything — it comes back as `readiness.warnings` in the response.

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `423` | READINESS_BLOCK | <name> can't work the <station> station: <requirement titles>. | A requirement rule whose `enforcement.kitchenStation` effect is block (or override-with-reason) is unmet for this person, and no override is active. | Show `message` and `reasons`. A location manager or HR can resend the same request with `override: { reasonCode, reason, expiresAt }` — it is written to the readiness ledger with the approver and expiry. The person’s own override is refused. |
| `400` | OVERRIDE_INVALID | An override needs reasonCode, reason, expiresAt. | `override` is missing a field, has an unknown reason code, or an expiry in the past. | — |
| `403` | OVERRIDE_FORBIDDEN | Sign in as a location manager or HR to override. | The caller may not approve an override (no caller, the person themselves, or only their own supervisor). | — |

Plus the standard platform errors: `401`, `429`, `500`.

#### See also

- `POST /workflow/task/{taskId}/cancel`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `taskId` | path | string | yes | Task id (`sk`). |

### Request body

### Responses

| Status | Meaning |
| --- | --- |
| `201` | The completed task |
| `400` | An override needs reasonCode, reason, expiresAt. — `override` is missing a field, has an unknown reason code, or an expiry in the past. |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | Sign in as a location manager or HR to override. — The caller may not approve an override (no caller, the person themselves, or only their own supervisor). |
| `423` | <name> can't work the <station> station: <requirement titles>. — A requirement rule whose `enforcement.kitchenStation` effect is block (or override-with-reason) is unmet for this person, and no override is active. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## POST /workflow/task/{taskId}/cancel

**Cancel a task**

`operationId: WorkflowController_cancelTask`

Sets the task status to `canceled`. Distinct from completing it — a canceled task did not finish its pipeline, and it drops out of the default task list without appearing in the recent-done window.

#### Signature

```http
POST /workflow/task/{taskId}/cancel (taskId: string) -> The canceled task
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Notes

- Returns HTTP 200 with a `null` body when the task id does not exist — check for `null` rather than relying on a 404.

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `POST /workflow/task/{taskId}/complete`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `taskId` | path | string | yes | Task id (`sk`). |

### Responses

| Status | Meaning |
| --- | --- |
| `201` | The canceled task |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## POST /workflow/task/restart

**Restart an owner's tasks**

`operationId: WorkflowController_restartOwnerTasks`

Sends **every** task belonging to one owning record back to stage 0. Used when a record has to go through its pipeline again — a reservation re-checked-in, an order re-fired to the kitchen.

This re-runs the stage-0 hooks, so any alerts or notifications wired to the first stage fire again.

#### Signature

```http
POST /workflow/task/restart (body) -> The restarted tasks
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Notes

- Affects all tasks for the owner, not just the active one.

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `POST /workflow/fire`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |

### Request body

The owning record.

```json
{
  "datatype": "reservation",
  "id": "RES-771"
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `201` | The restarted tasks |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## POST /workflow/task/{taskId}/reassign

**Reassign a task**

`operationId: WorkflowController_reassign`

Replaces the task's assignee list. The body **replaces** `assignTo` outright — send the full list, including anyone who should stay assigned.

#### Signature

```http
POST /workflow/task/{taskId}/reassign (taskId: string, body) -> The reassigned task
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Notes

- Replaces rather than appends.

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `GET /workflow/task`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `taskId` | path | string | yes | Task id (`sk`). |

### Request body

The new assignee list.

```json
{
  "assignTo": [
    "ops@example.com",
    "lead@example.com"
  ]
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `201` | The reassigned task |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## POST /workflow/task/{taskId}/note

**Add a note to a task**

`operationId: WorkflowController_addNote`

Appends an operator note to the task's `comments`, stamped with the caller's email and the stage the task was on at the time. Notes are kept out of the stage history on purpose, so adding them never distorts time-in-stage analytics.

#### Signature

```http
POST /workflow/task/{taskId}/note (taskId: string, body) -> The task with the note appended
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Notes

- Returns HTTP 200 with a `null` body when the task id does not exist — check for `null` rather than relying on a 404.
- The author is taken from the token, not the body.

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `GET /workflow/task/{taskId}/history`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `taskId` | path | string | yes | Task id (`sk`). |

### Request body

The note.

```json
{
  "note": "Customer called, running 20 minutes late"
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `201` | The task with the note appended |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## GET /workflow/analytics/{workflowId}/wait-times

**Get wait-time statistics**

`operationId: WorkflowController_waitStats`

Per-stage timing for one pipeline over a rolling window — average, median and p95 time in each stage, plus total flow time. p95 is the number to watch: an average that looks fine often hides a stage where one task in twenty stalls.

#### Signature

```http
GET /workflow/analytics/{workflowId}/wait-times (workflowId: string, windowDays?: integer) -> Per-stage and total timings
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `GET /workflow/analytics/task/{taskId}/eta`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `workflowId` | path | string | yes | Definition `sk`. |
| `windowDays` | query | integer | — | Rolling window in days. Default 7. |
| `refresh` | query | string | yes |  |
| `station` | query | string | yes |  |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | Per-stage and total timings |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## GET /workflow/analytics/task/{taskId}/eta

**Estimate a task's remaining time**

`operationId: WorkflowController_taskEta`

Projects how long an in-flight task has left, using the historical stage timings for its pipeline. An estimate from past throughput — not a commitment, and it is only as good as the history behind it.

#### Signature

```http
GET /workflow/analytics/task/{taskId}/eta (taskId: string) -> The estimate
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `GET /workflow/analytics/{workflowId}/wait-times`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `taskId` | path | string | yes | Task id (`sk`). |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | The estimate |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## POST /workflow/escalation/scan

**Run the overdue scan now**

`operationId: WorkflowController_scanNow`

Runs this org's SLA escalation scan immediately instead of waiting for the scheduled one (every 10 minutes): open tasks past their `dueDate` move to their next escalation tier and their notifications go out.

#### Signature

```http
POST /workflow/escalation/scan () -> { orgId, escalated, lastRun } — `escalated` counts tasks moved by this scan; `lastRun` is the last scheduled sweep across all orgs, or null
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `GET /workflow/escalation/breached`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |

### Responses

| Status | Meaning |
| --- | --- |
| `201` | { orgId, escalated, lastRun } — `escalated` counts tasks moved by this scan; `lastRun` is the last scheduled sweep across all orgs, or null |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

Example response:

```json
{
  "orgId": "acme",
  "escalated": 2,
  "lastRun": {
    "at": "2026-09-29T13:50:00.000Z",
    "orgs": 41,
    "escalated": 6
  }
}
```

## GET /workflow/escalation/breached

**List breached tasks**

`operationId: WorkflowController_breached`

Tasks past their `dueDate` and still open — what is already late right now.

#### Signature

```http
GET /workflow/escalation/breached (workflowId?: string) -> Breached tasks
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `GET /workflow/escalation/upcoming`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `workflowId` | query | string | — | Limit to one pipeline. |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | Breached tasks |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## GET /workflow/escalation/upcoming

**List tasks about to breach**

`operationId: WorkflowController_upcoming`

Tasks whose `dueDate` falls within the next N minutes — the window in which intervening still helps.

#### Signature

```http
GET /workflow/escalation/upcoming (withinMinutes?: integer, workflowId?: string) -> Tasks approaching breach
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `GET /workflow/escalation/breached`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `withinMinutes` | query | integer | — | Look-ahead window. Default 30. |
| `workflowId` | query | string | — |  |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | Tasks approaching breach |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## GET /workflow/task/{taskId}/sla

**Get a task's SLA snapshot**

`operationId: WorkflowController_slaForTask`

The SLA position for one task — current escalation tier, `dueDate`, time remaining and escalation history.

#### Signature

```http
GET /workflow/task/{taskId}/sla (taskId: string) -> The SLA snapshot
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `POST /workflow/task/{taskId}/snooze`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `taskId` | path | string | yes | Task id (`sk`). |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | The SLA snapshot |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## POST /workflow/task/{taskId}/snooze

**Snooze a task's SLA**

`operationId: WorkflowController_snooze`

Pushes `dueDate` forward by N minutes, so the task stops counting as breached. Measured from the existing `dueDate` when there is one, otherwise from now — snoozing an already-overdue task by 10 minutes moves it 10 minutes past its *original* deadline, which may leave it still breached.

A negative value pulls the deadline in.

#### Signature

```http
POST /workflow/task/{taskId}/snooze (taskId: string, body) -> The task with its new dueDate
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Notes

- Returns HTTP 200 with a `null` body when the task id does not exist — check for `null` rather than relying on a 404.
- Relative to the existing dueDate, not to now.

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `GET /workflow/task/{taskId}/sla`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `taskId` | path | string | yes | Task id (`sk`). |

### Request body

How long to snooze for.

```json
{
  "minutes": 15
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `201` | The task with its new dueDate |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## POST /workflow/task/{taskId}/escalate-now

**Escalate a task immediately**

`operationId: WorkflowController_escalateNow`

Marks the task overdue and moves it to the next escalation tier without waiting for the SLA timer — the manual pull for something that needs attention now. Fires that tier's notifications.

#### Signature

```http
POST /workflow/task/{taskId}/escalate-now (taskId: string) -> The escalated task
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Notes

- Sends the tier's notifications immediately.

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `GET /workflow/escalation/breached`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `taskId` | path | string | yes | Task id (`sk`). |

### Responses

| Status | Meaning |
| --- | --- |
| `201` | The escalated task |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

