Skip to main content
Relay records every request that passes through it, and can optionally capture the full request/response bodies. Both are read back through the control plane, so you get usage analytics and request-level debugging without bolting on a separate tool.

Usage tracking

Every request is logged — there’s no opt-in. Each record carries the relay key, policy, model, status, token counts, and timing. Capture happens off the hot path in a detached observer, so it never adds latency to a response. Read it back through the control plane: The usage endpoints filter by policy, model, status, and time window — for example, status >= 400 for errors only, or a model id over the last day:

Where usage is stored

The sink is selectable and hot-swappable via the control plane — no restart:

Payload logging

Payload logging captures the full request and response bodies and attaches them to the matching log record (joined by request id). It’s how you inspect exactly what a client sent and what the provider returned — invaluable for debugging integrations. It’s off by default and gated at three levels. All must line up for a body to be captured:
1

Global master switch

PUT /api/settings/payload-logging with enabled: true. While this is off, nothing is ever captured, regardless of the per-request flags below.
2

Per-request opt-in

Then capture is enabled for a request when either its policy or its relay key opts in — payloadLoggingEnabled: true on either one.
So you can turn capture on broadly (set it on a policy) or narrowly (set it on a single relay key you’re debugging), while the global switch stays the master kill switch.

Reading captured payloads

The bodies come back on the log detail endpoint:
The response includes request_body and response_body, plus request_truncated / response_truncated flags when a body exceeded maxBytes.
Payloads contain prompts and completions — potentially sensitive data. Keep it off by default, scope it to the keys or policies you’re actively debugging, and set a maxBytes cap.