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

# Request ids

> Every response carries a request id that the gateway mints at the edge: log it, and quote it when you report a problem.

Every response the API answers, successful or not, carries an `X-Request-Id` header:

```
X-Request-Id: 6f1c2a8e-3b7d-4f21-9a0c-2e5b81d7a4f3
```

Every error body repeats it as `request_id`:

```json theme={null}
{
  "type": "https://developers.investorlift.com/guides/concepts/errors#internal_error",
  "title": "Internal error",
  "status": 500,
  "code": "internal_error",
  "detail": "The request failed. Quote request_id when reporting it.",
  "instance": "/v1/buyers/match",
  "request_id": "6f1c2a8e-3b7d-4f21-9a0c-2e5b81d7a4f3"
}
```

The gateway mints the id at the edge, and it is one id end to end. The response also carries it as `zp-rid`, the
gateway's own name for it, with the same value. The API writes one server-side log line for your call and keys it on
the id. That line holds the route, the status, the duration and the row count. It also holds the account the key
belongs to and the dataset version the answer came from.

The gateway answers some refusals on its own: a `401`, a `403 quota_exceeded`, a `429`. Such a refusal carries the id
as `zp-rid` and as `request_id` in the body. It carries no `X-Request-Id` header, because that request never reached
the API. A client that wants one header on every response reads `zp-rid`.

**Log it on every response, not just on errors.** A 200 that returned the wrong rows is the hard case. Without the id,
no one can find the call.

## An id you send does nothing

At the edge, the gateway replaces an `X-Request-Id` you send, and never honours it. So nothing a caller sends can
collide with an entry in the request or audit records, or forge one. Keep your own trace id in your own logs, and
store the API's id next to it.

Do not send a `zp-rid` either. The gateway treats one it gets as its own trace id. That id comes back as `zp-rid`, and
as `request_id` on a refusal the gateway answers itself, because the gateway keys its logs on it.

If the value is not a UUID, the gateway replaces it before the API sees it. The two ids on your response then stop
matching, and a support lookup must start from `X-Request-Id`. A UUID you send travels end to end. A collision with one
of your own earlier ids is then yours to avoid.

<Note>
  A `500 internal_error` never echoes a database message. The `request_id` is the whole of what you can report, so log
  it. See [Errors](/guides/concepts/errors).
</Note>

## Partners and staff

On the internal host, which staff and contracted partners reach on the company network, a caller can bring its own
id. Send `X-Request-Id`, and the API uses your value instead of a minted one. So your trace id and the API's log line
carry the same label. The id must be 1 to 64 characters of letters, digits, `.`, `_`, `:` or `-`. The API ignores any
other value and uses a UUID.

The log line there also names the user the caller identified in `X-On-Behalf-Of`. For every response that carried
contact fields, the API writes an audit line. The audit line names the key, that value, the endpoint and the ids served.
That is a condition of the contact scope, not a debugging feature. So the header must be a real id of the person asking,
not a constant.


## Related topics

- [Errors](/guides/concepts/errors.md)
- [Acceptable use and abuse policy](/guides/acceptable-use.md)
- [The response envelope](/guides/concepts/envelope.md)
- [Quickstart](/guides/quickstart.md)
- [The Investor object](/api-reference/objects/investor.md)
