---
title: "Runs – Superbot API"
canonical_url: "https://superbot.gg/developers/runs"
last_updated: "2026-10-01"
summary: "Cloud agent runs: start one on a project, follow its events, cancel it, and get a signed webhook when it settles."
---

> Markdown twin of https://superbot.gg/developers/runs (the HTML page is canonical).
> The site index for agents is /llms.txt; every content page has a twin at its path plus `.md`.

# Runs

Cloud agent runs: start one on a project, follow its events, cancel it, and get a signed webhook when it settles.

Base URL: `https://superbot.gg`. Errors: [https://superbot.gg/developers#errors](https://superbot.gg/developers#errors). Spec: [https://superbot.gg/docs/openapi.json](https://superbot.gg/docs/openapi.json).

## Operations

- [List cloud runs](https://superbot.gg/developers/runs/listRuns.md): `GET /v1/runs`
- [Start a cloud run](https://superbot.gg/developers/runs/createRun.md): `POST /v1/runs`
- [Find the project for a repository](https://superbot.gg/developers/runs/listRunProjects.md): `GET /v1/runs/projects`
- [Get a cloud run](https://superbot.gg/developers/runs/getRun.md): `GET /v1/runs/{run_id}`
- [Follow a run’s events](https://superbot.gg/developers/runs/listRunEvents.md): `GET /v1/runs/{run_id}/events`
- [Cancel a cloud run](https://superbot.gg/developers/runs/cancelRun.md): `POST /v1/runs/{run_id}/cancel`
- [Steer a running cloud run](https://superbot.gg/developers/runs/sendRunMessage.md): `POST /v1/runs/{run_id}/messages`

## List cloud runs

`GET /v1/runs`

This account’s cloud runs from every source, oldest first, paged by run id.

- Operation id: `listRuns`
- Group: [Runs](https://superbot.gg/developers/runs.md)
- Auth: A caller key holding `runs:read` (`Authorization: Bearer sbc_…` or `x-api-key: sbc_…`), or a signed-in session.
- Scopes: `runs:read`

### Query parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `limit` | integer | optional | Items per page, 1-100. |
| `after_id` | string | optional | Return the page after this resource id (the previous page’s `last_id`). |
| `before_id` | string | optional | Return the page before this resource id (the next page’s `first_id`). |
| `status` | string | optional | Only runs in this status. One of `queued`, `running`, `done`, `failed`, `needs_merge`, `cancelled`. |
| `source` | string | optional | Only runs started by this source. One of `app`, `api`, `cli`, `routine`, `slack`, `linear`, `jira`, `github`. |

### Response 200

A page of runs.

`application/json`: RunList.

- `object` (string, required): One of `list`.
- `data` (array of Run, required)
  - `id` (string, required)
  - `object` (string, required): One of `run`.
  - `status` (string, required): `queued`, `running`, then one of `done`, `failed`, `needs_merge` (the work is on `branch` and waits for a merge) or `cancelled`. One of `queued`, `running`, `done`, `failed`, `needs_merge`, `cancelled`.
  - `source` (string, required): What started the run. Runs started here are `api`. One of `app`, `api`, `cli`, `routine`, `slack`, `linear`, `jira`, `github`.
  - `project` (string, required): The project the run works on.
  - `prompt` (string | null, required): The prompt, which is also the run’s title: show this to name the run. Null under zero data retention.
  - `mode` (string, required): One of `agent`, `plan`, `debug`.
  - `landing` (string, required): `main` lands the work on the default branch; `pr` opens a pull request. One of `main`, `pr`.
  - `budget` (RunBudget, required): What the run may spend: wall time, USD and legs.
    - `max_wall_ms` (integer, required)
    - `max_usd` (number, required)
    - `max_legs` (integer, required)
    - `leg_ms` (integer, required)
  - `usd_spent` (number | null, required)
  - `branch` (string | null, required): The branch the work sits on, when it did not land directly.
  - `landed_commit` (string | null, required)
  - `summary` (string | null, required): The runner’s end-of-run diagnostic once it settles, a machine-readable line for debugging and for telling a failed run from a finished one (for example `done — sandbox fence-only, 127 tool call(s), local space sp_…`), and it can name internal ids. It is not a title and not the run’s answer: name the run by `prompt`, and do not show this text to end users. Null under zero data retention.
  - `pr_url` (string | null, required)
  - `url` (string | null, required): A deep link that opens the run’s project in the Superbot app (`superbot://project/<id>`), when the project id is linkable.
  - `created_at` (string, required)
  - `updated_at` (string, required)
- `has_more` (boolean, required)
- `first_id` (string | null, required): Id of the first item on this page; pass as `before_id` for the previous page.
- `last_id` (string | null, required): Id of the last item on this page; pass as `after_id` for the next page.

### Errors

Every refusal carries `error`, `message`, `doc_url` and `request_id`; the gateway routes answer in the dialect you dialed.

| Status | Codes | When |
| --- | --- | --- |
| 400 | [`invalid_request`](https://superbot.gg/developers#errors-invalid_request) | The request is malformed or a parameter is invalid; `param` names the field. |
| 401 | [`unauthorized`](https://superbot.gg/developers#errors-unauthorized) | The bearer is missing, malformed or unknown. |
| 403 | [`insufficient_scope`](https://superbot.gg/developers#errors-insufficient_scope) | The key lacks a scope (insufficient_scope), is revoked, or may not call this route. |
| 429 | [`rate_limited`](https://superbot.gg/developers#errors-rate_limited) | Over the per-key request bucket; retry after x-ratelimit-reset. |

### Examples

```sh
curl -sS -X GET "https://superbot.gg/v1/runs" \
  -H "Authorization: Bearer $SUPERBOT_API_KEY"
```

```js
const res = await fetch(`https://superbot.gg/v1/runs`, {
  method: 'GET',
  headers: {
    Authorization: `Bearer ${process.env.SUPERBOT_API_KEY}`,
  },
});
console.log(res.status, await res.json());
```

```python
import os
import requests

res = requests.request(
    "GET",
    "https://superbot.gg/v1/runs",
    headers={
        "Authorization": f"Bearer {os.environ['SUPERBOT_API_KEY']}",
    },
)
print(res.status_code, res.json())
```

## Start a cloud run

`POST /v1/runs`

Queue a cloud agent run on a project. Refusals: 400 `invalid_mode`, `invalid_landing`, `invalid_prompt`, `missing_space`, `invalid_webhook_url`; 429 `run_concurrency_limit` (the account) or `key_run_limit` (this key, default 5 queued or running), with `Retry-After`. Asks the run raises are answered deny, since a key cannot answer them.

- Operation id: `createRun`
- Group: [Runs](https://superbot.gg/developers/runs.md)
- Auth: A caller key holding `runs:write` (`Authorization: Bearer sbc_…` or `x-api-key: sbc_…`), or a signed-in session.
- Scopes: `runs:write`

### Request body

`application/json`, required.

- `project` (string, required): The project to run on.
- `prompt` (string, required): What the agent should do.
- `mode` (string): One of `agent`, `plan`, `debug`. Default `agent`.
- `landing` (string): One of `main`, `pr`. Default `main`.
- `budget` (object): Caps for this run. Absent fields fall back to your saved defaults.
  - `minutes` (number)
  - `usd` (number)
  - `legs` (integer)
- `webhook_url` (string): A public https URL that receives a signed `run.settled` POST when the run settles.

### Response 201

The queued run.

`application/json`: CreatedRun.

- `id` (string, required)
- `object` (string, required): One of `run`.
- `status` (string, required): `queued`, `running`, then one of `done`, `failed`, `needs_merge` (the work is on `branch` and waits for a merge) or `cancelled`. One of `queued`, `running`, `done`, `failed`, `needs_merge`, `cancelled`.
- `source` (string, required): What started the run. Runs started here are `api`. One of `app`, `api`, `cli`, `routine`, `slack`, `linear`, `jira`, `github`.
- `project` (string, required): The project the run works on.
- `prompt` (string | null, required): The prompt, which is also the run’s title: show this to name the run. Null under zero data retention.
- `mode` (string, required): One of `agent`, `plan`, `debug`.
- `landing` (string, required): `main` lands the work on the default branch; `pr` opens a pull request. One of `main`, `pr`.
- `budget` (RunBudget, required): What the run may spend: wall time, USD and legs.
  - `max_wall_ms` (integer, required)
  - `max_usd` (number, required)
  - `max_legs` (integer, required)
  - `leg_ms` (integer, required)
- `usd_spent` (number | null, required)
- `branch` (string | null, required): The branch the work sits on, when it did not land directly.
- `landed_commit` (string | null, required)
- `summary` (string | null, required): The runner’s end-of-run diagnostic once it settles, a machine-readable line for debugging and for telling a failed run from a finished one (for example `done — sandbox fence-only, 127 tool call(s), local space sp_…`), and it can name internal ids. It is not a title and not the run’s answer: name the run by `prompt`, and do not show this text to end users. Null under zero data retention.
- `pr_url` (string | null, required)
- `url` (string | null, required): A deep link that opens the run’s project in the Superbot app (`superbot://project/<id>`), when the project id is linkable.
- `created_at` (string, required)
- `updated_at` (string, required)
- `webhook_secret` (string): The signing secret for `webhook_url`, returned ONCE, here. Verify each delivery: `X-Superbot-Signature: t=<unix>,v1=<hex>` where v1 is HMAC-SHA256(secret, `t + "." + body`).

### Errors

Every refusal carries `error`, `message`, `doc_url` and `request_id`; the gateway routes answer in the dialect you dialed.

| Status | Codes | When |
| --- | --- | --- |
| 400 | [`invalid_request`](https://superbot.gg/developers#errors-invalid_request) | The request is malformed or a parameter is invalid; `param` names the field. |
| 401 | [`unauthorized`](https://superbot.gg/developers#errors-unauthorized) | The bearer is missing, malformed or unknown. |
| 403 | [`insufficient_scope`](https://superbot.gg/developers#errors-insufficient_scope) | The key lacks a scope (insufficient_scope), is revoked, or may not call this route. |
| 429 | [`rate_limited`](https://superbot.gg/developers#errors-rate_limited) | Over the per-key request bucket; retry after x-ratelimit-reset. |

### Examples

```sh
curl -sS -X POST "https://superbot.gg/v1/runs" \
  -H "Authorization: Bearer $SUPERBOT_API_KEY" \
  -H "content-type: application/json" \
  -d '{"project":"prj_7f3a","prompt":"Fix the flaky login test."}'
```

```js
const res = await fetch(`https://superbot.gg/v1/runs`, {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.SUPERBOT_API_KEY}`,
    'content-type': 'application/json',
  },
  body: JSON.stringify({"project":"prj_7f3a","prompt":"Fix the flaky login test."}),
});
console.log(res.status, await res.json());
```

```python
import os
import requests

res = requests.request(
    "POST",
    "https://superbot.gg/v1/runs",
    headers={
        "Authorization": f"Bearer {os.environ['SUPERBOT_API_KEY']}",
        "content-type": "application/json",
    },
    json={"project":"prj_7f3a","prompt":"Fix the flaky login test."},
)
print(res.status_code, res.json())
```

## Find the project for a repository

`GET /v1/runs/projects`

Your projects whose linked repository is `repo`, compared after normalising the URL (scheme, `git@host:` form, a trailing `.git` and case do not matter). Pass a returned `id` as `project` to createRun. Only `id` and `name` are returned. An empty list means no project is linked to that repository. Refusal: 400 `invalid_repo`.

- Operation id: `listRunProjects`
- Group: [Runs](https://superbot.gg/developers/runs.md)
- Auth: A caller key holding `runs:read` (`Authorization: Bearer sbc_…` or `x-api-key: sbc_…`), or a signed-in session.
- Scopes: `runs:read`

### Query parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `repo` | string | required | The repository URL: `https://github.com/o/r`, `ssh://git@github.com/o/r.git` or `git@github.com:o/r.git` all match the same project. |

### Response 200

The matching projects, possibly none.

`application/json`: RunProjectList.

- `projects` (array of object, required)
  - `id` (string, required): The project id to pass as `project` to createRun.
  - `name` (string, required): The project’s name in the Superbot app.

### Errors

Every refusal carries `error`, `message`, `doc_url` and `request_id`; the gateway routes answer in the dialect you dialed.

| Status | Codes | When |
| --- | --- | --- |
| 400 | [`invalid_request`](https://superbot.gg/developers#errors-invalid_request) | The request is malformed or a parameter is invalid; `param` names the field. |
| 401 | [`unauthorized`](https://superbot.gg/developers#errors-unauthorized) | The bearer is missing, malformed or unknown. |
| 403 | [`insufficient_scope`](https://superbot.gg/developers#errors-insufficient_scope) | The key lacks a scope (insufficient_scope), is revoked, or may not call this route. |
| 429 | [`rate_limited`](https://superbot.gg/developers#errors-rate_limited) | Over the per-key request bucket; retry after x-ratelimit-reset. |

### Examples

```sh
curl -sS -X GET "https://superbot.gg/v1/runs/projects?repo=https%3A%2F%2Fgithub.com%2Facme%2Fapp" \
  -H "Authorization: Bearer $SUPERBOT_API_KEY"
```

```js
const res = await fetch(`https://superbot.gg/v1/runs/projects?repo=https%3A%2F%2Fgithub.com%2Facme%2Fapp`, {
  method: 'GET',
  headers: {
    Authorization: `Bearer ${process.env.SUPERBOT_API_KEY}`,
  },
});
console.log(res.status, await res.json());
```

```python
import os
import requests

res = requests.request(
    "GET",
    "https://superbot.gg/v1/runs/projects?repo=https%3A%2F%2Fgithub.com%2Facme%2Fapp",
    headers={
        "Authorization": f"Bearer {os.environ['SUPERBOT_API_KEY']}",
    },
)
print(res.status_code, res.json())
```

## Get a cloud run

`GET /v1/runs/{run_id}`

One run as it stands now.

- Operation id: `getRun`
- Group: [Runs](https://superbot.gg/developers/runs.md)
- Auth: A caller key holding `runs:read` (`Authorization: Bearer sbc_…` or `x-api-key: sbc_…`), or a signed-in session.
- Scopes: `runs:read`

### Path parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `run_id` | string | required | The run id (a Run `id`). |

### Response 200

The run.

`application/json`: Run.

- `id` (string, required)
- `object` (string, required): One of `run`.
- `status` (string, required): `queued`, `running`, then one of `done`, `failed`, `needs_merge` (the work is on `branch` and waits for a merge) or `cancelled`. One of `queued`, `running`, `done`, `failed`, `needs_merge`, `cancelled`.
- `source` (string, required): What started the run. Runs started here are `api`. One of `app`, `api`, `cli`, `routine`, `slack`, `linear`, `jira`, `github`.
- `project` (string, required): The project the run works on.
- `prompt` (string | null, required): The prompt, which is also the run’s title: show this to name the run. Null under zero data retention.
- `mode` (string, required): One of `agent`, `plan`, `debug`.
- `landing` (string, required): `main` lands the work on the default branch; `pr` opens a pull request. One of `main`, `pr`.
- `budget` (RunBudget, required): What the run may spend: wall time, USD and legs.
  - `max_wall_ms` (integer, required)
  - `max_usd` (number, required)
  - `max_legs` (integer, required)
  - `leg_ms` (integer, required)
- `usd_spent` (number | null, required)
- `branch` (string | null, required): The branch the work sits on, when it did not land directly.
- `landed_commit` (string | null, required)
- `summary` (string | null, required): The runner’s end-of-run diagnostic once it settles, a machine-readable line for debugging and for telling a failed run from a finished one (for example `done — sandbox fence-only, 127 tool call(s), local space sp_…`), and it can name internal ids. It is not a title and not the run’s answer: name the run by `prompt`, and do not show this text to end users. Null under zero data retention.
- `pr_url` (string | null, required)
- `url` (string | null, required): A deep link that opens the run’s project in the Superbot app (`superbot://project/<id>`), when the project id is linkable.
- `created_at` (string, required)
- `updated_at` (string, required)

### Errors

Every refusal carries `error`, `message`, `doc_url` and `request_id`; the gateway routes answer in the dialect you dialed.

| Status | Codes | When |
| --- | --- | --- |
| 400 | [`invalid_request`](https://superbot.gg/developers#errors-invalid_request) | The request is malformed or a parameter is invalid; `param` names the field. |
| 401 | [`unauthorized`](https://superbot.gg/developers#errors-unauthorized) | The bearer is missing, malformed or unknown. |
| 403 | [`insufficient_scope`](https://superbot.gg/developers#errors-insufficient_scope) | The key lacks a scope (insufficient_scope), is revoked, or may not call this route. |
| 404 | [`not_found`](https://superbot.gg/developers#errors-not_found) | No such resource on this account. |
| 429 | [`rate_limited`](https://superbot.gg/developers#errors-rate_limited) | Over the per-key request bucket; retry after x-ratelimit-reset. |

### Examples

```sh
curl -sS -X GET "https://superbot.gg/v1/runs/$RUN_ID" \
  -H "Authorization: Bearer $SUPERBOT_API_KEY"
```

```js
const runId = 'RUN_ID';
const res = await fetch(`https://superbot.gg/v1/runs/${runId}`, {
  method: 'GET',
  headers: {
    Authorization: `Bearer ${process.env.SUPERBOT_API_KEY}`,
  },
});
console.log(res.status, await res.json());
```

```python
import os
import requests

run_id = "RUN_ID"
res = requests.request(
    "GET",
    f"https://superbot.gg/v1/runs/{run_id}",
    headers={
        "Authorization": f"Bearer {os.environ['SUPERBOT_API_KEY']}",
    },
)
print(res.status_code, res.json())
```

## Follow a run’s events

`GET /v1/runs/{run_id}/events`

With `Accept: text/event-stream`, server-sent events (`id` is the event `seq`; reconnect with `Last-Event-ID` to resume); the stream ends once the run is final. Otherwise JSON: the events after `after`, long-polled up to `wait` seconds.

- Operation id: `listRunEvents`
- Group: [Runs](https://superbot.gg/developers/runs.md)
- Auth: A caller key holding `runs:read` (`Authorization: Bearer sbc_…` or `x-api-key: sbc_…`), or a signed-in session.
- Scopes: `runs:read`

### Path parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `run_id` | string | required | The run id (a Run `id`). |

### Query parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `after` | string | optional | Only events with a greater `seq`. `Last-Event-ID` wins when both are sent. |
| `wait` | string | optional | Long-poll: hold the request up to this many seconds (max 25) for a new event. JSON replies only. |

### Response 200

The events.

`application/json`: RunEventList.

- `object` (string, required): One of `list`.
- `data` (array of RunEvent, required)
  - `object` (string, required): One of `run.event`.
  - `run_id` (string, required)
  - `seq` (integer, required): Per-run sequence number; the SSE `id`, and what `after` / `Last-Event-ID` resume from.
  - `type` (string, required): One of `status`, `result`, `pr`, `note_queued`, `note_delivered`.
  - `created_at` (string, required)
  - `note_id` (string): On `note_queued` / `note_delivered`: the note’s id (never its text).
  - `length` (integer): On `note_queued` / `note_delivered`: the note’s length in characters.
  - `status` (string): One of `queued`, `running`, `done`, `failed`, `needs_merge`, `cancelled`.
  - `branch` (string)
  - `landed_commit` (string)
  - `usd_spent` (number)
  - `summary` (string | null): On `result` only: the runner’s end-of-run diagnostic, as `summary` on the run (not a title or an answer). Null under zero data retention.
  - `pr_url` (string)
  - `pr_number` (integer)
  - `pr_state` (string)
  - `publish_error` (string)
- `next_after` (integer, required): Pass as `after` on the next poll.
- `done` (boolean, required): True once nothing more will happen to the run.

`text/event-stream`: string.

### Errors

Every refusal carries `error`, `message`, `doc_url` and `request_id`; the gateway routes answer in the dialect you dialed.

| Status | Codes | When |
| --- | --- | --- |
| 400 | [`invalid_request`](https://superbot.gg/developers#errors-invalid_request) | The request is malformed or a parameter is invalid; `param` names the field. |
| 401 | [`unauthorized`](https://superbot.gg/developers#errors-unauthorized) | The bearer is missing, malformed or unknown. |
| 403 | [`insufficient_scope`](https://superbot.gg/developers#errors-insufficient_scope) | The key lacks a scope (insufficient_scope), is revoked, or may not call this route. |
| 404 | [`not_found`](https://superbot.gg/developers#errors-not_found) | No such resource on this account. |
| 429 | [`rate_limited`](https://superbot.gg/developers#errors-rate_limited) | Over the per-key request bucket; retry after x-ratelimit-reset. |

### Examples

```sh
curl -sS -X GET "https://superbot.gg/v1/runs/$RUN_ID/events" \
  -H "Authorization: Bearer $SUPERBOT_API_KEY"
```

```js
const runId = 'RUN_ID';
const res = await fetch(`https://superbot.gg/v1/runs/${runId}/events`, {
  method: 'GET',
  headers: {
    Authorization: `Bearer ${process.env.SUPERBOT_API_KEY}`,
  },
});
console.log(res.status, await res.json());
```

```python
import os
import requests

run_id = "RUN_ID"
res = requests.request(
    "GET",
    f"https://superbot.gg/v1/runs/{run_id}/events",
    headers={
        "Authorization": f"Bearer {os.environ['SUPERBOT_API_KEY']}",
    },
)
print(res.status_code, res.json())
```

## Cancel a cloud run

`POST /v1/runs/{run_id}/cancel`

Stop the run. A run that already settled is returned as it is.

- Operation id: `cancelRun`
- Group: [Runs](https://superbot.gg/developers/runs.md)
- Auth: A caller key holding `runs:write` (`Authorization: Bearer sbc_…` or `x-api-key: sbc_…`), or a signed-in session.
- Scopes: `runs:write`

### Path parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `run_id` | string | required | The run id (a Run `id`). |

### Response 200

The run after the cancel.

`application/json`: Run.

- `id` (string, required)
- `object` (string, required): One of `run`.
- `status` (string, required): `queued`, `running`, then one of `done`, `failed`, `needs_merge` (the work is on `branch` and waits for a merge) or `cancelled`. One of `queued`, `running`, `done`, `failed`, `needs_merge`, `cancelled`.
- `source` (string, required): What started the run. Runs started here are `api`. One of `app`, `api`, `cli`, `routine`, `slack`, `linear`, `jira`, `github`.
- `project` (string, required): The project the run works on.
- `prompt` (string | null, required): The prompt, which is also the run’s title: show this to name the run. Null under zero data retention.
- `mode` (string, required): One of `agent`, `plan`, `debug`.
- `landing` (string, required): `main` lands the work on the default branch; `pr` opens a pull request. One of `main`, `pr`.
- `budget` (RunBudget, required): What the run may spend: wall time, USD and legs.
  - `max_wall_ms` (integer, required)
  - `max_usd` (number, required)
  - `max_legs` (integer, required)
  - `leg_ms` (integer, required)
- `usd_spent` (number | null, required)
- `branch` (string | null, required): The branch the work sits on, when it did not land directly.
- `landed_commit` (string | null, required)
- `summary` (string | null, required): The runner’s end-of-run diagnostic once it settles, a machine-readable line for debugging and for telling a failed run from a finished one (for example `done — sandbox fence-only, 127 tool call(s), local space sp_…`), and it can name internal ids. It is not a title and not the run’s answer: name the run by `prompt`, and do not show this text to end users. Null under zero data retention.
- `pr_url` (string | null, required)
- `url` (string | null, required): A deep link that opens the run’s project in the Superbot app (`superbot://project/<id>`), when the project id is linkable.
- `created_at` (string, required)
- `updated_at` (string, required)

### Errors

Every refusal carries `error`, `message`, `doc_url` and `request_id`; the gateway routes answer in the dialect you dialed.

| Status | Codes | When |
| --- | --- | --- |
| 400 | [`invalid_request`](https://superbot.gg/developers#errors-invalid_request) | The request is malformed or a parameter is invalid; `param` names the field. |
| 401 | [`unauthorized`](https://superbot.gg/developers#errors-unauthorized) | The bearer is missing, malformed or unknown. |
| 403 | [`insufficient_scope`](https://superbot.gg/developers#errors-insufficient_scope) | The key lacks a scope (insufficient_scope), is revoked, or may not call this route. |
| 404 | [`not_found`](https://superbot.gg/developers#errors-not_found) | No such resource on this account. |
| 429 | [`rate_limited`](https://superbot.gg/developers#errors-rate_limited) | Over the per-key request bucket; retry after x-ratelimit-reset. |

### Examples

```sh
curl -sS -X POST "https://superbot.gg/v1/runs/$RUN_ID/cancel" \
  -H "Authorization: Bearer $SUPERBOT_API_KEY"
```

```js
const runId = 'RUN_ID';
const res = await fetch(`https://superbot.gg/v1/runs/${runId}/cancel`, {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.SUPERBOT_API_KEY}`,
  },
});
console.log(res.status, await res.json());
```

```python
import os
import requests

run_id = "RUN_ID"
res = requests.request(
    "POST",
    f"https://superbot.gg/v1/runs/{run_id}/cancel",
    headers={
        "Authorization": f"Bearer {os.environ['SUPERBOT_API_KEY']}",
    },
)
print(res.status_code, res.json())
```

## Steer a running cloud run

`POST /v1/runs/{run_id}/messages`

Add a note to a run that is queued or running. The run is not restarted: it reads the note at its next step boundary (never mid-step) and carries on with it as a note from you. Notes are applied oldest first. Refusals: 409 `run_not_active` (the run settled); 400 `invalid_note` or `note_too_long` (over 8192 bytes); 429 `too_many_notes` (20 notes already waiting), with `Retry-After`. The run's events record `note_queued` and `note_delivered` with the note id and length, never its text.

- Operation id: `sendRunMessage`
- Group: [Runs](https://superbot.gg/developers/runs.md)
- Auth: A caller key holding `runs:write` (`Authorization: Bearer sbc_…` or `x-api-key: sbc_…`), or a signed-in session.
- Scopes: `runs:write`

### Path parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `run_id` | string | required | The run id (a Run `id`). |

### Request body

`application/json`, required.

- `text` (string, required): The note, up to 8192 bytes of UTF-8.

### Response 202

The note, queued.

`application/json`: RunNote.

- `id` (string, required)
- `object` (string, required): One of `run.note`.
- `run_id` (string, required)
- `queued_at` (string, required)

### Errors

Every refusal carries `error`, `message`, `doc_url` and `request_id`; the gateway routes answer in the dialect you dialed.

| Status | Codes | When |
| --- | --- | --- |
| 400 | [`invalid_request`](https://superbot.gg/developers#errors-invalid_request) | The request is malformed or a parameter is invalid; `param` names the field. |
| 401 | [`unauthorized`](https://superbot.gg/developers#errors-unauthorized) | The bearer is missing, malformed or unknown. |
| 403 | [`insufficient_scope`](https://superbot.gg/developers#errors-insufficient_scope) | The key lacks a scope (insufficient_scope), is revoked, or may not call this route. |
| 404 | [`not_found`](https://superbot.gg/developers#errors-not_found) | No such resource on this account. |
| 409 | [`conflict`](https://superbot.gg/developers#errors-conflict) | The resource is not in a state that allows this change. |
| 429 | [`rate_limited`](https://superbot.gg/developers#errors-rate_limited) | Over the per-key request bucket; retry after x-ratelimit-reset. |

### Examples

```sh
curl -sS -X POST "https://superbot.gg/v1/runs/$RUN_ID/messages" \
  -H "Authorization: Bearer $SUPERBOT_API_KEY" \
  -H "content-type: application/json" \
  -d '{"text":"Skip the migration for now and focus on the failing test."}'
```

```js
const runId = 'RUN_ID';
const res = await fetch(`https://superbot.gg/v1/runs/${runId}/messages`, {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.SUPERBOT_API_KEY}`,
    'content-type': 'application/json',
  },
  body: JSON.stringify({"text":"Skip the migration for now and focus on the failing test."}),
});
console.log(res.status, await res.json());
```

```python
import os
import requests

run_id = "RUN_ID"
res = requests.request(
    "POST",
    f"https://superbot.gg/v1/runs/{run_id}/messages",
    headers={
        "Authorization": f"Bearer {os.environ['SUPERBOT_API_KEY']}",
        "content-type": "application/json",
    },
    json={"text":"Skip the migration for now and focus on the failing test."},
)
print(res.status_code, res.json())
```
