Skip to content

Forward to an external router

You may not want to run provider billing at all. Someone else — a platform, a reseller, your own central IT — runs a router with the accounts on it, and your agents reach models through theirs.

The question that usually stops this arrangement is: do they then get my customer list?

They do not have to, and whether they do is decided by who runs the router, not by the protocol:

who runs the routerdo they see your users?how calls are made
an LLM provider or platformno, and they have no reason to. They meter you as one accountyour agents call out opaque, and their router leaves requireIdentifiedCaller off
your own company, hooked to Bedrock, Azure or similaryes, deliberately. You are accountable for your own people and want to see which user each call was forcallers are identified, and the router sets requireIdentifiedCaller: true

Both are normal. The rest of this page is mostly the first case, where the operator is someone else; the second is your own router and is covered in Run your own.

your user your agent your policy your router what leaves one identity their router holds the keys they see your agent · they need not see your users

Your router forwards under its own HexaEight identity: the external operator authorises your router, once, and that is the party they have a relationship with and bill.

There is no token to carry. Your router proves itself cryptographically, with its identity, on every call. That is the credential. The auth and secret fields in an upstream entry exist for ordinary providers — Bedrock, OpenAI and the like, which issue API keys — and an entry that forwards to another HexaEight router leaves auth at its default, none.

Whether your individual users are named to them is your choice.

Your agent decides this, per call. Where it would normally put the person it is acting for, it puts the literal :opaque: instead. Nothing is configured on the external router, and nothing is configured in advance — it is a choice made in the request:

your agent sendsthe external router meters
forUser: [email protected]per caller — they see alice
forUser: :opaque:per agent — they see only you

With :opaque:, per-caller accounting stays inside your agent, where your callers are actually known. The external router meters your agent as one customer.

Nothing is weakened by it:

  • the relaying agent is a real identity that was already authorised
  • it is the party the external router has a relationship with and bills
  • the stored subject is the agent, so every log and downstream meter says so plainly

Nobody is misled. The trade is explicit and yours to make: choose opacity, and the external router gates and meters per agent instead of per person.

A customer roster should not have to be disclosed to a model provider as the price of routing through one.

youthe external operator
provider keys—holds them
which models are availablerequestdecides
who your end users areknow themneed not
per-user meteringyours, locallyper your agent
revoking one of your usersyour policynot involved

Your users are admitted, metered and revoked by your agent’s policy. The external operator authorises the identity that calls them — your agent when it calls out directly, or your router when you run one in between — once, and never sees a person behind it.

Running the router that others forward into, you want the opposite of a self-hosted deployment:

  • accept opaque callers — leave requireIdentifiedCaller off. Turning it on requires every customer to disclose their user list to you, which most will refuse and none of them need to do
  • authorise per calling identity — that agent or router is your customer
  • meter per calling identity — it is what you can bill

A company running a router for its own staff wants the reverse of all three, because the people on the other side are its own: see Run your own.

A self-hosted router usually sets requireIdentifiedCaller: true; an external one usually must not. The two deployments want opposite things, and the setting is how you say which you are.

The operator of the external router gives you two things:

its URLwhere their router listens
admissionthey add the identity that will call them to their policy, once — your agent, or your router if you run one in between

They do not need your user list, and you do not need an account with their model providers.

Forwarding is just an upstream whose URL is their router instead of a provider. In your own upstreams.yaml:

upstreams:
- match: "partner-*" # a route name you choose
shape: "anthropic" # the API your engines speak
url: "https://their-router.example.com/v1/messages"
auth: "none" # your router's identity IS the credential

Then seal an engine against it exactly as you would any other route:

Terminal window
hexaeight-activate engine --add chat \
--name chat \
--model "partner-sonnet|<their model id>" \
--router "<your-router-identity>|http://127.0.0.1:5100"

Your agents still talk only to your router. It decides which calls leave.

Opacity is the calling agent’s choice, made per request: it either sends the user’s subject as forUser, or sends :opaque:.

forUser: <sha512 of the user's email> they meter per person
forUser: :opaque: they meter per agent - your list stays yours

And the receiving operator decides whether opacity is allowed at all, with one line in their upstreams.yaml:

requireIdentifiedCaller: true # refuses opaque callers outright

If you are the external operator, leave that off. Turning it on requires every customer to disclose their user list to you as the price of routing through you.

Nothing stops you running your own router for some routes and forwarding others. Agents name a route; where that route resolves is the router’s business. Moving a model from your account to a partner’s — or back — changes no agent configuration.