---
title: "Authentication"
description: "How to authenticate a request to the roasOS API and to the MCP server."
url: https://docs.roasos.com/authentication
---

# Authentication

Every request needs an API key. Send the key as a bearer token.

One key opens both entry paths. The REST API at `https://api.roasos.com` and the MCP server at `https://mcp.roasos.com/mcp` read the same credential. There is no second token to make.

## Make a key

Make a key in your [workspace settings](https://www.roasos.com/settings/workspace). You need a Growth plan or a Scale plan. A key has this format:

```
roasos_sk_0d80bcba7586d8f...
```

<Callout type="warn">
  Keep your API key secret. The key has full access to your workspace. If a key becomes known to other persons, revoke the key in your settings. Then make a new key.
</Callout>

## Use the key

Add the key to the `Authorization` header of every REST request:

```bash
curl https://api.roasos.com/v1/account \
  -H "Authorization: Bearer roasos_sk_..."
```

An MCP client sends the same header on the transport. Refer to [Connect an AI agent (MCP)](/mcp).

```json
{
  "mcpServers": {
    "roasos": {
      "type": "http",
      "url": "https://mcp.roasos.com/mcp",
      "headers": { "Authorization": "Bearer roasos_sk_..." }
    }
  }
}
```

## What a bad key answers

| Condition                               | Response              |
| --------------------------------------- | --------------------- |
| No `Authorization` header               | `401 missing_api_key` |
| A token without the `roasos_sk_` prefix | `401 invalid_api_key` |
| A revoked key, or an unknown key        | `401 invalid_api_key` |

## Rate limits

Each key carries its own requests-per-minute value. The default is **600 requests each minute**. This is a default, not a fixed ceiling: your key row can hold a higher value, up to 1,000.

Two policies run on separate counters. The read limit is the value on your key. The write limit is one fifth of it.

| Policy | Requests                                                                                   | Limit           |
| ------ | ------------------------------------------------------------------------------------------ | --------------- |
| Read   | Every `GET`, and every other path                                                          | 600 each minute |
| Write  | A write to `/v1/generations`, `/v1/avatars`, `/v1/scenes`, `/v1/products` or `/v1/uploads` | 120 each minute |

A model endpoint, a workflow and an agent run use the read policy.

Each successful response includes your current limits in these headers:

* `X-RateLimit-Limit`
* `X-RateLimit-Remaining`
* `X-RateLimit-Reset`

If you go above a limit, roasOS answers `429 rate_limit_exceeded` with a `Retry-After` header. Wait for that time. Then send the request again.

## Cost controls

Each key carries its own spend policy. It bounds the price of one call, the daily and monthly budgets, the approval threshold, and the allowed models.

Read the policy of the calling key:

```bash
curl https://api.roasos.com/v1/limits \
  -H "Authorization: Bearer roasos_sk_..."
```

```json
{
  "data": {
    "policy": {
      "max_credits_per_request": 500,
      "approval_threshold_credits": 100,
      "allowed_models": null
    },
    "daily": {
      "limit": 2000,
      "used": 340,
      "remaining": 1660,
      "reset_at": "2026-08-23T00:00:00.000Z"
    },
    "monthly": {
      "limit": 40000,
      "used": 5120,
      "remaining": 34880,
      "reset_at": "2026-09-01T00:00:00.000Z"
    }
  }
}
```

| Field                                | What it bounds                                         |
| ------------------------------------ | ------------------------------------------------------ |
| `policy.max_credits_per_request`     | The highest price of one paid call                     |
| `policy.approval_threshold_credits`  | The highest price that runs without a human approval   |
| `policy.allowed_models`              | The models this key may call. `null` means every model |
| `daily.limit`, `monthly.limit`       | The credits this key may spend in each window          |
| `daily.reset_at`, `monthly.reset_at` | UTC midnight, and the first day of the next month      |

The agent pages name the approval threshold `auto_approve_up_to_credits`. It is the same policy value that `GET /v1/limits` publishes as `policy.approval_threshold_credits`.

roasOS refuses a call above one of these bounds before it spends:

| Code                                 | Cause                                                                |
| ------------------------------------ | -------------------------------------------------------------------- |
| `403 request_credit_limit_exceeded`  | The price is above `max_credits_per_request`                         |
| `403 spend_approval_required`        | The price is above the approval threshold, and no person approved it |
| `429 daily_credit_budget_exceeded`   | The key reached its daily credit budget                              |
| `429 monthly_credit_budget_exceeded` | The key reached its monthly credit budget                            |
| `503 limits_unavailable`             | roasOS cannot read the policy now                                    |

The approval threshold is also the authority that lets an agent run spend without a person. Refer to [Ask the agent](/agent/ask-the-agent) and to [Quotes and credits](/concepts/quotes-and-credits).
