# Overview

The workbenches.dev API is one HTTP API at `https://api.workbenches.dev`. Every resource route is under `/v1`. The same routes serve the `wb` CLI, the dashboard, the MCP server, and your integrations; what differs is the credential.

- Request and response bodies are JSON with snake_case fields.
- Direct resource URLs take UUIDs, except runs, sessions, and commands (see [Identifiers](#identifiers)).
- Actions that are not plain create, read, update, or delete are modelled as resources, such as `POST /v1/searches` and `POST /v1/resolutions`.

Two other surfaces sit outside `/v1`: the OCI image registry at `images.workbenches.dev/v2` (see [Images](/docs/api/images)), and the OAuth routes at `/oauth/*` and `/.well-known/*` that MCP clients use (see [Connect](/docs/mcp/connect#oauth)).

## Authentication

Every request carries one of two credentials.

### Organization API keys

```sh
curl https://api.workbenches.dev/v1/profile \
  -H "Authorization: Bearer wb_..."
```

A key belongs to one organization, holds one or more scopes, and always expires. Tokens are `wb_` followed by 64 hex characters. A key always acts in its own organization.

Keys come from:

- the dashboard, where an owner or admin chooses scopes and an expiry of 1 to 365 days (default 90),
- `wb login`, which holds every scope except `org:admin` and lasts 90 days,
- an MCP client's OAuth sign-in, labelled `MCP: <client name>`, with the scopes granted (never `org:admin`) and 90 days.

A key stops working the moment its creator's membership in the organization ends. `Basic` authentication with a `wb_` token as the password is also accepted, so standard OCI clients work with the image registry.

### Browser sessions

The dashboard signs in with Google and uses a session cookie. Some routes accept only a session: they serve the dashboard and are marked "Session" in this reference. A mutating request with a session cookie must come from the dashboard origin; a request with an `Authorization` header counts as a key call and skips that check.

### Scopes

| Scope            | Allows                                                                                                                             |
| ---------------- | ---------------------------------------------------------------------------------------------------------------------------------- |
| `catalog:read`   | List and search the organization's Workbenches, including internal ones, its repositories, analytics, images, and billing account. |
| `packages:write` | Push versions, submit and unpublish Workbenches, read submissions, sync and discover GitHub repositories.                          |
| `runs:read`      | Read runs, sessions, events, outcomes, projects, and workers.                                                                      |
| `runs:write`     | Start runs, send them commands, create projects, and register workers.                                                             |
| `org:admin`      | Edit the organization and its logo.                                                                                                |

### Roles

Organization members have a role: `owner`, `admin`, or `member`. In this reference:

- **Key `scope`** means a key of the target organization holding that scope.
- **Session: member** means a signed-in member of any role.
- **Session: manager** means an owner or admin.
- **Manager creator** means a key whose creating user is currently an owner or admin. A demoted creator's keys lose that power immediately.
- **Open** means anonymous callers are accepted, and a key or session widens what they see.

A stale or invalid key on an open read is treated as anonymous.

## Errors

Errors have one shape:

```json
{
    "error": {
        "code": "not_found",
        "message": "Run not found",
        "request_id": "..."
    }
}
```

| Status | Code                  | Meaning                                                                              |
| ------ | --------------------- | ------------------------------------------------------------------------------------ |
| 400    | `validation_failed`   | The request did not match the contract. The message says which field.                |
| 401    | `unauthorized`        | No valid credential.                                                                 |
| 402    | `plan_limit`          | A plan or spend limit refused it. The message names the limit and how to raise it.   |
| 403    | `forbidden`           | The credential cannot do this: wrong organization, missing scope, or missing role.   |
| 404    | `not_found`           | It does not exist, or you cannot see it.                                             |
| 409    | `conflict`            | It conflicts with current state, such as a version that is not higher than the last. |
| 409    | `branch_in_use`       | Another unfinished run uses the requested branch.                                    |
| 409    | `worker_offline`      | The worker is not connected.                                                         |
| 413    | `payload_too_large`   | The body is over the route's limit.                                                  |
| 422    | `worker_unsuitable`   | The worker cannot run this Workbench.                                                |
| 422    | `unprocessable`       | The request is well formed but cannot be carried out.                                |
| 429    | `too_many_requests`   | Rate limited.                                                                        |
| 503    | `service_unavailable` | A dependency is unavailable.                                                         |
| 500    | `internal_error`      | An unexpected failure. Quote the `request_id`.                                       |

An internal Workbench, run, or other resource you cannot see is reported as not found. A run, session, or command that exists answers 403 to a caller outside its organization and to a key of its organization without the scope.

The `/oauth/*` routes use the OAuth shape instead: `{ "error", "error_description" }`. The image registry uses the OCI error format.

## Identifiers

| Resource                         | Form                                               |
| -------------------------------- | -------------------------------------------------- |
| Run                              | `wb_` followed by 24 lowercase letters and digits  |
| Session                          | `wbs_` followed by 24 lowercase letters and digits |
| Command                          | `wbc_` followed by 24 lowercase letters and digits |
| Everything else                  | UUID                                               |
| Organizations, projects, workers | Also have a slug: lowercase words joined by `-`    |

## Selecting the organization

A key always acts in its own organization. A browser session names the organization where a route needs one: with `organization` (a slug) on run, session, project, and worker routes, or `organization_id` (a UUID) on others. Each route lists which.

## Pagination

List routes that page take `limit` and `cursor` and return `next` (or `next_cursor`), the cursor for the following page, or `null` at the end. Pages are newest first.

## Health

| Method | Path         | Auth | Result                                                  |
| ------ | ------------ | ---- | ------------------------------------------------------- |
| GET    | `/v1/health` | Open | `{ "status": "healthy", "service": "workbenches-api" }` |
| GET    | `/v1/ready`  | Open | `{ "status" }`, after pinging the database.             |

## Route index

| Resource                                     | Page                                              |
| -------------------------------------------- | ------------------------------------------------- |
| Keys, profile, CLI login                     | [API keys and login](/docs/api/keys)              |
| Organizations, members, invitations, logos   | [Organizations](/docs/api/organizations)          |
| Workbenches, searches, versions, submissions | [Workbenches and registry](/docs/api/workbenches) |
| Runs and sessions                            | [Runs and sessions](/docs/api/runs)               |
| Run events, realtime                         | [Events](/docs/api/events)                        |
| Run commands                                 | [Commands](/docs/api/commands)                    |
| Outcomes, changes                            | [Outcomes and changes](/docs/api/outcomes)        |
| Projects                                     | [Projects](/docs/api/projects)                    |
| Secrets, OpenRouter                          | [Secrets](/docs/api/secrets)                      |
| Workers                                      | [Workers](/docs/api/workers)                      |
| GitHub, repositories, discoveries            | [GitHub and repositories](/docs/api/github)       |
| Images, pull credentials                     | [Images](/docs/api/images)                        |
| Billing                                      | [Billing](/docs/api/billing)                      |
| Run previews                                 | [Live previews](/docs/cloud/previews#api)         |
