# Management tokens

> Create a scoped, expiring management token in the console, restrict it to one project, and understand how it follows its creator's role.

Source: https://infro.io/docs/manage/tokens

> **Note:** INFRO is in private early access. Running these examples requires an early-access account, an active trial or subscription entitlement, and your own provider connection. Self-serve purchasing is not generally open. See [Early access](https://infro.io/early-access).

> **Warning:** **Built, not yet available.** The management API is built and not deployed: `/manage/v1` does not answer requests yet, and nothing on this page can be used today. These pages describe the contract it ships with.

A management token is the only credential `/manage/v1` accepts. It is a person's authority handed to a program, for a limited time and a limited set of resources. It is not a separate identity: every request runs as the person who created the token, with their role as it is at that moment, and the token's scopes narrow that further. A token can never do something its creator could not do in the console today.

## Creating a token

Tokens are created in the console, under **Settings → API tokens**, by an owner or an admin. Choose a label, the scopes, an optional project and an expiry. The token (`mt_infro_` followed by 43 characters) is shown once, when it is created; INFRO stores only a hash of it. Every owner of the organization is emailed when a token is created, with its label, scopes, creator and expiry.

There is no endpoint on `/manage/v1` that creates, lists or revokes tokens. A token cannot create another token. Revoke a token in the same console screen; revoking takes effect on its next request.

## Scopes

Scopes are grouped into families. Configuration: `projects`, `keys`, `connections`, `routes`, `settings`, `budgets`, `webhooks`, `prices`, `notifications`, `cost_centers`, `commitments`, `guardrails` and `end_users`. Data: `analytics` (usage, request metadata and traces), `findings` and `audit` (the audit log). Each is granted as `<family>:read` or `<family>:write`, and write includes read; `analytics` and `audit` are read-only. `*:read` reads every configuration family, which is what `terraform plan` and `infro export` need, and no data family: request history, findings and the audit log are granted by name, so a token made for Terraform never gains them. There is no `*:write`: write access is granted one family at a time, so the token's list of scopes reads as what it can change.

A request outside the token's scopes is refused with `403` and `code: "insufficient_scope"`, naming the scope it needs. The organization's plan still applies on top: see [Plans](https://infro.io/docs/manage/overview#plans).

The [MCP gateway](https://infro.io/docs/mcp-gateway) adds the configuration family `mcp` (servers, tools and key grants). `*:read` includes it. `mcp:write` changes servers and grants; approving, blocking and unblocking a tool also need the token's creator to be an owner or admin at that moment. A project-restricted token cannot hold `mcp`.

## Project-restricted tokens

A token can be restricted to one project. It may then hold only `projects`, `keys`, `guardrails`, `end_users`, `analytics` and `findings` scopes, and not `*:read`. Its usage, requests and traces are that project's; its findings are those scoped to that project. It sees that project, the project's gateway keys, their guardrail policies and the project's end-customer rule, and nothing else. It cannot create projects, creates gateway keys only in its own project, and sets guardrails only on its project and its keys; anything else is refused with `403` and `code: "project_restricted"`. A resource that belongs to another project answers `404`, the same as one that does not exist, so the token cannot learn what else exists.

This fits a pipeline that provisions one tenant or one application: it can create and rotate its own keys without being able to see the rest of the organization.

## Expiry

Every token expires. The default is 90 days, the maximum is 365, and there is no option for a token that never expires. An expired token is refused like a revoked one; create a new one.

## Tokens follow their creator

- Only an owner or an admin can create a token, and a token only works while its creator is still an owner or admin of the organization.
- If the creator is changed to another role, their tokens are refused with `403` and `code: "token_creator_not_admin"`. The tokens are kept: making that person an admin again restores them.
- If the creator leaves the organization or is removed from it, every token they created is revoked.
- Because each request runs as the creator's current role, a role change in the console takes effect on the token's next request.

> **Note:** For a token that should outlive one person's role, create it as a person whose membership is meant to last, and rotate it when that changes. The owners' email on every creation is there so that tokens do not appear unnoticed.

## Using a token

```bash
curl https://api.infro.io/manage/v1/organization \
  -H "Authorization: Bearer $INFRO_MANAGEMENT_TOKEN" \
  -H "User-Agent: my-provisioner/1.0"
```

Pass the token as `Authorization: Bearer mt_infro_...`; nothing else is accepted. The API sets no CORS headers: it is meant to be called by programs, not from a browser page.

## Where a token is refused

| Credential | `/v1` (inference) | `/console` | `/manage/v1` |
| --- | --- | --- | --- |
| Gateway key (`sk_infro_...`) | Accepted | Refused | Refused with `401` |
| Management token (`mt_infro_...`) | Refused with `401` | Refused | Accepted |

A gateway key serves traffic and must never reconfigure the organization, and a management token changes configuration and never serves traffic. Keep them in different secret stores.

## Rate limits

- 120 requests per minute per token. The limit follows the token, not the address, so pipelines sharing CI runners do not slow each other down.
- 30 failed authentications per minute per address. After that, requests from that address are refused with `429` until the minute passes.

## Errors

| Status | `code` | Meaning |
| --- | --- | --- |
| 401 | — | The token is missing, malformed, unknown, expired or revoked. The message does not say which. |
| 403 | `plan_feature` | The organization's plan does not include the management API, or this kind of write. |
| 403 | `insufficient_scope` | The token lacks the scope this request needs. |
| 403 | `insufficient_role` | The creator's current role cannot make this change in the console either. |
| 403 | `project_restricted` | A project-restricted token tried to act outside its project. |
| 403 | `token_creator_not_admin` | The creator is no longer an owner or admin. |
| 429 | — | Too many requests for this token, or too many failed authentications from this address. |

The full list of management API errors is on [Errors](https://infro.io/docs/api/errors#management-api-errors).
