AI GridDocs
Sign Up

API keys

One key, one project — issuing rules, reveal-once secrets, rotation, spending limits and expiry.

Updated Sep 9, 2026

An API key authenticates your calls to the serving API (/v1/models, /v1/chat/completions, the sandbox invoke endpoints). A key looks like aig_ followed by a 32-character token, and it is bound to exactly one project — the binding is chosen at creation and never changes.

bash
curl https://api.aigridapp.com/v1/chat/completions \
  -H "Authorization: Bearer $AIGRID_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"model":"openai/gpt-oss-20b","messages":[{"role":"user","content":"hello"}]}'

Runtime actors#

A runtime actor is the identity behind a call, separate from what pays for it. A human's API key is one kind of actor; a sandbox product also runs under its own actor, so its calls spend the project budget without needing a personal key. A project's Runtime actors tab lists each one with its class, environment, keys and last call; opening a record shows where it was created from and the wallet binding that decides who pays.

A project's runtime actors, including the sandbox actor its studio runs spend under — identity decides who acts, the binding decides who pays.

One key, one project#

The bound project is the execution and charging context of every call the key makes: usage, policy checks and wallet charges all land on that project. There is no per-call project choice for a key — the X-AIGrid-Project selector header may restate the bound project, and nothing more. A selector that names a different project is refused with 403 project_mismatch before any money is reserved.

The key holds no funds of its own. Every call charges the project wallet of its bound project.

Who may issue a key#

Creating a key requires, all at once: an active organization membership, an active grant on the project's owning team, and an active project grant carrying project.invoke (Project Owner or Project Consumer) — confirmed by the authorization adapter. Anything less answers 403 key_issuer_denied. The full rule, and how it differs from ordinary consumption, is on Roles and permissions.

The rule is re-evaluated on every use of the key: revoke the creator's grants or suspend the person, organization or project, and the next call is refused.

Access policy: all-eligible or listed#

Each key carries one of two access policies, chosen at creation:

  • all-eligible (the default) reaches every resource currently eligible in the bound project — including products assigned later.
  • listed reaches exactly the resources named in allowedModels. Every entry must be an eligible resource of the project at issue time (422 resource_not_eligible otherwise), and eligibility is re-checked on every call — naming a resource your list excludes answers 403 key_scope. An empty list never means "all".

Spending limits and expiry#

Optional controls set at creation, both enforced on admission:

Setting Values
Spending limit an amount in micro-USD, resetting daily, weekly or monthly — or lifetime
Expiry 1–365 days; 90 days when not specified

Limits and expiry are part of the key and survive rotation. Wider organization spend controls apply on top.

Rotation#

Rotating a key issues a replacement secret with the same project, access policy, list, spending limit and expiry span — and revokes the old key immediately. The registry records the lineage (rotatedFrom / rotatedTo) and both the rotation and the revocation are audited.

Legacy unbound keys#

Keys created before project binding became mandatory have no project. They are refused everywhere with 403 key_unbound — never auto-bound, never auto-revoked, and not rotatable. The console marks them "Needs reissue": create a project-bound key and revoke the old one.

What happens when a key is refused#

A rejected call never reaches a provider and nothing is charged — no usage record, no reservation, no dispatch. See Errors for the codes (unauthenticated, project_mismatch, key_scope, key_unbound, key_issuer_denied) and what clears each one.

Next#