[BUG] Spend meter's rate model can't express real prices: pricing.multiplier is global and capped at 1, and inference_geo is ignored
Preflight Checklist
- [x] I have searched existing issues and this hasn't been reported yet
- [x] This is a single bug report
- [x] I am using the latest version of Claude Code
What's Wrong?
The Claude apps gateway's spend meter keys a rate on (upstream, model), but the price a provider actually charges also depends on the inference geography and, first-party, the request mode. Three documented gaps follow, all in the direction that under-counts spend, so caps admit more than configured.
1. pricing.multiplier cannot express a premium. > 1 is rejected at boot (Number must be less than or equal to 1, at pricing.multiplier). But premiums are exactly what a data-residency deployment needs:
| Upstream | What triggers the premium | Premium | Encoded in the model ID? |
| --- | --- | --- | --- |
| bedrock | us. / eu. / au. / jp. inference profiles, or a bare in-region model id | +10% | Yes — the prefix |
| vertex | regional and multi-region endpoints | +10% | Yes — the endpoint |
| anthropic (first-party) | inference_geo: "us", per request or via a workspace default_inference_geo | 1.1× | No |
| anthropicAws (Claude Platform on AWS) | the same inference_geo: "us" | 1.1× | No |
| foundry | the US Data Zone Standard deployment type | 1.1× | No |
Sources are Anthropic's own: Data residency pricing — "specifying US-only inference through the inference_geo parameter incurs a 1.1x multiplier on all token pricing categories, including input tokens, output tokens, cache writes, and cache reads" and "Regional and multi-region endpoints include a 10% premium over global endpoints" — plus Claude in Amazon Bedrock: "Global: … No pricing premium. Regional: … carry a 10% pricing premium over global endpoints." AWS's Bedrock pricing page publishes two Claude tables, "Global Cross-region Inference" and "Geo and In-region Cross-region Inference", the second exactly 1.1× the first on every column (us-east-1 and ap-southeast-2 checked 2026-09-07; Opus 5 $5.00/$25.00 vs $5.50/$27.50).
The built-in table is list price, i.e. the global rate, so a residency deployment under-counts real spend by ~9% and a $500/month cap admits roughly $550. Systematic, one-directional, and not visible in the config, the boot log, or the audit events.
2. pricing.multiplier is global to the gateway. There is no per-upstream form — checked against 2.1.229, all rejected at boot:
| Attempted form | Result |
| --- | --- |
| multiplier inside an overrides row | Unrecognized key(s) in object: 'multiplier' |
| pricing.upstreams: { bedrock: { multiplier: 0.9 } } | Unrecognized key(s) in object: 'upstreams' |
| pricing.multipliers: { bedrock: 0.9 } | Unrecognized key(s) in object: 'multipliers' |
| pricing.markup: 1.1 | Unrecognized key(s) in object: 'markup' |
Rates are per-upstream (overrides[].upstream), but the multiplier isn't. Multi-upstream failover is a first-class feature, and the natural configurations put one multiplier over two different rate cards: an in-region primary with a global fallback (one tier premium, one not), or bedrock alongside anthropic, where each side carries its own separately negotiated discount. Applying one number to both is wrong for at least one of them.
3. Nothing consumes inference_geo. On anthropic / anthropicAws / foundry the premium is per-request, so overrides — keyed {upstream, model} — cannot price both geos: two requests to the same model on the same upstream differ only by their inference_geo. An org with a US-only workspace default is metered ~9% light on every request with no supported correction.
The meter is already handed the discriminator. The response usage object carries inference_geo, and the pinned binary's usage schema parses it (inference_geo: nullable().optional(), alongside service_tier and cache_creation) and threads it through usage merging. The metering path simply doesn't read it.
On bedrock and vertex the tier is in the model ID, so overrides rows are a workaround there — but a verbose one: four rates × N models, re-derived on every price change, and a model that isn't listed silently falls back to list price, including one added by a version bump.
The two levers also conflict. The config reference notes an override row "includes the higher fast mode rate, so fast and standard requests meter at the same four rates." Fast mode on Opus 5 is $10/$50 against $5/$25 standard — 2×, first-party only. So using rows to correct a geo premium on a first-party upstream halves fast-mode metering: fixing one dimension by breaking another. That is the shape of the problem. The rate model needs another axis, not more rows.
What Should Happen?
Any one of these helps, and the first two are small:
- Allow
multiplier > 1, or add a siblingmarkup, so a flat tier premium is one line instead of a per-model table. - Allow
multiplierper upstream — as a field on anupstreams[]entry, on anoverridesrow, or as apricing.upstreamsmap — so a failover stack or a mixed-provider deployment can price each upstream on its own rate card and its own discount. - Apply the documented 1.1× when the response reports non-global inference, from the
usage.inference_geothe meter already receives. This is Anthropic's own published pricing rule, not third-party pricing the gateway would have to track, and it is the only option that fixes the first-party case at all.
Minor, same theme: an overrides row carries one cache_write rate, but 5m and 1h cache writes are priced apart (geo-tier Opus 5: $6.875 vs $11.00), so a row can encode only one of the two.
Environment Info
- Claude Code version on the gateway server: 2.1.229 (
linux-x64, run asclaude gateway --config gateway.yaml) - Upstream: Amazon Bedrock,
auth: {}(task-role credentials via the AWS default chain),global.anthropic.*inference profiles - Deployment: ECS Fargate behind an internal ALB, RDS for PostgreSQL store,
admin:block enabled - Every schema claim above is a boot-time result from that binary; the config-schema check runs before Postgres, so
could not connect to Postgresconfirms the schema passed. Prices read from Anthropic's pricing docs and AWS's pricing feed on 2026-09-07.
Additional Context
Runtime metering isn't verified here — proving the meter charges the global rate for a us.-profile request needs a live gateway with a store. Everything asserted above is either a boot-time schema result or a published price.
Prior report #83690 raised the Bedrock half of this and asked for tier-aware rates, operator-supplied rate overrides, or a documented disclosure of the skew. 2.1.227 shipped the overrides — the pricing: block, general enough to cover a negotiated discount on any provider, which is the right shape for that ask; thank you for it. That issue was then auto-closed by the stale bot before the rest was triaged, and the direction that survived is the consequential one: caps that admit ~10% more than configured. Filing this as the narrower, provider-general follow-up.