Claude on Bedrock, Vertex and direct are three different products
Same model name, three auth mechanisms, three rate tables, three separate caches — and a dashboard that merges them produces blended figures that are plausible and wrong.
"claude-opus-5" is not one thing. It runs on Anthropic's own API, on AWS Bedrock, and on Google Vertex, and the three deployments differ in every dimension an engineering team actually touches: how you authenticate, what the model is called, what it costs per endpoint class, and — least understood — where the prompt cache lives. Treat them as one product and your numbers go quietly wrong in both directions.
Three namespaces for one model
The same model carries a different id on each platform, with different date grammars:
direct claude-sonnet-4-5-20250929 (dated ids: compact, hyphenated)
bedrock us.anthropic.claude-sonnet-4-5-20250929-v1:0
vertex claude-sonnet-4-5@20250929 (@-dated before 4.6; dateless after)Bedrock adds two ornaments of its own: a geo prefix (us., eu., jp., au., or global. — and global. is a prefix, not the absence of one) and a -v1:0 version suffix. The geo prefix is not decoration either — it encodes the endpoint class, which changes the price. A system that keys anything on "the model name" has to decide, per platform, what the name even is. The general version of that problem — response ids that differ from request ids — is its own post; the platform dimension here is the part of it money depends on.
Three auth mechanisms, three different proxy postures
Direct Anthropic authenticates with an x-api-key header — a bearer-style credential with no body binding, so an intermediary can restructure a request. Bedrock is split: SigV4 signs the body's hash, Bedrock API keys do not, so mutation rights depend on which credential each request carries. Vertex authenticates with a short-lived OAuth2 access token — a bearer, no body hash, so mutation is possible, and the proxy holds nothing durable at all. Same vendor's model, three different answers to "may a middlebox improve this request", each derived from the credential's cryptography rather than anyone's policy.
Three prices — and endpoint class is a price axis
The headline per-million rates happen to agree today ($5/$25 for Opus 5 across all three at the global class), but agreement is a coincidence to verify, not a rule to assume, and it is already false one axis over. Regional and multi-region endpoints carry a +10% factor on both Bedrock and Vertex — visible in Google's own published arithmetic ($5.00 global vs $5.50 multi-region Opus input). Since most production Bedrock traffic uses us./eu. inference profiles, the regional price is the price for most real workloads. Meanwhile some pairs simply do not exist: Vertex publishes no regional rate for Opus 5 or Sonnet 5 because it does not serve them regionally — a pricing engine should refuse that combination rather than average around it. Long-context behaviour splits too, per model version: Sonnet 4.5 on Bedrock doubles input above 200K tokens while Sonnet 4.6 explicitly does not — opposite behaviour on adjacent versions of one line, which is why it is per-row data, not policy. Even provenance differs: the same rate can be read off AWS's marketplace listing for one model and only designated by contract for another, and an invoice-grade number should know which it has. The full published-versus-verified split is the field guide.
Three caches — this is the one that bites silently
The prompt cache is per platform. A prefix written through api.anthropic.com does nothing for the byte-identical prefix arriving at bedrock-runtime; a cache warmed on Bedrock is cold on Vertex. The isolation boundary is not even the platform alone — it is workspace-shaped on direct and account/project-shaped on the clouds — but the platform boundary is the one teams cross without noticing, because the model name stays the same while the cache identity does not.
Concretely: a team migrating traffic from direct to Bedrock sees their cache hit rate collapse and their write volume spike, with no change in their prompts. Nothing is broken. Every Bedrock call is warming a brand-new cache while the direct cache idles toward expiry. A dashboard that merges the platforms renders that migration as "caching degraded fleet-wide" — a plausible reading, and wrong.
What a merged dashboard gets wrong, precisely
Merging produces two blended numbers, each individually believable. A blended $/token averages three rate tables weighted by traffic mix, so it matches no invoice from any of the three vendors — and it moves when the mix moves, which reads as a price change that never happened. A blended cache-hit rate averages across three caches that cannot share entries, so it under-reports every platform's real behaviour and over-promises what a fix on any one of them can achieve. The rule that falls out: display identity and billing identity must be different keys. "Claude Opus 5" is a fine label for grouping a UI; the join key underneath must carry the platform, the platform's own model id, and the endpoint class, or the aggregates are fiction. That three-key split is exactly how Vigil's pricing layer is keyed, and cache-hit aggregation is forbidden from crossing it.
What to do
If you run Claude on more than one platform, check what your cost dashboard uses as its grouping key — a bare model name means your per-model figures are blends, and your first fix is splitting by platform before trusting any of them. Budget any platform migration for a cold cache: expect a write-heavy first day and hold the old platform's traffic until the new cache is warm, rather than reading the hit-rate dip as a regression. And when you compare platform prices, compare at your endpoint class — the +10% regional factor on the clouds is the real price of most production traffic, and the headline global rate is the one you are least likely to be paying.