> ## Documentation Index
> Fetch the complete documentation index at: https://docs.knoxcall.com/llms.txt
> Use this file to discover all available pages before exploring further.

# The KnoxCall Response Block

> Tell a KnoxCall error from your provider's, and see exactly where the time went

# 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. A `429` 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.

<Note>
  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.
</Note>

## The one check that matters

**`X-Knox-Upstream-Status` is present if and only if a real upstream response was
received.**

```text theme={"dark"}
# Your provider answered. This 429 is theirs.
HTTP/1.1 429 Too Many Requests
X-Knox-Origin:          upstream
X-Knox-Upstream-Status: 429     ← present

# KnoxCall answered. The call never left our network.
HTTP/1.1 429 Too Many Requests
X-Knox-Origin: knoxcall
X-Knox-Error:  route_rate_limited
                                ← no X-Knox-Upstream-Status
```

If you wrap a provider SDK, branch on that absence. Without it, a client library
reads our `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.

```js theme={"dark"}
const gatewayError = !res.headers.get('x-knox-upstream-status');
if (gatewayError) {
  // KnoxCall refused this. res.headers.get('x-knox-error') says why.
  // Do NOT hand it to the provider SDK's retry logic.
}
```

`X-Knox-Origin` says the same thing in a word, for when you are reading `curl -i`
rather than writing code.

## Every header

| Header                     | Meaning                                                                                                                                                             |
| -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `X-Knox-Request-Id`        | The call id. Quote it to support; it matches your logs.                                                                                                             |
| `X-Knox-Origin`            | `upstream` or `knoxcall` — who produced this status and body.                                                                                                       |
| `X-Knox-Upstream-Status`   | The status your upstream returned. **Present only on a genuine forward.**                                                                                           |
| `X-Knox-Error`             | KnoxCall's error code, on a KnoxCall-originated refusal.                                                                                                            |
| `X-Knox-Plane`             | Which KnoxCall surface answered: `route`, `proxy`, `ai`.                                                                                                            |
| `X-Knox-Sandbox`           | `true` when the call ran against your Test data space.                                                                                                              |
| `X-Knox-Latency-Ms`        | Total milliseconds inside KnoxCall.                                                                                                                                 |
| `X-Knox-Latency-Phase`     | What that number measured — see below.                                                                                                                              |
| `X-Knox-Upstream-Ms`       | Milliseconds spent waiting on your provider.                                                                                                                        |
| `X-Knox-Overhead-Ms`       | Milliseconds spent in KnoxCall itself.                                                                                                                              |
| `X-Knox-RateLimit-Route`   | `limit=…, remaining=…, reset=…` for the route limit.                                                                                                                |
| `X-Knox-RateLimit-Tenant`  | The same, for your account-wide limit.                                                                                                                              |
| `X-Knox-RateLimit-Monthly` | The same, for your plan's monthly call ceiling.                                                                                                                     |
| `Server-Timing`            | `knoxcall;dur=…, knoxcall_upstream;dur=…`, so your browser's network panel shows the split. Appended to any `Server-Timing` your upstream sent, never replacing it. |

## 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:

```text theme={"dark"}
X-Knox-RateLimit-Route:   limit=100, remaining=97, reset=2026-09-21T10:00:00.000Z
X-Knox-RateLimit-Tenant:  limit=600, remaining=583, reset=2026-09-21T10:00:00.000Z
X-Knox-RateLimit-Monthly: limit=100000, remaining=41233
```

`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.

<Note>
  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.
</Note>

## On errors KnoxCall itself returns

When KnoxCall refuses a call, the body is ours, so the block is repeated there as
a `knoxcall` object alongside the usual `error` envelope:

```json theme={"dark"}
{
  "error": {
    "type": "route_rate_limited",
    "message": "Route rate limit exceeded. Try again in 12 seconds.",
    "request_id": "0f9c1a52-…"
  },
  "knoxcall": {
    "request_id": "0f9c1a52-…",
    "origin": "knoxcall",
    "plane": "route",
    "latency_ms": 3,
    "latency_phase": "complete",
    "code": "route_rate_limited",
    "message": "Route rate limit exceeded. Try again in 12 seconds.",
    "rate_limit": {
      "route": { "limit": 100, "remaining": 0, "reset": "2026-09-21T10:00:00.000Z" }
    }
  }
}
```

The `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.
