Skip to main content
Every response the API answers, successful or not, carries an X-Request-Id header:
Every error body repeats it as request_id:
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.
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.

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.