Relays
Every operator node is also a relay. When a user sends a request, it doesn't go straight to the node that will serve it — it goes through one relay hop first. The relay is some other operator's node, and its job is to forward the sealed request to its target without ever being able to read it.
This is how the network keeps a user's identity separate from their prompt: the node that runs the model sees the relay's address, not the user's, and the relay sees an opaque sealed payload, not its contents. Running a relay well is part of being a node on this network — it isn't optional, and it benefits every operator including you.
What your node does as a relay
When your node is picked as a relay for someone else's request, it:
- Receives a request marked with a target operator and node, and the path to forward to (reserve, inference, etc.).
- Forwards the request to the target node's endpoint.
- Streams the target's response back to the client.
The payload your node forwards is sealed to the target node's encryption key, not yours. You can't decrypt it; you're a transport hop. That's deliberate — it's what lets the network use any node as a relay without expanding who can read a given request.
What your node does as a target
When your node is the target (the one serving the request), the request reaches you from a relay, not from the user. From your side:
- The connection's source address is the relay's, so you never learn the user's network identity.
- Everything else — reserve, sealed prompt, receipt, settlement — works exactly as in the payment flow. Relaying changes who you see, not how you get paid.
How relays get chosen
The client picks a fresh relay for each request, and the selection deliberately spreads load and protects privacy:
- The relay is never the target — or a sibling of it. The exclusion is at the operator level: every node belonging to the target's operator is dropped, so a node can't relay for itself or for another of its operator's nodes.
- Owner diversity is mandatory. This is a hard rule, not a preference: a relay is excluded if it shares the target's owner address. The relay and target are therefore always two different operators under distinct owner keys — so no single honest operator ever holds both your network identity and your prompt.
- Compatible nodes are eligible. A relay has to speak a compatible protocol version (and, best-effort, sit on a different /16 subnet than the target).
- Reachable, faster relays are preferred — selection favors relays it has measured as responsive, weighted by latency with enough randomness that no single relay dominates. Reachability is a preference, not a gate: if no known- reachable relay is eligible, the client falls back to the full eligible pool (so cold, unproven relays still get tried) rather than failing.
The upshot for you: a fast, reliable, well-connected node gets used as a relay more often, and reliable relaying builds the reachability reputation that keeps your node in rotation.
Reliability and reputation
The network tracks relay reliability per node. If your node accepts relay traffic but fails to forward it — it's reachable, but can't reach the target — clients down-rank it as a relay for a while and prefer others. If your node is unreachable as a transport endpoint at all, it's demoted faster. Both recover automatically once your node starts forwarding successfully again.
To be a good relay:
- Stay reachable at your advertised endpoint, with low latency.
- Forward promptly to targets and stream responses back without buffering the whole reply.
- Keep your protocol version current, so you remain eligible for both serving and relaying.
- Let your node's own response headers through — see below.
Don't strip the X-Zs-Relay-Hop header
Your node stamps a small header, X-Zs-Relay-Hop: 1, on every response it
produces while relaying. It carries no information about the request, the
client, or the target — its only job is to prove that your node actually
handled the request, as opposed to the request dying at your CDN, load
balancer, or reverse proxy before it ever arrived.
That distinction is what protects you. When a relayed request fails with a generic gateway error and no protocol error code, a client has to decide who was at fault. If your header is present, the client knows your node did its job and looks elsewhere. If it's missing, the client concludes your front door ate the request and down-ranks you.
So if something in front of your node strips unknown response headers, you will be quietly penalised for failures that were never yours, with no error in your own logs to explain it. Check for:
- Cloudflare Transform Rules or WAF rules that remove response headers.
- nginx
proxy_hide_header/more_clear_headerswith a broad pattern. - An API gateway or CDN configured to pass through only an allow-list of
response headers — add
X-Zs-Relay-Hopto it.
If you serve browser clients, the header must also be readable cross-origin.
Your node already advertises it in Access-Control-Expose-Headers; if your edge
rewrites that header, keep X-Zs-Relay-Hop in the list. A browser cannot read
a header that isn't exposed, and it treats "cannot read" identically to "not
sent" — so stripping it there has the same effect as stripping it outright.
Nodes running an older protocol version don't send this header, and clients know not to hold its absence against them. It only matters once your node advertises support for it.
Fail-closed privacy
The privacy guarantee is enforced on the client side, and it fails closed: if no eligible relay is available for a target, the client refuses to send directly rather than expose the user's address.
As an operator you don't have to implement that rule — but it's worth knowing that a sparsely-connected network hurts everyone's routability, which is another reason relaying for others is in your interest.