# API keys

> Workspace keys for scripts and clients without a browser. Format, headers, limits, and what a key cannot do.

Source: https://docs.indexzero.site/agents/api-keys



An API key authenticates a request to the MCP endpoint as your workspace, without an OAuth flow. Use one for scripts, CI, server-side agents, or any client that does not implement OAuth for remote MCP servers.

## Creating a key [#creating-a-key]

<Steps>
  <Step>
    ### Open AI & MCP [#open-ai--mcp]

    In the app, open **AI & MCP** from the sidebar. Creating keys requires a plan with MCP access; on the Free plan the page shows the upgrade prompt instead.
  </Step>

  <Step>
    ### Name it and create [#name-it-and-create]

    Give the key a name (up to 80 characters, "CI pipeline" style) so you can tell keys apart later. Keys created in the app do not expire; delete a key to revoke it.
  </Step>

  <Step>
    ### Copy it now [#copy-it-now]

    The key is shown **once**, at creation. Only a hash is stored; if you lose it, delete it and create another.
  </Step>
</Steps>

Keys look like `iz_` followed by a random string. The list on the page shows each key's name, the first characters, when it was created, and when it was last used, and lets you delete it.

## Sending it [#sending-it]

Either header form works:

```
x-api-key: iz_your_key_here
```

```
Authorization: Bearer iz_your_key_here
```

The `iz_` prefix is what identifies the value as an IndexZero key. A bearer token without it is treated as an OAuth access token instead.

## What a key can and cannot do [#what-a-key-can-and-cannot-do]

* A key reaches **only** `https://app.indexzero.site/mcp`. It is verified directly and never exchanged for a session, so it cannot reach account, billing, or dashboard endpoints even if leaked.
* A key acts as the **whole workspace** with every MCP scope. There are no per-tool scopes on keys; use separate keys per integration so one can be revoked without the others.
* Deleting a key takes effect immediately.

## Rate limits [#rate-limits]

Keys are limited to **500 requests per minute**. Past that, the endpoint returns HTTP 429 with a `Retry-After` header in seconds:

```json
{ "error": "rate_limited", "error_description": "..." }
```

## Errors [#errors]

| Status | Body                                                                 | Meaning                                           |
| ------ | -------------------------------------------------------------------- | ------------------------------------------------- |
| 401    | `{"error":"invalid_api_key", ...}`                                   | The key is unknown, expired, or was deleted.      |
| 429    | `{"error":"rate_limited", ...}` or `{"error":"usage_exceeded", ...}` | Too many requests; honour `Retry-After`.          |
| 402    | tool result with `PLAN_UPGRADE_REQUIRED`                             | The workspace's plan does not include MCP access. |

Errors at the credential layer use the RFC 6749 shape (`error`, `error_description`). Errors inside a tool call come back as MCP tool results; see [Errors](/reference/errors).
