Skip to content

API reference

Base URL https://api.multigrid.ai/v1. Everything is JSON over HTTPS. The version is the /v1 in the path, and it is the only one there has been.

Authentication

Send your key as a bearer token. Keys are scoped to a project and can carry their own spend cap and rate limit, so a leaked client key cannot drain the account.

bash
curl https://api.multigrid.ai/v1/models \
  -H "Authorization: Bearer $MULTIGRID_API_KEY"

Request headers

Authorization
`Bearer mg_live_…`. Required on every call except the three public catalogue reads: GET /models, GET /providers and GET /models/{vendor}/{model}/endpoints.
Idempotency-Key
Client-generated key. A retry replays the stored answer rather than paying for the same completion twice; the claim is taken before we go upstream, so two simultaneous retries cannot both run.
X-Multigrid-Cache-Ttl
Seconds, up to 86400. Opts this request into the exact-match cache — which is off unless you ask for it. Equivalent to `{ "cache": { "ttl": … } }` in the body.
X-Multigrid-Batch-Name
On POST /batches only. A label for the job, so it is identifiable in the dashboard. `?name=` does the same thing.
HTTP-Referer
OpenRouter's attribution header, accepted so that migrating is a base-URL change and nothing else. Stored as the `referer` request tag, filterable in Activity — unless you set `metadata.referer` yourself, in which case the body wins.
X-Title
OpenRouter's app-name header. Stored as the `title` request tag, on the same terms.

Response headers

X-Multigrid-Request-Id
Stable id. Pass it to GET /generation to see what the request did.
x-request-id
The same value, under the name OpenAI's SDKs and every piece of logging middleware written against them already look for. Both are always written together; neither is more authoritative.
X-Multigrid-Model
The model that actually served the request, which is not always the one you asked for.
X-Multigrid-Provider
The provider that actually served it.
X-Multigrid-Attempts
How many providers were tried before one succeeded.
X-Multigrid-Cost-Usd
Exact cost to six decimal places. Absent on a stream, where the cost is not known until the last token — it rides the terminal SSE chunk instead.
X-Multigrid-Byok
`true` when your own provider key served it, and we therefore charged you nothing.
X-Multigrid-Cache
`hit`, and only on a hit. Absent on every other response.
X-Multigrid-Idempotent-Replay
`true` when this is a stored answer replayed against an Idempotency-Key rather than a fresh completion.
X-RateLimit-Limit
Requests permitted in the current 60-second window. On successful responses as well as the 429 — an adaptive-concurrency client needs the headroom before it is refused, not after.
X-RateLimit-Remaining
How many are left in it.
X-RateLimit-Reset
Seconds until the window empties. Relative rather than a timestamp, so no clock agreement is needed.
X-Multigrid-Batch-Status
On GET /batches/{id}/results only: the job's status when the download began, so a partial file is explicable.

Inference

POST/chat/completionsCreate a chat completion

The main inference endpoint. OpenAI-compatible, with optional models, provider, cache and retry fields an ordinary OpenAI SDK passes straight through. The model id may be a plain vendor/model slug, a slug with a :floor, :nitro or :free routing suffix, multigrid/auto (the cheapest model that fits the prompt and the capabilities you need, with the reason in the response), or @preset/name.

Parameters and examples
POST/embeddingsCreate embeddings

Vectors from any embedding model in the catalogue, billed per token like everything else.

Parameters and examples
POST/images/generationsGenerate an image

Text-to-image through the same key, balance and spend cap. Billed per image rather than per token.

Parameters and examples
POST/video/generationsGenerate a video

Billed per unit of output, against the same balance and the same ceiling.

Parameters and examples
POST/rerankRerank documents

Score a set of documents against a query. Per-unit pricing, not per token.

Parameters and examples

Catalogue

GET/modelsList models

The catalogue in OpenAI's /v1/models shape, with prices as both a per-token decimal and integer micros. No key required — prices are what people compare before they sign up. ?modality=chat|embedding|image|video|rerank narrows it to the ids one endpoint accepts, which is the list worth trusting over any page.

Parameters and examples
GET/models/{vendor}/{model}/endpointsList a model's routes

Every provider that serves one model, with what that route costs and its priority — routes on the same model can be priced differently.

