zc-request-id value (zcreq_…) is the correlation spine. The same id flows through the challenge, the paid retry, the allowance check, and the usage record. See how ZeroClick works for the lifecycle.
ZeroClick to your API (request)
Headers ZeroClick sets on every request it forwards to yourupstreamBaseUrl:
zc-agent-id and zc-buyer-id
These answer two different questions, and a request can carry either one or both:
zc-agent-idis who called. It is always the agent that executed this request, never some other agent that happens to have paid for the plan being drawn down.zc-buyer-idis who they belong to. One buyer can hold many agents; every one of them is entitled to everything the buyer owns.
Key per-caller state (rate limits, per-run scratch data) on
zc-agent-id. Key per-customer state (history, tenancy, saved records, anything a human should still see after their agent is replaced) on zc-buyer-id when it is present, since a buyer can retire one agent and call you with the next. Two requests carrying the same zc-buyer-id under different agent ids are the same customer.
Before forwarding, ZeroClick strips every inbound
zc-* and x-zc-* header plus x-payment, payment, and payment-signature, then sets its own. An agent can never spoof these values. Any upstream auth you configured between ZeroClick and your API passes through unchanged.zc-signature
t=<unix seconds>,kid=<hsec_…>,v1=<64 lowercase hex>; sandbox traffic appends ,sb=1. t is the signing time (verify within a tolerance, 300 seconds by default). kid names the signing secret so you can select the right one during rotation. v1 is the HMAC-SHA256 (constant-time compare) over a six-field canonical string: t, the uppercased method, the raw path and query, the SHA-256 hex of the raw body bytes, the zc-request-id value, and the zc-agent-id value or empty string. The signed canonical is identical for sandbox and live traffic; verifiers that parse only t/kid/v1 ignore the trailing sb=1. Full byte-level rules: signature spec.
Your API to ZeroClick (response)
zc-usage
{ "serviceSlug", "meterSlug", "quantity" } items; quantity is an integer from 0 to 2,147,483,647 (0 settles a capped meter at zero). Set it only on a 2xx response that delivered. A 4xx must not carry it. ZeroClick strips the header before the agent sees the response. This is the preferred way to settle usage; settle usage covers it against the async POST /v1/usage alternative.
If billing fails after your API already delivered (a malformed header, a denial, or a settlement exception), ZeroClick does not drop the response. It returns the body to the agent and names the failure in the zc-usage-error response header. The payment stays observable rather than silently lost.
ZeroClick to the agent (response)
Identity-only responses carry no receipt header. Free-mode responses covered by included units carry no
zc-billing: there was no per-request payment to settle.
zc-billing
The agent to ZeroClick (request)
The proof carries everything: the challenge an agent signs embeds ZeroClick’s payment metadata, so the paid retry needs no other headers. The retry must be byte-identical to the challenged request, because the payment is bound to the request’s body digest. Protocol details: payment protocols.
zc-mode
free is the only recognized value; ZeroClick treats anything else as paid rather than rejecting it. The mode applies to the whole request, so your allowance pre-gate (POST /v1/usage/check) honors the same decision the proxy made. Agents send it on every call they want covered. ZeroClick tracks the allowance per buyer - every agent claimed by the same human draws from one shared pool - and serves it only to claimed agents with a verified email, so an unidentified free-mode caller is answered with 401 bearer_required and registers - and gets claimed - before its first covered call. See free and identity endpoints.