- What the call really cost. The gateway prices each call itself, including its own caching and markups.
- Which model really served. When the model you asked for is down or rate-limited, the gateway falls back to another one. Your cost changes and nothing in your code notices.
A gateway you call
The gateway’s response comes back into your process, so you wrap the client you use to call the gateway, the same way you would for a model provider. The gateway’s recipe reports the token counts, plus what only the gateway knows, when it returns it:OpenRouter
The SDK recognizes both ways of calling OpenRouter and selects the OpenRouter recipe automatically: OpenRouter’s own client,OpenRouter from @openrouter/sdk, and an OpenAI client whose base URL is on openrouter.ai. Both report the same metrics under the same names, so one meter covers either client. See OpenRouter for each client’s event names.
streamOptions: { includeUsage: true } with the OpenRouter client, or stream_options: { include_usage: true } with the OpenAI client. Without it, the stream reports no usage and the call is not metered.
OpenRouter charges in credits, and a single call usually costs a small fraction of one credit. The recipe reports cost as a whole number, so by default it counts in millionths of a credit: a call that cost 0.0003 credits is reported as 300. If the feature or currency you bill in Stigg uses a different unit, pass the recipe yourself with unitsPerCredit. For example, to report in hundredths of a credit:
openrouterRecipe options
LiteLLM Proxy
LiteLLM Proxy’s API follows OpenAI’s format, so you call it with theOpenAI client and its token counts use OpenAI’s field names. Whether you host the proxy yourself or use LiteLLM’s cloud-hosted version, each proxy has its own address, so the SDK cannot recognize it automatically. Pass the recipe with your proxy’s base URL:
x-litellm-response-cost response header. Headers are sent before generation starts, so streamed LiteLLM calls report tokens but no cost. Non-streaming calls report both.
litellmRecipe options
Amazon Bedrock
Bedrock serves models from many vendors through one API, the Converse API. Wrap aBedrockRuntimeClient from @aws-sdk/client-bedrock-runtime. The SDK recognizes it automatically.
Bedrock differs from the other gateways in two ways:
- No
cost. Bedrock returns token counts but no price, so you can bill tokens but not the gateway’s cost. - No routing drift. Bedrock serves exactly the model you name, so there is no
modeldimension.
Billing tokens or billing cost
An OpenRouter or LiteLLM call reports two kinds of numbers: the token counts, andcost, what the gateway charged for the call. You choose which one your pricing is based on:
- Bill tokens to price calls the same way whether they go straight to a provider or through a gateway. Meter the token metrics.
- Bill
costto pass on what the gateway actually charged, plus your margin. Meter thecostmetric.
Optional: convert cost into credits in your code
Optional: convert cost into credits in your code
Instead of mapping a feature to credits in Stigg, the SDK can convert usage into credits before it is reported, and deduct them straight from the credit balance. Use this only when the conversion has to live in code. See Weighted credits.
Gating on cost
By default a gateway check uses a requested usage of 1, which asks “is there anything left?”, and the real amount is reported after the call. When billing tokens, a customer can go over the limit by about one call. When billingcost in millionths of a credit, one call can be thousands of units, so a customer with one unit left can pass the check and then spend well past it. If that matters for your product, pass an estimate that returns an upper bound for the call, for example from max_tokens and the highest rate you expect to pay. It is used as the requested usage.
Routing drift
Themodel dimension records the model that served, not the one you asked for. Filter or group a meter by it in Stigg to see how often your traffic falls back, and how that changes your cost.
A gateway you operate
A proxy you run is a separate process. It sees requests, not the customer or agent behind them, and the customer’s budget lives in your application. So the work splits across the boundary:- Your application checks the budget in-process, as usual, and sends attribution with the request as
x-stigg-*headers. - Your proxy forwards the request, reads usage off the provider’s response, and reports it with
stigg.ingestFromHeaders().
In your application
stigg.headers(context).
In your proxy
vendor is one of anthropic, openai (Chat Completions), openai-responses, gemini or typesafe. It is named rather than guessed because several vendors share field names (input_tokens appears in both Anthropic and OpenAI Responses usage), and a wrong guess would report to the wrong meter. If you omit it, pass a metrics mapper so the SDK knows what to report.