Three ways to tag a request
The gateway reads the customer id from the first of these that is present, in this order:
If you already pass
user to the OpenAI SDK or metadata.user_id to the Anthropic SDK, you
are done — the gateway picks those up with no code change and still forwards the fields to
the provider unchanged. The header is for everything else (Bedrock-style /model/…/converse,
text-to-speech, GPU endpoints) and for when you want one mechanism across every SDK.
metadata.user_id is enough:
Option C: customer keys (recommended)
When the requests come from the customer’s own systems — a reseller integration, a tenant you onboard with their own credentials — give that customer a customer key instead of asking them to tag anything. A customer key is one of your organization’s API keys bound to one customer id: every request made with it is billed to you and reported under that customer, with nothing to add to the request. Add the customer’s organization / sub-account and the key becomes a sub key that also splits the customer’s spend by their organizations (cust_8f3a2b › emea).
Create them in the portal — Keys → Create key → One of your customers (enterprise admins)
— or over the API with one of your organization-level keys:
x-aireserve-customer or user,
the key’s customer is what gets reported. The x-aireserve-feature tag below still works on a
customer key.
Each customer key on the Keys page carries a Customer badge and a Spend for this customer
link straight into Analytics, where a customer with sub keys expands into its organizations in
the Spend by Customer card. Listing and revoking keys, the error codes, and the full schemas
are on the Customer keys reference page.
The optional feature tag
x-aireserve-feature names the feature or action inside your product that made the call —
draft-email, summarize-thread, nightly-sync. It is recorded next to the customer id on
every usage record and comes along in exports, so you can later split one customer’s spend by
what they used. It is header-only and entirely optional.
Limits and validation
Values are trimmed of surrounding whitespace. A tag that is empty, too long, or contains
control characters is ignored — the request is served and billed normally, it just lands
as untagged. Tagging never produces an error response. When the header is invalid but the body
carries a valid
user / metadata.user_id, the body value is used.
Where it shows up
- Analytics → Spend by Customer. The portal’s Analytics page gains a Spend by Customer card listing your top 25 customers in the selected date range by spend, with requests, tokens, and each customer’s share of spend. An (untagged) row holds every request that carried no customer id, so the table always reconciles with the period total. The card appears only once at least one request in the range carried a customer id; it follows the same date range and team/member filters as every other card.
- CSV / JSON download. Each card downloads its own rows (
endCustomerId,requests,tokens,spendUsd,spendShare), and the page-level Download all data (JSON) includes the same breakdown. - The API.
GET /v1/customers/usagereturns the same figures per customer — plus, once your organization has pricing rules, what each customer owes and your margin — andGET /v1/customers/{customerId}/usagedrills into one customer. See Check the amount.
Requests whose results are produced by a background job after the call returns — image
edits and video generation — are not attributed to a customer yet. Everything served inline
(chat, messages, responses, image generation, speech, Bedrock-style converse, GPU chat
completions) is.
Pricing you charge
Spend by Customer tells you what each customer cost you. Pricing rules add what each customer owes you: a rule is the price your organization charges for a slice of its tagged usage, and every matched request is priced with it, so revenue and margin sit next to cost in the usage API. Each rule has a scope (which customers and features it covers), a kind (how the amount is computed), and an effective window (the period of usage it prices).
When several rules cover a request, the most specific scope wins: customer and feature,
then customer only, then feature only, then all customers. Within one scope, the rule whose
window covers the request’s UTC day and has the latest effective from wins, so a price change
is a new rule with a later start — the old one keeps pricing the usage it covered. A window may
start in the future (a scheduled price) and may be closed with an end date; closing it never
rewrites history. Usage that no rule covers is reported at cost and flagged
priced: false,
so a gap in your price list shows up as a visible zero margin rather than a quietly wrong total.
How the amounts come together:
- Markup, per-request, and per-token rules are applied to each successful request and summed. A monthly flat fee is booked once per customer per UTC month, on the first day in that month with matched usage, and is never pro-rated.
- Failed requests are never billed to a customer. They are left out of
requestsand the token counts. Their cost still counts towardcost_usd, so your cost reconciles with the rest of Analytics. - Amounts are USD with six decimals, rounded half away from zero once per request. Margin is
billable − cost; margin percent ismargin ÷ billable × 100, two decimals, andnullwhen nothing was billable. - As soon as one rule applies to the period, every report row carries
billable_usd,margin_usd, andmargin_pctnext tocost_usd(has_pricing_rules: true). Theuntaggedbucket stays cost-only — nothing can be billed to a customer you did not name.
Pricing rules are reporting-only, like the tags themselves. They never change what AI
Reserve charges your organization, and AI Reserve does not invoice your customers for you —
the figures are there for you to bill from.
In the portal
Organization admins manage rules under Analytics → Customer pricing (also reachable from Set prices on the Spend by Customer card). The list shows every rule’s scope, price, window and status — Active, Scheduled, or Ended. Add rule asks who the price is for, then how you charge, and reads the rule back in one sentence before saving. Change price starts a new version and ends the current one where it begins; End stops a rule from now, or removes one that has not started yet. Once one rule covers the selected range, the Spend by Customer card adds Revenue and Margin (amount and percent) to every customer row, to each organization under it, and in a totals line; a By feature view breaks the same figures down byx-aireserve-feature tag. A
negative margin is labelled Loss, a gross margin under 20% Low margin, usage that no rule
covers No rule (shown at cost, with a link to add one), and a group where only some usage was
priced Partly priced. The card’s CSV gains costUsd, revenueUsd, marginUsd, marginPct
and priced columns. The figures are the ones GET /v1/customers/usage returns for the same
range: the same engine prices both, so the portal and the API never disagree. Margin is an
organization-wide figure — it is computed for the whole organization, not for a team or member
filter — and, like the API, for ranges of up to 92 days.
Check the amount (API)
Two read endpoints return usage, cost, and — with pricing rules — billable amount and margin per customer, so your own billing or support tooling can answer “what does this customer owe?”. Both take your AI Reserve API key and are scoped to the organization that owns it.start is inclusive and end exclusive; both accept a UTC date (2026-10-01) or an RFC 3339
timestamp. Leave them out for the last 30 days. A period may span at most 92 days — longer
ranges and malformed dates return 400. The customer id in the path is URL-encoded, exactly as
you tagged it; an id you never tagged returns zeros, not 404.
draft-email feature, and a $99 monthly flat fee for everything else the customer does:
billable_usd; requests under a monthly flat rule add nothing per request. Had a feature
matched no rule at all, its row would show billable_usd equal to cost_usd and
priced: false.
Both endpoints share your organization’s API rate limit and return the standard
error shape —
401 for a missing key, 403 when a screen rejects
it, 429 with Retry-After. Full request and response schemas are under Customers in the
API reference.