- The request and response bodies are OpenAI’s, and travel unchanged but for two rewrites named below.
- Errors arrive in the OpenAI error envelope, so your existing error handling parses them.
- What we add is additive: extra response headers and one SSE comment line, both of which a compliant client ignores.
https://ai.uniblock.dev and give it a
Uniblock API key. Nothing else about your code changes.
Base URL
The endpoints that exist today
That table is the whole documented surface. A path that is not on it is one this
site says nothing about, which is not the same as a path that does not exist.
What a call to a path we do not serve returns
A path under/v1 that this release does not serve is refused at one boundary,
so it fails the same way every time rather than in a new way per path. It is a
404 in the OpenAI envelope, with type invalid_request_error and code
endpoint_not_supported:
404
405 with the code
method_not_allowed and an Allow header naming the methods that are served.
A GET on /v1/chat/completions is the everyday example.
Request parameters
The chat completion body is forwarded as you sent it. There is no request schema of ours in front of it and no allowlist of parameters, so a parameter your client already sends works without waiting for us to add it. A body the provider rejects comes back as the provider’s own OpenAI-shaped error. Two fields are read on the way through, both to work out what the request could cost before it is sent:model, and max_tokens or max_completion_tokens.
Reading one does not change it.
Two rewrites exist, and they are the whole list. A request naming a routing
profile or unirouter/auto has its model replaced with the model being tried
on that attempt, because that is what a route means. And a request that names no
output ceiling, sent to a provider whose own API refuses a request without one,
has max_tokens filled in with the model’s published maximum output, which is
the figure credit was already being held against. Every other provider is sent
your body without the field. Request parameters
covers both in full.
Two consequences worth stating:
- Nothing Uniblock-specific belongs in a request. There is no parameter of ours to send, and no header can change how a request is served.
max_tokensis worth sending even though it is optional. It is what sizes the amount we hold against your balance before the call, so a request without it is held at a larger estimate and reaches your account spend rate cap sooner. See rate limits and spend controls.
Model ids
Models are namedprovider/model, for example openai/gpt-4o-mini. The id is split once on the
first slash: the part before it names the provider that will serve the request, and everything after
it is that provider’s own id for the model, slashes included and passed on unchanged. The same model
carried by two providers is two ids, and you choose which one you send.
A bare OpenAI-style name with no provider is not a Uniblock model id. It is refused with 400 and
the code model_id_not_pinned, naming both accepted forms, rather than being routed to whichever
provider we happen to carry it under. Ask GET /v1/models for the ids you can
call.
Request headers
SendAuthorization and Content-Type. Nothing else you send is forwarded: the
request we make on your behalf is built from your request body and our own
provider credential, with a fresh header set, so headers beyond those two are
neither honoured nor passed to the provider.
x-uniblock-* is our reserved namespace on both directions of the wire. Sending
one has no effect for the same reason: it does not travel.
Response differences
All three differences are additions to an otherwise unchanged OpenAI response.The request id
Every response, success or error, carriesx-uniblock-request-id, and the same
value on x-request-id, which is the header the OpenAI SDKs already read. On an
error, the id also appears as request_id inside the error object. That fifth
field inside error is the one shape difference from OpenAI’s envelope, and it
is inside error rather than beside it precisely so that an SDK reading the
fields it knows ignores it safely.
Diagnostic headers
A short allowlist of response headers describes how the request was served. These are the ones that ship today:
Nothing else the provider sets travels onward. That is deliberate rather than
incidental, and it has one consequence you will notice: provider rate limit
headers are not forwarded. If you currently read the remaining-requests and
reset headers that a provider sets, those are absent here, because they describe
a pool we hold rather than a limit that applies to you. Your own limits arrive as
429 responses with codes you can branch on, documented in
rate limits and spend controls.
The usage comment line on a stream
A streamed reply carries one extra line immediately beforedata: [DONE],
starting with a colon:
Errors
Status codes and the closed set oftype values are OpenAI’s. Branch on type
and code, never on the message text: the fields are the contract and the
sentences are prose that may be reworded. Every shipped code and its status is in
errors.
One difference in kind is worth naming. Some of our refusals are about money
rather than about your request: not enough credit, or an account spend rate cap.
Those reuse OpenAI’s own insufficient_quota and rate_limit_error types, so the
branch your client already has keeps working, and carry a Uniblock code that
says which of them happened.
What we do not claim
- We have not published a proof run of an unmodified official SDK against the
production hostname. The instructions on this site set only
base_urlandapi_key, which is the whole intended change, and we will say so as a tested result rather than an expectation once that run exists. - We make no statement here about behaviour under concurrency, latency added by the hop, or availability. No figure for any of those has been measured in a way we are willing to publish.