Migrating from another gateway
What carries over unchanged, what is named differently, and what we do not implement.
The swap
Coming from OpenAI directly, or from a gateway that speaks the same format, the diff is three lines.
- baseURL: "https://api.openai.com/v1",
- apiKey: process.env.OPENAI_API_KEY,
- model: "gpt-4o",
+ baseURL: "https://api.multigrid.ai/v1",
+ apiKey: process.env.MULTIGRID_API_KEY,
+ model: "openai/gpt-4o",Model ids are the one thing that always needs touching: ours are namespaced vendor/model. GET /models is public, so you can map your ids before you change any code.
What carries over
The request body is OpenAI’s and validation is deliberately shallow — we check that model is a non-empty string and that messages has at least one entry, and let everything else through. A parameter a vendor added last week reaches them untouched rather than being rejected by us for being unfamiliar.
The routing fields are named the same way OpenRouter names them, on purpose: models for a fallback chain and provider: { order, ignore, allow_fallbacks, sort } for provider preferences. A config carried over keeps working rather than being silently ignored, which would change your bill without changing your code. See provider preferences.
What is different
- Responses carry a
multigridobject. Model, provider, attempts and exact cost. Additive — clients that do not know about it ignore it. - Errors use OpenAI’s envelope with our codes.
{ error: { message, type, code, request_id } }. Existing error handling keeps parsing; thecodevalues are ours. See the error reference. - Streams end with our terminal chunk. Usage and cost arrive on a final chunk before
data: [DONE], so a client that stops reading at the firstfinish_reasonwill miss the numbers but not the answer. HTTP-RefererandX-Titleare read. OpenRouter’s two attribution headers land as therefererandtitlerequest tags, filterable in Activity and groupable in Analytics like any other tag — so the labels you have been slicing spend by survive the move without touching a call site. An explicitmetadata.refererormetadata.titlein the body wins over the header. There is no public app leaderboard here for them to feed; they are yours.- Browser calls work, and the spec is machine-readable. Every
/v1endpoint sends CORS headers and answers preflights, so a client-side integration carries over. The OpenAPI 3.1 document at/api/openapi.jsongenerates clients, Postman collections and mocks.
What we do not implement
Two fields other gateways use are accepted and stripped before the request leaves us: transforms and route. Nothing breaks if they arrive, and nothing happens either — if you were relying on prompt transforms to fit a long context, that work is not being done here.
There is also no stored, versioned routing policy object to migrate to. Routing is expressed per request, or saved as a preset you call by name.
Checklist
- Map every model id against
GET /models. - Confirm we hold a route for each one:
GET /models/{vendor}/{model}/endpointslists the providers, in the order they will be tried, with prices. - Move gateway-specific fields you were sending into
metadataor delete them.HTTP-RefererandX-Titlecan stay as they are. - Set a spend cap on the new key before you point production at it.
- Run a playground call against each model to confirm we have a working key for its provider on this deployment.
Something here disagrees with what the API actually did? That is a bug in this page, and worth reporting.
Report it