Request headers
Two rules about everything else you send:
x-hopscotch-*request headers are reserved. We remove every inbound header in that namespace before doing anything with your request. Sending one has no effect, and no header you send can change how a request is routed or served.- Your headers do not reach the model provider. The upstream request is built from your body, and from nothing else you sent. If a parameter matters to a provider, send it in the body, which is forwarded as you wrote it.
Response headers
The four diagnostic headers are set when there is something to say and are absent
otherwise. Treat them as diagnostics: read them in logs, do not build behaviour
on them, and expect the set to grow.
Nothing else from upstream reaches you. In particular, provider rate-limit
headers are not forwarded: the limits you are subject to are ours, so a
provider’s remaining-quota headers would describe a budget that is not yours and
tell you nothing you can act on. Read our own limits from the
429 codes in
Errors instead.
Every response carries the same id on two headers:
x-hopscotch-request-id,
which is ours, and x-request-id, which is the one the official OpenAI SDKs
surface on their error objects. Every error envelope repeats it as
request_id. Quote it when you ask us about a request. Without it we are
guessing at which of your requests you mean.Token counts
A non-streamed response carries token counts where an OpenAI-compatible client already looks for them: theusage object in the response body, as the provider
reported it.
A streamed response cannot do that, because the body is a sequence of events and
the counts are only final at the end. So a streamed response carries one extra
line, immediately before its terminating data: [DONE]:
data: [DONE]:
The usage line
Counts not reported
Fields are omitted rather than set to zero when a provider did not report them,
so “the provider did not say” stays distinguishable from “nothing was used”.
reported: true with zeros means zero. An absent field means unknown.
The counts are the provider’s own. Nothing is re-counted or estimated.
A stream that is cut off carries no usage line, because there are no final
counts to report.
On a response that is not streamed there is no separate counts line. The
provider’s own usage object inside the JSON body is what you read, exactly as
you would from OpenAI. Either way, the figures we settle your balance against
are the ones on your Activity screen.
Where to read the counts, stated once so there is no doubt: on a streamed
response, the comment line above. On a response that is not streamed, the usage
object in the body, which is where an OpenAI-compatible client already looks.
Two rules that make the difference between reading this correctly and quietly
mis-reading it:
- Absent is not zero. A count the provider did not report is omitted rather
than sent as
0, because “we were not told” and “none were used” are different facts and only one of them is free. reported: falsemeans we have no counts, not that the request was free. It carries no token fields at all.
v moves only
when a reader would have to behave differently.