# API keys

4 endpoints.

## List the permission vocabulary

```http
GET https://orbitwrite.com/api/v1/api-keys/permissions
```

Every resource, its actions, and what each workspace role grants. Use it to build the `scopes` object for `POST /api-keys`.

**Authentication:** session cookie.

### Responses

#### 200

The permission catalog

- `resources` (object, required) — Every resource and the actions defined on it. A key's `scopes` must be a subset.
- `roles` (object, required) — What each workspace role grants, in the same shape — so a key can be scoped to match a role.

#### 401

Not signed in

- `error` (string, required)
- `issues` (any[], optional)

## List a workspace's API keys

```http
GET https://orbitwrite.com/api/v1/api-keys
```

Returns key metadata (never the secret, which is only surfaced once on creation). Any member may read.

**Authentication:** session cookie.

### Query parameters

- `organizationId` (string, required)

### Responses

#### 200

The workspace's API keys

- `keys` (ApiKey[], required)
  - `id` (string, required)
  - `name` (string, required)
  - `keyPrefix` (string, required) — Non-sensitive prefix for the masked UI preview
  - `lastUsedAt` (string | null, required) — ISO 8601.
  - `createdAt` (string, required) — ISO 8601.
  - `scopes` (object | null, required) — What the key may do. `null` means full workspace authority — the implicit grant of every key minted before scopes existed.

#### 400

Invalid request

- `error` (string, required)
- `issues` (any[], optional)

#### 401

Not signed in

- `error` (string, required)
- `issues` (any[], optional)

#### 403

Not a member of the organization

- `error` (string, required)
- `issues` (any[], optional)

## Create an API key

```http
POST https://orbitwrite.com/api/v1/api-keys
```

Owner/admin only: a key grants programmatic, org-wide access, so minting one is a privileged action. The response carries the full secret exactly once.

**Authentication:** session cookie.

### Request body (`application/json`)

- `organizationId` (string, required)
- `name` (string, required)
- `scopes` (object, optional) — What the key may do, as `{ resource: [action, …] }` — e.g. `{"post": ["read", "create"], "tag": ["read"]}`. Omit to grant the key full workspace authority (the behaviour of every key minted before scopes existed). Prefer the narrowest set the integration needs. Valid resources and actions are listed in `GET /api-keys/permissions`.

### Responses

#### 200

The key was created; `secret` is shown once

- `ok` (boolean, required, one of `true`)
- `secret` (string, required) — The full key — surfaced exactly once, never retrievable again

#### 400

Invalid request

- `error` (string, required)
- `issues` (any[], optional)

#### 401

Not signed in

- `error` (string, required)
- `issues` (any[], optional)

#### 403

Not a member of the organization

- `error` (string, required)
- `issues` (any[], optional)

## Revoke an API key

```http
DELETE https://orbitwrite.com/api/v1/api-keys/{keyId}
```

Owner/admin only. The key stops authenticating immediately (its hash row is deleted).

**Authentication:** session cookie.

### Path parameters

- `keyId` (string, required)

### Query parameters

- `organizationId` (string, required)

### Responses

#### 200

The key was revoked

- `ok` (boolean, required, one of `true`)

#### 400

Invalid request

- `error` (string, required)
- `issues` (any[], optional)

#### 401

Not signed in

- `error` (string, required)
- `issues` (any[], optional)

#### 403

Not a member of the organization

- `error` (string, required)
- `issues` (any[], optional)

#### 404

The resource does not exist

- `error` (string, required)
- `issues` (any[], optional)
