> ## Documentation Index
> Fetch the complete documentation index at: https://instabox.sh/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# API keys

> Make a key, send it, pick its scopes, and know which workspace it reaches.

An API key (`ibk_...`) is how code, CI jobs, and agents call InstaBox: the HTTP API, the SDK, the CLI,
and SSH all accept one. People sign in with GitHub or Google to use the dashboard and to make keys.

```bash theme={null}
export INSTABOX_API_KEY=ibk_...
curl -H "X-API-Key: $INSTABOX_API_KEY" https://api.instabox.sh/v1/machines
```

Send the key as `X-API-Key: <key>` or `Authorization: Bearer <key>`. The CLI and the SDK read the key
from `INSTABOX_API_KEY`, and the server from `INSTABOX_API_URL` (default `https://api.instabox.sh`).
With the key set, the CLI needs no `instabox login`.

## Make a key

> [tab] Dashboard
>
> Choose **API keys** in the sidebar, then **Create Key**
> ([dashboard.instabox.sh/dashboard/api-keys](https://dashboard.instabox.sh/dashboard/api-keys)).
> **Full access** suits the SDK, and **Restricted** picks scopes. The key belongs to the workspace
> selected in the sidebar.

> [tab] CLI
>
> ```bash theme={null}
> instabox keys create --name ci             # a key of your personal workspace
> instabox keys create --name ci --org team  # a key of workspace team (its owner or an admin)
> instabox keys ls
> instabox keys rm <key>
> ```

> [tab] An agent
>
> With nobody at the keyboard, run `instabox login --agent`, then approve it.
> See [Agent sign-up](https://instabox.sh/docs/security/agent-sign-up.md).

You see the secret once. Only a sign-in makes and revokes keys, so a key never makes another key.
Revoking a key also ends its SSH certificates.

## Pick a key's scopes

| Scope | Allows |
| - | - |
| `machines:read` | list and get machines, operations, metrics and usage |
| `machines:write` | create, start, stop, pause, resume, resize, set auto-pause and labels, exec, files and SSH |
| `machines:delete` | delete machines |
| `images:read`, `images:write`, `images:delete` | list, save and delete snapshots |
| `workspace:admin` | a workspace's key only: everything above plus the workspace's members, invites and Secrets, as an admin of that workspace |

Write and delete include read. Without `--scope`, `instabox keys create` gives a personal key
`machines:read`, `machines:write`, `machines:delete`, and `images:read`, and a workspace key
`workspace:admin`.

> [!NOTE]
>
> Give `images:read` to keys that create machines. The SDK and CLI use it to look snapshot names up.

> [!WARNING]
>
> A key with `machines:write` can select [Org Secrets](https://instabox.sh/docs/security/secrets.md) for a machine and run code
> there, and that code can send the selected Secrets to their allowed hosts. For a new machine that
> should get credentials from neither store, pass `"vault": false, "secrets": []` on create.

## Which workspace a key reaches

Every key belongs to exactly one workspace and reaches nothing outside it.

* A key made with `instabox keys create` (no `--org`), with `POST /v1/keys`, or on **API keys** with
  your personal workspace selected belongs to your personal workspace. One made with `--org W`, with
  `POST /v1/orgs/{id}/keys`, or with `W` selected belongs to `W`.
* Machines a key creates go in its workspace. Other workspaces' machines, snapshots, and settings are
  `404` to it, and so is a create naming another workspace's `orgId`.
* To work in another workspace, use a key of that workspace, which its owner or an admin makes. Only a
  sign-in reaches every workspace you belong to (`instabox create --org W`).
* To see a key's workspace, call `GET /v1/orgs` (`instabox workspace ls`) with it. It lists that one
  workspace. `GET /v1/me` also has `orgId` for a workspace key.

## Key errors

A bad key gets a `401` whose `error.code` says why: `missing_key`, `malformed_key`, `invalid_key`,
`expired_key`, or `revoked_key`. A key without the scope a route needs gets `403 missing_scope`, and
`requiredScopes` names the scopes that route accepts. See [Errors](https://instabox.sh/docs/reference/errors.md).

## What a key cannot do

Some routes take a sign-in (`instabox login` or the dashboard) and refuse any API key with
`403 permission_denied` ("API keys cannot be used on this route"). They cover managing API keys, your
Vault, GitHub CI installations and jobs, creating and deleting workspaces, billing, and sessions.

A workspace's [Org Secrets](https://instabox.sh/docs/security/secrets.md) take a `workspace:admin` key instead. To set up CI,
install the GitHub App from the dashboard ([CI](https://instabox.sh/docs/use-cases/ci.md)).

> [accordion] Every route that refuses an API key
>
> * **API keys:** `GET /v1/keys`, `POST /v1/keys`, `DELETE /v1/keys/{id}`, `GET /v1/orgs/{id}/keys`,
>   `POST /v1/orgs/{id}/keys`, `DELETE /v1/orgs/{id}/keys/{keyId}`
> * **Vault:** `GET /v1/vault`, `PUT /v1/vault/{name}`, `PATCH /v1/vault/{name}`,
>   `DELETE /v1/vault/{name}`, `POST /v1/vault/import`, `POST /v1/vault/{name}/export`
> * **GitHub CI:** `GET /v1/orgs/{id}/github/installations`,
>   `DELETE /v1/orgs/{id}/github/installations/{installationId}`, `GET /v1/orgs/{id}/github/jobs`,
>   `GET /v1/orgs/{id}/github/jobs/{job}`, `GET /v1/orgs/{id}/github/stats`
> * **Workspaces and billing:** `POST /v1/orgs`, `DELETE /v1/orgs/{id}`, `PATCH /v1/orgs/{id}/billing`,
>   `POST /v1/orgs/{id}/billing/checkout`, `POST /v1/orgs/{id}/billing/portal`,
>   `POST /v1/orgs/{id}/billing/plan`, `POST /v1/orgs/{id}/billing/credits/subscribe`,
>   `DELETE /v1/orgs/{id}/billing/subscription`, `POST /v1/orgs/{id}/billing/subscription/resume`
> * **Sessions:** `GET /v1/sessions`, `DELETE /v1/sessions/{id}`
>
> The [API reference](https://instabox.sh/docs/api-reference/introduction.md) lists every route a key can call.

> [card] [SDK quick start](https://instabox.sh/docs/integrations/sdk-quickstart.md)
>
> Use the key from TypeScript or HTTP.

> [card] [Agent sign-up](https://instabox.sh/docs/security/agent-sign-up.md)
>
> An agent gets its own key, approved by you.
