# Tasks

> Durable, joinable tasks with one recorded result, plus resource-aware admission.

Source: https://docs.getrunstate.com/api/tasks/

<!-- Generated by apps/docs/scripts/gen-api.mjs from packages/contracts/openapi.yaml. Do not edit. -->

All paths are relative to the API base URL (`https://api.getrunstate.com`) and require `Authorization: Bearer <api key>`. See [the API overview](https://docs.getrunstate.com/api/) for authentication, idempotency and the error envelope.

## GET /tasks

```http
GET /v1/spaces/{spaceId}/tasks
```

List tasks with optional scopeId/state filters.

- **Key permission:** `coordination_read`

**Path parameters**

| Name | Type | Notes |
| --- | --- | --- |
| `spaceId` | string (uuid) | required |

**Query parameters**

| Name | Type | Notes |
| --- | --- | --- |
| `scopeId` | string (uuid) |  |
| `state` | string |  |
| `limit` | integer |  |

**Responses**

| Status | Meaning |
| --- | --- |
| `200` | Tasks |

```bash
curl -X GET "$RUNSTATE_BASE_URL/v1/spaces/$RUNSTATE_SPACE_ID/tasks" \
  -H "Authorization: Bearer $RUNSTATE_API_KEY"
```

## POST /tasks

```http
POST /v1/spaces/{spaceId}/tasks
```

Submit durable work; idempotent create-or-join by taskKey+fingerprint.

- **Key permission:** `coordination_write`
- **Idempotency-Key header:** required
- **TypeScript SDK:** `run.mailbox(name).submit()`
- **Python SDK:** `run.mailbox(name).submit()`

**Path parameters**

| Name | Type | Notes |
| --- | --- | --- |
| `spaceId` | string (uuid) | required |

**Request body** (JSON)

| Field | Type | Required | Notes |
| --- | --- | --- | --- |
| `scopeId` | string (uuid) | yes |  |
| `mailboxId` | string (uuid) | yes |  |
| `taskKey` | string | yes | length 1–512 |
| `input` | any JSON | no |  |
| `deadline` | string (date-time) | no |  |
| `subscriberId` | string | no |  |
| `requirements` | object | no |  |
| `requirements.pools` | array of object | no |  |
| `requirements.pools[].name` | string | yes |  |
| `requirements.pools[].units` | integer | yes | min 1 |
| `requirements.quotas` | array of object | no |  |
| `requirements.quotas[].name` | string | yes |  |
| `requirements.quotas[].units` | integer | yes | min 1 |
| `requirements.budgets` | array of object | no |  |
| `requirements.budgets[].name` | string | yes |  |
| `requirements.budgets[].reserveMinor` | string | yes | pattern `^\d+$` |
| `workLimit` | string | no |  |

**Responses**

| Status | Meaning |
| --- | --- |
| `201` | taskId |
| `409` | Error envelope `{"error":{"code","message","requestId"}}` |

```bash
curl -X POST "$RUNSTATE_BASE_URL/v1/spaces/$RUNSTATE_SPACE_ID/tasks" \
  -H "Authorization: Bearer $RUNSTATE_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{"scopeId":"<run id>","mailboxId":"<mailboxId>","taskKey":"<taskKey>"}'
```

## GET /tasks/{id}

```http
GET /v1/spaces/{spaceId}/tasks/{id}
```

Restart-safe task view incl. outcome and subscribers.

- **Key permission:** `coordination_read`
- **TypeScript SDK:** `ticket.status(), ticket.result(), ticket.awaitAdmission()`
- **Python SDK:** `ticket.status(), ticket.result(), ticket.await_admission()`

**Path parameters**

| Name | Type | Notes |
| --- | --- | --- |
| `spaceId` | string (uuid) | required |
| `id` | string (uuid) | required |

**Responses**

| Status | Meaning |
| --- | --- |
| `200` | Task view |
| `404` | Error envelope `{"error":{"code","message","requestId"}}` |

```bash
curl -X GET "$RUNSTATE_BASE_URL/v1/spaces/$RUNSTATE_SPACE_ID/tasks/<id>" \
  -H "Authorization: Bearer $RUNSTATE_API_KEY"
```

## POST /tasks/{id}/cancel

```http
POST /v1/spaces/{spaceId}/tasks/{id}/cancel
```

Cancel a nonterminal task and its delivery (cleanup, ungated)

- **Key permission:** `coordination_write`
- **TypeScript SDK:** `ticket.cancel()`
- **Python SDK:** `ticket.cancel()`

**Path parameters**

| Name | Type | Notes |
| --- | --- | --- |
| `spaceId` | string (uuid) | required |
| `id` | string (uuid) | required |

**Request body** (JSON)

| Field | Type | Required | Notes |
| --- | --- | --- | --- |
| `reason` | string | no | max length 512 |

**Responses**

| Status | Meaning |
| --- | --- |
| `200` | CANCELLED |
| `409` | Error envelope `{"error":{"code","message","requestId"}}` |

```bash
curl -X POST "$RUNSTATE_BASE_URL/v1/spaces/$RUNSTATE_SPACE_ID/tasks/<id>/cancel" \
  -H "Authorization: Bearer $RUNSTATE_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{}'
```

## POST /tasks/{id}/join

```http
POST /v1/spaces/{spaceId}/tasks/{id}/join
```

Idempotently subscribe to a shared task.

- **Key permission:** `coordination_write`
- **TypeScript SDK:** `ticket.join()`
- **Python SDK:** `ticket.join()`

**Path parameters**

| Name | Type | Notes |
| --- | --- | --- |
| `spaceId` | string (uuid) | required |
| `id` | string (uuid) | required |

**Request body** (JSON)

| Field | Type | Required | Notes |
| --- | --- | --- | --- |
| `subscriberId` | string | yes |  |
| `scopeId` | string (uuid) | yes |  |

**Responses**

| Status | Meaning |
| --- | --- |
| `200` | Task state |
| `404` | Error envelope `{"error":{"code","message","requestId"}}` |

```bash
curl -X POST "$RUNSTATE_BASE_URL/v1/spaces/$RUNSTATE_SPACE_ID/tasks/<id>/join" \
  -H "Authorization: Bearer $RUNSTATE_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{"subscriberId":"<subscriberId>","scopeId":"<run id>"}'
```

## POST /tasks/{id}/detach

```http
POST /v1/spaces/{spaceId}/tasks/{id}/detach
```

Detach a subscriber; zero subscribers does not cancel the task.

- **Key permission:** `coordination_write`
- **TypeScript SDK:** `ticket.detach()`
- **Python SDK:** `ticket.detach()`

**Path parameters**

| Name | Type | Notes |
| --- | --- | --- |
| `spaceId` | string (uuid) | required |
| `id` | string (uuid) | required |

**Request body** (JSON)

| Field | Type | Required | Notes |
| --- | --- | --- | --- |
| `subscriberId` | string | yes |  |

**Responses**

| Status | Meaning |
| --- | --- |
| `200` | detached |
| `404` | Error envelope `{"error":{"code","message","requestId"}}` |

```bash
curl -X POST "$RUNSTATE_BASE_URL/v1/spaces/$RUNSTATE_SPACE_ID/tasks/<id>/detach" \
  -H "Authorization: Bearer $RUNSTATE_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{"subscriberId":"<subscriberId>"}'
```

## GET /ops/tasks/{taskId}

```http
GET /v1/spaces/{spaceId}/ops/tasks/{taskId}
```

Debugger task detail.

- **Key permission:** `usage_read`

**Path parameters**

| Name | Type | Notes |
| --- | --- | --- |
| `spaceId` | string (uuid) | required |
| `taskId` | string (uuid) | required |

**Responses**

| Status | Meaning |
| --- | --- |
| `200` | Task view |
| `404` | Error envelope `{"error":{"code","message","requestId"}}` |

```bash
curl -X GET "$RUNSTATE_BASE_URL/v1/spaces/$RUNSTATE_SPACE_ID/ops/tasks/<taskId>" \
  -H "Authorization: Bearer $RUNSTATE_API_KEY"
```

## POST /tasks/admit

```http
POST /v1/spaces/{spaceId}/tasks/admit
```

Resource-aware admission; atomically claims a delivery plus declared resources.

Discovery picks READY deliveries FIFO; each candidate is re-checked under the documented multi-resource lock order. 204 when nothing can be admitted (after the waitMs long poll, if one was requested); an empty admit stores no response under its Idempotency-Key. The pool grants and work-limit slot are released with the delivery (complete, nack, or lease expiry) and renewed with it; quota consumptions are spent. Raw recv remains a bypass outside this guarantee.

- **Key permission:** `coordination_write`
- **Idempotency-Key header:** required
- **TypeScript SDK:** `mailbox.admit()`
- **Python SDK:** `mailbox.admit()`

**Path parameters**

| Name | Type | Notes |
| --- | --- | --- |
| `spaceId` | string (uuid) | required |

**Request body** (JSON)

| Field | Type | Required | Notes |
| --- | --- | --- | --- |
| `scopeId` | string (uuid) | yes |  |
| `mailboxId` | string (uuid) | yes |  |
| `holder` | string | yes |  |
| `holderSession` | string | yes |  |
| `leaseSeconds` | integer | no | default `30` |
| `waitMs` | integer | no | 0–120000; Long-poll an empty receive for up to this many milliseconds (capped by the server at api.longPollMaxWaitMs; 0 or absent answers at once). Returns as soon as work is available, when the wait ends, or when the API starts draining. An empty long poll of at least 1000 ms does not count toward request rate limits. |

**Responses**

| Status | Meaning |
| --- | --- |
| `200` | Admitted delivery with token and claimed resources |
| `204` | Nothing admissible right now |

```bash
curl -X POST "$RUNSTATE_BASE_URL/v1/spaces/$RUNSTATE_SPACE_ID/tasks/admit" \
  -H "Authorization: Bearer $RUNSTATE_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{"scopeId":"<run id>","mailboxId":"<mailboxId>","holder":"worker-1","holderSession":"<session id>"}'
```