Parameters and examples
GET/providersList providers

The providers we can route to, and what each one is.

Parameters and examples

Batch

POST/batchesCreate a batch

Queue a set of requests to run without holding a connection open. Billed at exactly the same rate as a live call — there is no batch discount. The body is the JSONL file itself, not an uploaded file id: this is not OpenAI's batch API and client.batches.create() will not work against it. ?name= labels the job.

Parameters and examples
GET/batchesList batches

Your jobs, newest first, with counts and status. Capped at 100 with no cursor.

Parameters and examples
GET/batches/{id}Retrieve a batch

Status and per-item counts for one job.

Parameters and examples
DELETE/batches/{id}Cancel a batch

Stops dispatch. Items that already ran are still billed and their results stay downloadable.

Parameters and examples
GET/batches/{id}/resultsDownload batch results

The completed items, including the ones that failed and why, as JSONL keyed by your own custom_id. ?filter=failed|succeeded narrows it. Readable while the job is still running — X-Multigrid-Batch-Status says how far along it was.

Parameters and examples

Observability

GET/generationRetrieve one request

What a single request actually did, by request id — for when the response body did not survive a crash or a retry loop. Scoped to your own account.

Parameters and examples
GET/usageUsage and cost

The same aggregates the Analytics page renders, by day, model and provider, so a finance team can reconcile an invoice without screen-scraping.

Parameters and examples
POST/feedbackSubmit a quality score

Attach your own score to a request id, so Analytics can put quality next to price. Idempotent — a second score replaces the first.

Parameters and examples

Management

GET/keyInspect the calling key

Balance, key cap, account cap and rate limit, so a client can tell which of the four ways it can be refused applies without triggering each one.

Parameters and examples
GET/creditsRetrieve credit balance

The account balance, derived from the ledger.

Parameters and examples
GET/keysList API keys

Requires a provisioning key; an inference key gets a 403 that says so.

Parameters and examples
POST/keysCreate an API key

Mint a scoped key with its own spend cap and rate limit. The secret is returned once.

Parameters and examples
GET/keys/{id}Retrieve a key

Metadata and limits. Never the secret.

Parameters and examples
PATCH/keys/{id}Update a key

Change its name, spend cap or rate limit.

Parameters and examples
DELETE/keys/{id}Revoke a key

Effective immediately: the key row is read from the database on every request, so there is no cache to wait out.

Parameters and examples

OAuth

POST/api/oauth/tokenRedeem an authorization code

The tail of the PKCE flow: an authorization code becomes an ordinary inference key with no expiry. Errors here are RFC 6749 shaped, not ours, so any OAuth library parses them. CORS is open — a single-page app is a first-class caller.

Parameters and examples
GET/api/oauth/clientsList OAuth applications

The applications this account has registered. Requires a provisioning key, so every client on the consent screen traces back to an account.

Parameters and examples
POST/api/oauth/clientsRegister an OAuth application

Public clients only — PKCE with S256, and no client secret is ever issued or returned.

Parameters and examples

Rate limits

There are two, and the tighter one wins: the limit you set on a key yourself, and — when you set none — a default that rises with the account’s trust level as settled payments accumulate. The ceilings are deliberately set above what a real production service reaches, because this limiter is a blast-radius control for a leaked key rather than a quota. What actually bounds your spend is the balance, the per-key spend cap and the account’s monthly ceiling, all three of which are denominated in money.

Every response carries X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset, successes included, so a client can slow down before it is refused rather than after. A 429 adds Retry-After, which is authoritative. For the exact number applying to one key, GET /key reports it alongside your caps and balance.

Rate limit details

Calling this from a browser

Every endpoint under /v1 sends Access-Control-Allow-Origin: * and answers preflight OPTIONS, so client-side fetch works. It is safe to open because these endpoints authenticate with a bearer token and never with a cookie, so there is no ambient authority for a hostile page to borrow. The X-Multigrid-* and X-RateLimit-* headers above are all listed in Access-Control-Expose-Headers, so browser JavaScript can read them.

That does not make it a good idea to ship a key you paid for into a web page. Mint a key with its own spend cap for anything a browser holds, or use the OAuth flow so each user brings their own.