The KnoxCall response block
When you call a route through KnoxCall, the status, headers and body you get back are your upstream’s, forwarded verbatim. That is deliberate: your code should see what your provider actually said, byte for byte. It leaves one question the response alone cannot answer. A429 came back — was
that your provider’s rate limit, or ours? A 502 — did the call reach them at
all? The KnoxCall response block answers it, on every response, without touching
the body your provider sent.
The whole
x-knox- response namespace is reserved. If your upstream sends
a header in it, KnoxCall drops it rather than relaying it. Everything below is
always KnoxCall speaking, never something an upstream can forge.The one check that matters
X-Knox-Upstream-Status is present if and only if a real upstream response was
received.
429 as the provider’s and retries against a limit that is not the one
refusing it — backing off in the wrong place, for the wrong reason, until the
provider’s own limiter finally trips.
X-Knox-Origin says the same thing in a word, for when you are reading curl -i
rather than writing code.
Every header
Latency, and what it measured
X-Knox-Latency-Ms cannot mean the same thing on a buffered and a streamed
response, so it is labelled rather than left ambiguous:
X-Knox-Latency-Phase: complete— the whole body was in hand. The number is the full round trip.X-Knox-Latency-Phase: first-byte— the response is streaming. Headers must be sent before any body byte, so this is time-to-first-byte and the total is not knowable yet.
X-Knox-Upstream-Ms and X-Knox-Overhead-Ms split that time between your provider
and us. Both are omitted when the split was not measured rather than estimated —
if you see them, they were timed.
Rate limits
Each limiter reports its own window, so three different ceilings do not collapse into one ambiguous pair of numbers:reset is an ISO-8601 instant. It is absent on the monthly window, which rolls
over with your billing period rather than on a fixed clock.
The older
X-RateLimit-Limit, X-RateLimit-Tenant-* and X-API-Usage-* headers
are still sent and still correct. They are deprecated in favour of the block
above — the three families used different names, units and reset formats, and
none of them said whether the limit that refused you was KnoxCall’s or your
provider’s. Nothing that reads them today needs to change yet.On errors KnoxCall itself returns
When KnoxCall refuses a call, the body is ours, so the block is repeated there as aknoxcall object alongside the usual error envelope:
knoxcall key is a sibling of error, not nested inside it, so the existing
error envelope is unchanged and a client that does not know about the block simply
ignores it.
On a forwarded response the block stays in the headers only. Your upstream’s
body is passed through untouched — it may be JSON, a PDF, an image or a stream, and
KnoxCall does not rewrite any of them.