Billing & usage accuracy
Most requests are priced from the token usage the provider reports (input, output, cached, audio) times the per-model rate; image, video, 3D and some audio requests are priced per image / per second / per character instead (see the modality table below). Either way the rate is your rate — the model’s published price when your operator has set one, otherwise the provider-cost basis; never marked up from a cheaper upstream you don’t see (which provider actually serves a given model is an internal routing detail, and any margin is the operator’s, not billed to you on top). How precisely we can meter a request depends on how you call the gateway. There are two modes.
Paying for your usage
Section titled “Paying for your usage”Your usage draws down an account balance. Your operator puts your account on one of two payment modes:
- Prepay — you top up the balance up front; requests are served while the balance is positive.
- Postpay — you spend against a credit limit and are invoiced for the accrued usage each period.
This is the platform billing you ↔ the gateway operator. It is separate from Stripe Token Billing, which is how you bill your own end-users.
Prepay — top up your balance
Section titled “Prepay — top up your balance”Create a Stripe Checkout session for the amount you want to add:
POST /gw/billing/checkout # scope: keys:manage{ "amount_usd": 50 }→ { "url": "https://checkout.stripe.com/c/pay/…" }Open the returned url, pay by card, and your balance is credited once Stripe
confirms the payment (the gateway credits on the signed payment webhook — not on
the browser redirect, so a closed tab never loses a paid top-up). The amount is
credited before tax; any VAT is collected by Stripe on top. Minimum and
maximum top-up amounts are set by your operator.
This endpoint exists only when your operator has enabled platform billing; otherwise it returns
404. If you’re unsure which payment mode your account is on, ask your operator.
Postpay — periodic invoices
Section titled “Postpay — periodic invoices”On postpay you keep serving traffic up to your credit limit; the platform issues a Stripe invoice for the usage accrued since the last one (typically monthly). You receive a hosted Stripe invoice link to pay by the due date — paying it restores your headroom for the next period. Usage is invoiced exactly once.
Your per-request spend is always visible in
GET /gw/usage; your operator can confirm your
current balance and limit.
Two modes
Section titled “Two modes”1. Transparent proxy (drop-in)
Section titled “1. Transparent proxy (drop-in)”Point your existing OpenAI/Anthropic client at the gateway base URL and call
vendor routes directly (/openai/*, /anthropic/*, /alibaba/*, …). The
gateway forwards your request byte-for-byte — it never rewrites your body.
- Non-streaming responses always carry
usage, so they are billed exactly. - Streaming responses, on OpenAI-compatible providers, only include
usagein the final chunk if your request setsstream_options.include_usage: true. If you don’t set it, that stream has no usage to meter and is billed approximately, then trued-up at the end of the billing period against the provider’s own numbers (reconciliation).
In short: transparent mode is “we aggregate your traffic and reconcile your
invoice monthly.” For exact, immediate per-request cost, either set
stream_options.include_usage yourself, or use the SDK.
2. Through the SDK (exact, immediate)
Section titled “2. Through the SDK (exact, immediate)”The official SDKs (sociaro-ai for Python and TypeScript) set
stream_options.include_usage for you on every OpenAI-format stream
(Anthropic streams report usage in message_delta events, which the gateway
aggregates). So every call — streaming or not — is metered exactly at the moment
it completes. No month-end true-up needed.
This is the main billing advantage of the SDK, on top of:
- one unified API across all providers (
author/modelslugs), - automatic fallback chains and routing,
- typed image / video / async helpers,
- the
/gwself-service client (keys, budgets, usage).
See the Python SDK and TypeScript SDK guides.
At a glance
Section titled “At a glance”| Call style | Non-streaming | Streaming | Accuracy |
|---|---|---|---|
Transparent, no include_usage | exact | approximate → monthly true-up | eventual |
Transparent, include_usage: true | exact | exact | immediate |
| SDK | exact | exact (set for you) | immediate |
What counts toward cost
Section titled “What counts toward cost”- Input / output tokens at the model’s per-MTok rate.
- Cached prompt tokens are billed at the model’s cache-read rate when set
(cheaper), otherwise at the input rate. Cached tokens are never
double-counted — the OpenAI-format
prompt_tokens(which includes the cached portion) is normalized so the cached part is billed once. - Cache writes (Anthropic prompt caching) at the cache-write rate.
- Audio input tokens (omni models) at the model’s audio rate when set.
Non-token modalities (images, video, audio seconds, 3D) are billed per their own unit — see Async jobs and Media doors.
How each model kind is billed
Section titled “How each model kind is billed”The billing unit depends on the model’s kind (from GET /v1/models). Each
unit is multiplied by the model’s per-unit rate; the cost lands in your usage
records the same way regardless of kind.
| Kind | Unit | Metered from | Notes |
|---|---|---|---|
llm (chat) | tokens (per MTok) | provider usage — input, output, cached, cache-write, audio-input | the cases above; tiered rates and variant multipliers apply where set |
image | per image | number of images returned (or n) | flat USD per generated image; async image jobs hold a provisional cost at create and finalize at terminal state — see async jobs |
video | per second or per token | finalized at terminal state | Alibaba Wan/HappyHorse → per_second_video × resolution multiplier (e.g. 720p ×1, 1080p ×1.5); ByteDance Seedance → per_token × resolution/variant multipliers. A provisional cost is held at create and trued-up on completion — see async jobs |
embedding / rerank | input tokens (per MTok) | provider usage.prompt_tokens | input-only; output not billed |
audio — TTS | per character | Unicode characters of the request input | charged from your request text, not the audio |
audio — ASR | per second of audio | provider usage.seconds | via the chat door / native async |
audio — voice ops | flat | per call | e.g. voice enrollment / design |
3d | per token | finalized at terminal state | async, like video |
embeddingandrerankmodels are live (alibaba/text-embedding-v4,-v3,alibaba/qwen3-rerank).audioand3dmodels are not in the live catalog yet — noaudiomodel is enabled, so both TTS (/v1/audio/speech,404) and ASR (through the chat door) are not yet callable — see embeddings, reranks & audio; their rows document how they bill once available.
Exact per-model rates are not published in a static table (they change); your
actual charge is always recorded per request in
GET /gw/usage. cost_usd there is what you
are charged — your operator’s published rate for that model when one is set,
otherwise the provider-cost basis; either way you never see the upstream
provider or the margin between the two.
If your account has a negotiated discount, cost_usd already reflects it — you
see your own (discounted) rate directly, nothing to apply yourself. The
discount is a percentage off the operator’s published rate for a model; it
does not apply on requests where no published rate exists (you’re billed the
provider-cost basis there, undiscounted). You still never see the upstream
provider or the margin the operator captures — the routing provider is always
hidden (#71).
Some accounts have a different, model-specific rate for one or more models. This comes in two forms, and your operator picks which one applies per model:
- a model-specific discount — simply overrides your general discount for that model only (it can be more or less favorable than your general rate, and may even be no discount at all on a specific model while your general discount still applies everywhere else);
- a negotiated fixed rate — your own rate for that model, computed from your actual usage the same way the published rate is, but set independently of it (not a percentage off the published rate — it can be higher or lower).
Either way, if one model’s cost_usd looks different from what your general
discount would imply, that’s an intentional per-model arrangement, not a
billing error. cost_usd in GET /gw/usage already reflects whichever rate
applies to that request; there’s nothing for you to compute, and you still
never see the upstream provider or the margin the operator captures (#71).