# Management API

The management API sets up workspaces and keys from your own systems. MSPs use it to add a client in two calls. It is modelled on OpenRouter's key management API, so it will feel familiar.

It needs a **management key**. Create one in the [console](https://www.continuumlabs.ai/console) under Cost control. A management key can manage workspaces and keys and read statements. It cannot call models. Ordinary keys cannot use these endpoints.

All amounts are Australian dollars, excluding GST.

## Add a client in two calls

```bash
# 1. A workspace with an allowance
curl https://api.continuumlabs.ai/v1/workspaces \
  -H "Authorization: Bearer cl-your-management-key" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Harbour & Co Accounting",
    "allowance_aud": 500,
    "allowance_reset": "monthly",
    "at_limit": "downshift",
    "downshift_model": "gpt-oss-120b",
    "alert_email": "it@harbourco.example",
    "resale_markup_pct": 40
  }'

# 2. A key in that workspace
curl https://api.continuumlabs.ai/v1/keys \
  -H "Authorization: Bearer cl-your-management-key" \
  -H "Content-Type: application/json" \
  -d '{"name": "Front desk app", "workspace_id": "WORKSPACE_ID", "limit": 100, "limit_reset": "monthly"}'
```

The new key is in the `key` field of the response. It is shown once. Only a scrambled version is stored.

## Workspaces

| Call | Does |
|---|---|
| `GET /workspaces` | Lists workspaces, with this period's spend. |
| `GET /workspaces/{id}` | One workspace. |
| `POST /workspaces` | Creates one. `name` is required. |
| `PATCH /workspaces/{id}` | Changes any field. |
| `DELETE /workspaces/{id}` | Deletes it. Its keys stay, without a workspace. |

| Field | Meaning |
|---|---|
| `name` | Up to 60 characters. |
| `allowance_aud` | The allowance, or `null` for none. |
| `allowance_reset` | `daily`, `weekly` or `monthly`. |
| `at_limit` | `stop`, or `downshift` to use a cheaper model from 90%. |
| `downshift_model` | The cheaper model's ID. Required with `downshift`. |
| `alert_email`, `alert_webhook` | Where alerts go at 50%, 80% and 100%. The webhook must be `https`. |
| `resale_markup_pct` | For MSPs: the markup statements show the client. |

Responses add `allowance_remaining_aud` and `spent_this_period_aud`.

## Keys

| Call | Does |
|---|---|
| `GET /keys` | Lists ordinary keys, with this period's usage. |
| `GET /keys/{id}` | One key. |
| `POST /keys` | Creates one. Returns the key once. |
| `PATCH /keys/{id}` | Changes the name, workspace, limit, or switches it off. |
| `DELETE /keys/{id}` | Deletes it. Requests using it stop at once. |

| Field | Meaning |
|---|---|
| `name` | Up to 60 characters. |
| `workspace_id` | The workspace, or `null`. |
| `limit` | The key's own limit, or `null` for none. |
| `limit_reset` | `daily`, `weekly` or `monthly`. |
| `disabled` | `true` switches the key off at once. |

Responses add `limit_remaining` and `usage_this_period`.

## Statements

| Call | Does |
|---|---|
| `GET /statements/account?month=2026-10` | The whole account's statement for a month. |
| `GET /statements/{workspace_id}?month=2026-10` | One workspace's. |

See [statements](/docs/statements) for what's in it.

## Errors

Errors use the same shape as the rest of the API. A bad field returns `400` with a message naming it. An ID from another account returns `404`.
