# API reference
Graphene is an OpenAI-compatible inference API. If your code already talks to
OpenAI, the only change is the base URL — see the [Quickstart](/docs/welcome).
This page is the reference for everything else: authentication, the inference
surface, the management endpoints, errors, rate limits and versioning.
## Base URLs
| Purpose | URL |
| -------------------------- | ---------------------------- |
| Inference (OpenAI-compat) | `https://api.graphene.ai/v1` |
| Portal, docs and manifests | `https://graphene.ai` |
Machine-readable definitions of everything below:
- `https://graphene.ai/api/openapi` — OpenAPI 3.1, including the `x-pricing`,
`x-rate-limits` and `x-sla` vendor extensions.
- `https://graphene.ai/.well-known/agent.json` — capability manifest.
- `https://graphene.ai/api/benchmarks` — live performance telemetry.
## Authentication
Every request carries a workspace inference key as a bearer token:
```
Authorization: Bearer grph_live_...
```
Keys are created in the portal under **API keys**. Things worth knowing:
- **The prefix tells you which environment issued the key.** `grph_live_` is a
production credential; `grph_test_` was issued by a non-production deployment
and is not valid for live traffic. Check the prefix before wiring a key into
anything that bills.
- **Keys are scoped credentials only.** A key never grants a capability your
workspace does not already hold. It inherits the routing policy, budget and
agreement lane of the workspace that issued it. Adding a scope to a key cannot
unlock an enterprise capability — that is decided by your agreement, not by
the key.
- **The secret is shown once.** Only the last four characters are recoverable
afterwards. Rotate rather than recover.
- **Scopes** limit what a key may do. Inference keys need no extra scope;
management endpoints require explicit scopes such as `entitlements:read`,
listed per endpoint below.
## Chat completions
```
POST https://api.graphene.ai/v1/chat/completions
```
Request and response bodies follow the OpenAI chat-completions schema, so the
official SDKs work unmodified:
```python
from openai import OpenAI
import os
client = OpenAI(
base_url="https://api.graphene.ai/v1",
api_key=os.environ["GRAPHENE_API_KEY"],
)
resp = client.chat.completions.create(
model="claude-opus-4-8",
messages=[{"role": "user", "content": "Hello, Graphene"}],
stream=True,
)
```
Streaming uses the same server-sent-event framing as OpenAI. Tool calls, JSON
mode, `temperature`, `max_tokens` and the rest of the common surface pass
through to the routed provider.
### Models
The public model identifiers are the provider names, addressable through the one
endpoint:
```
claude-opus-4-8 gpt-5.5 llama-4 gemini-3 mistral-large deepseek-r2
```
The authoritative list is `models` in the capability manifest — read it rather
than hard-coding this list, because it moves when capacity does. See
[Models](/docs/models) for what each is good for.
Enterprise and sovereign customers get a larger catalogue with per-model
pricing, context windows and routing locality, plus the ability to bind a key to
a single model. That surface is gated — see
[Enterprise and sovereign access](/docs/enterprise-access).
## Management endpoints
These live on the portal origin (`https://graphene.ai`), not the inference base
URL. All of them accept a signed-in browser session; the ones with a scope also
accept `Authorization: Bearer <key>` when the integrator API is enabled for your
deployment.
| Endpoint | Method | Scope | Returns |
| ---------------------------------------- | -------- | ------------------- | -------------------------------------------------------- |
| `/api/v1/me/entitlements` | GET | `entitlements:read` | Plan, limits and which capabilities your workspace holds |
| `/api/v1/catalogue/models` | GET | session only | Full model catalogue — **enterprise/sovereign only** |
| `/api/v1/capacity` | GET | session only | Current capacity posture |
| `/api/v1/capacity/history` | GET | session only | Historical capacity series |
| `/api/v1/capacity/alerts` | GET | session only | Capacity alerts |
| `/api/v1/workspace/{workspaceId}/runway` | GET | session only | Token runway projection |
| `/api/budget/snapshot` | GET | session only | Monthly cap, spend-to-date and warn threshold |
| `/api/workspace/v1/keys` | GET/POST | session only | List and create workspace inference keys |
| `/api/workspace/v1/keys/{keyId}/rotate` | POST | session only | Rotate a key's secret |
| `/api/benchmarks` | GET | none (public) | Per-model latency, throughput, queue depth, 24h uptime |
| `/api/openapi` | GET | none (public) | OpenAPI 3.1 document with pricing metadata |
## Errors
Errors are returned as `application/problem+json` (RFC 9457) with a stable
machine-readable `code`. Branch on `code`, never on `title` or `detail`:
```json
{
"title": "Enterprise catalogue access required",
"status": 403,
"code": "model_catalogue_access_required",
"detail": "The model catalogue is available exclusively to enterprise and sovereign-compute customers."
}
```
| Status | `code` | Meaning |
| ------ | --------------------------------- | --------------------------------------------------------------------------- |
| 401 | `unauthorized`, `invalid_token` | No session and no valid bearer key |
| 403 | `insufficient_scope` | Key is valid but lacks the scope the endpoint requires |
| 403 | `model_catalogue_access_required` | Capability is enterprise/sovereign-gated and your lane does not hold it |
| 404 | `integrator_api_disabled` | Bearer-key access to management endpoints is off for this deployment |
| 429 | `rate_limited` | Rate limit hit; honour `retry_after` (seconds) |
| 503 | `no_compliant_route` | No route satisfied your compliance constraints — **fail-closed**, see below |
| 503 | `budget_unavailable` | Budget service could not be read |
### `no_compliant_route` is not a transient error
If your workspace carries region, provider or residency constraints and no
available capacity satisfies them, Graphene returns `503 no_compliant_route`
with a `failed_constraints[]` array — it does **not** quietly serve the request
somewhere else. Retrying without changing anything will fail the same way.
Graphene does not silently reroute workloads across jurisdictions. See
[Sovereignty](/docs/sovereignty).
## Rate limits
The published tiers, also carried in the OpenAPI `x-rate-limits` extension:
| Tier | Requests / minute | Tokens / minute |
| ------------ | ----------------- | --------------- |
| `free` | 60 | 60,000 |
| `pro` | 600 | 1,000,000 |
| `enterprise` | by agreement | by agreement |
Management endpoints are separately limited to 120 requests per minute per
session or key. A limited response is `429` with `retry_after` in seconds — back
off for that long rather than retrying immediately.
## Pricing and billing
Billing is per token at a flat **20% under each provider's published list
price**. There is no platform fee, seat charge or minimum. Machine-readable
form, from the OpenAPI `x-pricing` extension:
```json
{
"unit": "per_million_tokens",
"basis": "provider_list_price",
"discount_pct": 20,
"rates_endpoint": "/api/v1/pricing"
}
```
`rates_endpoint` names the planned per-model machine rates feed; it is a
follow-up and may return 404 today. Until it ships, read prices from the
catalogue (enterprise) or compute them from the provider list price and the
discount. See the [Billing FAQ](/docs/billing-faq).
## Service levels
The OpenAPI `x-sla` extension reports `commitment: "enterprise-agreement-only"`.
That is literal: self-serve usage is provided as-is, and uptime, latency floors
and support tiers are commitments that exist only under an enterprise agreement.
The [benchmarks endpoint](/docs/system-status) publishes what we actually
measure, including honest nulls where a metric is not yet instrumented.
## Versioning
- The inference surface is versioned in the path (`/v1`). Breaking changes ship
as a new path segment, never as a silent change to `/v1`.
- Additive changes — new fields, new models, new vendor extensions — can land in
`/v1` at any time. Parse defensively and ignore fields you do not recognise.
- Deprecations are announced in the [changelog](/changelog) and, for enterprise
agreements, directly. Superseded model identifiers keep an alias for at least
one minor version.
## Next steps
- **[Agent cards](/docs/agent-cards)** — every machine-readable descriptor
Graphene publishes
- **[Building agents](/docs/building-agents)** — notes for developers wiring
agents to Graphene
- **[For agents](/docs/for-agents)** — instructions written for the agent itself
- **[Enterprise and sovereign access](/docs/enterprise-access)** — pinned
models, region constraints, private routing