Workbenches is an open standard. Read why
Docs API keys and login

API reference

API keys and login

Keys#

Keys are managed by signed-in members in the dashboard. A key cannot create or revoke keys.

List keys#

GET /v1/keys

Session: member.

Query Type Meaning
organization slug Required. The organization.

Response 200:

{
    "keys": [
        {
            "id": "uuid",
            "organization_id": "uuid",
            "prefix": "wb_a1b2c3d4",
            "label": "CI",
            "scopes": ["runs:read", "runs:write"],
            "created_by": "uuid",
            "expires_at": "2027-01-26T12:00:00Z",
            "last_used_at": null,
            "revoked_at": null,
            "created_at": "2026-10-28T12:00:00Z"
        }
    ]
}

prefix is the first 11 characters of the token, to identify a key. Only a hash of the token is stored.

Create a key#

POST /v1/keys

Session: manager.

Field Type Meaning
organization_id UUID Required.
label string, 1 to 120 characters Required.
scopes list of catalog:read, packages:write, runs:read, runs:write, org:admin Required.
expires_in_days integer, 1 to 365 Default 90.

Response 201: the key, as in the list, plus token, wb_ and 64 hex characters. The token is returned once.

Revoke a key#

DELETE /v1/keys/:id

Session: the key's creator, or a manager of its organization. Response 200 { "deleted": true }.

Profile#

GET /v1/profile

Any key. Sessions are refused. Returns who the key is:

{
    "organization": {
        "id": "uuid",
        "slug": "acme",
        "name": "Acme",
        "description": null,
        "website": null,
        "logo_url": null,
        "accent": null,
        "verified": false,
        "personal": false,
        "created_at": "...",
        "updated_at": "..."
    },
    "user": { "id": "uuid", "email": "ada@example.com" },
    "scopes": ["catalog:read", "packages:write", "runs:read", "runs:write"],
    "key": { "id": "uuid", "label": "wb CLI", "expires_at": "..." }
}

user is null for a key with no owning user. wb whoami shows the same.

MCP connections#

Keys created by an MCP client's OAuth sign-in, for the signed-in user.

List connections#

GET /v1/connections

Session only.

Query Type Meaning
organization slug Required.

Response 200 { "connections": [ { "id", "organization_id", "client_name", "connected_at", "last_used_at", "expires_at" } ] }.

Disconnect#

DELETE /v1/connections/:id

Session only: the user who approved it. Revokes the key. Response 200 { "deleted": true }. 404 for an ID that is not an MCP connection.

CLI login#

The device flow wb login uses to get a key. A login lasts 10 minutes, and the client polls at the returned interval.

Start a login#

POST /v1/logins

Open.

Field Type Meaning
label string, 1 to 120 characters Required. The key's label.

Response 201:

Field Meaning
id The login.
code The user code, such as ABCD-1234.
label The label.
verification_url Where the user approves.
expires_at When the login expires.
interval Seconds between polls, 1 to 30.
approved false.
secret A one-time secret, 64 hex characters. Keep it; it proves the exchange.

Read a login#

GET /v1/logins/:id

Open. The same fields without secret.

Approve a login#

PATCH /v1/logins/:id with { "organization_id": "uuid" }

Session only. The user approves the login for one of their organizations. Response 200 { "approved": true }. The dashboard's approval page does this for you.

Exchange for a key#

POST /v1/tokens

Open; the request proves the secret.

Field Type
login_id UUID
secret 64 hex characters

Response 200: { "status": "pending" } until approved, then:

{
    "status": "complete",
    "token": "wb_...",
    "key_id": "uuid",
    "organization": {
        "id": "uuid",
        "slug": "acme",
        "name": "Acme",
        "...": "..."
    },
    "scopes": ["catalog:read", "packages:write", "runs:read", "runs:write"],
    "expires_at": "..."
}

The key holds every scope except org:admin and lasts 90 days.