Bedrock’s pricing page looks simple: a rate per million input tokens, a rate per million output tokens, done. Then the first real month arrives and the bill is several times the spreadsheet. The pricing card wasn’t wrong. It just doesn’t describe how spend accumulates in a production system with long system prompts, tool definitions, retrieval context, reasoning tokens and retries.
This is the playbook we use when a team already has something running on Bedrock and wants the bill to be smaller and predictable. It is ordered the way we work: measure first, then the changes that need no commitment, then the ones that do. There is a fully worked cost example in the middle with the arithmetic shown.
Prices and model lineups in this article are as of October 2026. They change often. We quote Anthropic’s published list prices for the arithmetic; confirm the exact Bedrock rate for your model, region and endpoint on the Bedrock pricing page before you budget.12
How a Bedrock bill is actually built
For a Claude model on Bedrock, one request can touch six or seven different meters. Teams that model only the first two are the ones who get surprised.
| Meter | What drives it | Why it surprises people |
|---|---|---|
| Uncached input | System prompt, tool schemas, retrieved context, conversation history | Agents resend the whole history and every tool definition on every turn |
| Output | The answer plus any reasoning the model does | Five times the input rate on current Claude models2 |
| Cache writes | First use of a cached prefix (1.25x input for a 5-minute TTL, 2x for 1 hour) | A prefix that changes every request is written every request |
| Cache reads | Reuse of a cached prefix (0.1x input; 0.05x on Sonnet 5.5 and Opus 5.5) | Cheap, but only if the prefix is byte-for-byte stable2 |
| Endpoint premium | Regional or geographic routing instead of global | 10% premium over global for Claude 4.5 models and later3 |
| Long-context tier | Haiku 5.5 prompts over 100,000 tokens | The whole request moves to the higher rate, cache reads included2 |
| Committed capacity | Reserved tier or Provisioned Throughput | Billed whether or not you send traffic |
One accounting detail catches finance teams: Claude models on Bedrock are third-party models billed through AWS Marketplace, so the charges show up in Cost Explorer under the model provider rather than under Amazon Bedrock.4 If your dashboard filters on the Bedrock service, your biggest line item may be missing from it.
The five surprises we diagnose most often
- Reasoning tokens. Sonnet 5.5 and Haiku 5.5 on Bedrock have adaptive thinking on by default, with effort defaulting to high and medium respectively.45 Thinking tokens are part of the billed output, and Anthropic reports them separately in
usage.output_tokens_details.thinking_tokens.6 A classification call that “only returns one word” can still bill hundreds of output tokens. - Token counts measured on the wrong model. Claude 4.7 and later use a newer tokenizer that produces roughly 30% more tokens for the same text than Sonnet 4.6 and earlier.2 A budget built from last year’s token logs is low before you change anything else.
- Oversized
max_tokens. Bedrock throttling is based on an upfront reservation of input tokens plusmax_tokens, not on what the model actually generates.7 Setting it to the model maximum “just in case” burns quota, which pushes teams to buy capacity they don’t need. - Retries that resend the full prompt. Every retry of a long-prompt call pays for the prompt again. Aggressive client retries layered on SDK retries layered on an agent framework’s own retry loop multiply quietly.
- Capacity bought for the peak. Committed capacity sized for the busiest hour spends most of the month idle.
Step 1: make spend attributable before you optimise
You cannot cut what you cannot attribute. Bedrock now gives you three complementary mechanisms, and we usually use two of them together.
- Application inference profiles. Create a profile per application or team, tag it, and call the profile ARN instead of the model ID. The tags flow to Cost Explorer and the Cost and Usage Report. The finest grain is per usage type per day, so this is for chargeback, not per-request analysis.8
- Per-request metadata. Attach up to 16 key-value pairs to each Converse or InvokeModel call. They land in your model invocation logs (only when logging is enabled in that region), not on your bill, so you compute cost from token counts and your own rate card.9
- CloudWatch runtime metrics.
InputTokenCount,OutputTokenCount,CacheReadInputTokenCount,CacheWriteInputTokenCount,InvocationThrottlesand latency metrics, published underAWS/Bedrock.7
The wrapper we put on the call path looks roughly like this. It also sets up the cache checkpoint used in step 2, so it does double duty.
import boto3
brt = boto3.client("bedrock-runtime", region_name="us-east-1")
SYSTEM_PROMPT = load_prompt("support_system", version="v14") # static, versioned
def answer(question: str, context: str, *, feature: str, user_hash: str) -> str:
resp = brt.converse(
# Swap in an application inference profile ARN to get cost allocation tags.
modelId="global.anthropic.claude-sonnet-5-5",
system=[
{"text": SYSTEM_PROMPT},
{"cachePoint": {"type": "default"}}, # everything above is cacheable
],
messages=[{
"role": "user",
"content": [{"text": f"<context>{context}</context>\n\n{question}"}],
}],
inferenceConfig={"maxTokens": 800}, # also bounds the quota reservation
requestMetadata={"feature": feature, "user": user_hash, "env": "prod"},
)
u = resp["usage"]
# inputTokens excludes cache reads and writes, so record all four.
emit_usage(feature, u["inputTokens"], u.get("cacheReadInputTokens", 0),
u.get("cacheWriteInputTokens", 0), u["outputTokens"])
blocks = resp["output"]["message"]["content"]
return next(b["text"] for b in blocks if "text" in b)Keep metadata keys low-cardinality (feature, team, env) and never put personal data in them; AWS’s own guidance says the same.9 Once invocation logs are flowing to CloudWatch Logs, a Logs Insights query gives you a per-feature view in seconds:
fields requestMetadata.feature as feature, modelId,
input.inputTokenCount as inTok,
output.outputTokenCount as outTok
| stats sum(inTok) as inputTokens, sum(outTok) as outputTokens, count() as calls
by feature, modelId
| sort outputTokens descThen put an alarm on it. We like an anomaly band on hourly output tokens, because runaway agents and bad prompt deploys show up there first. In Terraform:
resource "aws_cloudwatch_metric_alarm" "bedrock_output_tokens" {
alarm_name = "bedrock-output-tokens-above-band"
comparison_operator = "GreaterThanUpperThreshold"
evaluation_periods = 2
threshold_metric_id = "band"
alarm_actions = [aws_sns_topic.llm_spend.arn]
metric_query {
id = "m1"
return_data = true
metric {
namespace = "AWS/Bedrock"
metric_name = "OutputTokenCount"
period = 3600
stat = "Sum"
}
}
metric_query {
id = "band"
expression = "ANOMALY_DETECTION_BAND(m1, 3)"
label = "OutputTokenCount (expected)"
return_data = true
}
}We deliberately alarm on the metric without a ModelId dimension. Requests that fail before Bedrock resolves the model are published without it, so filtering by model can undercount.7
Step 2: cache the stable prefix
In agent and RAG systems the system prompt and tool definitions are usually the largest single chunk of input, and they are identical across requests. Prompt caching turns that chunk from full price into a fraction of it.
The mechanics that matter on Bedrock:
- Checkpoints are evaluated in the order
tools, thensystem, thenmessages. Changing anything earlier invalidates everything after it.10 - The Claude 5.5 models and Opus 5 need at least 512 tokens before a checkpoint (Sonnet 5 needs 1,024), allow up to four checkpoints, and support 5-minute and 1-hour TTLs. Some older models need far more: 4,096 tokens for Opus 4.5 to 4.7 and Haiku 4.5.10
- The TTL resets on every hit. If a prefix is used more often than every five minutes, the 5-minute cache stays warm on its own; the 1-hour option is for prefixes reused less often than that.10
- Cache reads don’t count toward your tokens-per-minute quota; cache writes do.7
- Caching is not available for batch inference, and cross-region routing can increase cache writes at times of high demand.10
The break-even is quick. With a 5-minute write at 1.25x and a read at 0.1x, a prefix pays for itself the first time it is read again.2 The failure mode is not the price, it is prefix instability. The bugs we find most often: a timestamp or request ID rendered into the system prompt, tool definitions serialised in a non-deterministic order, per-user data placed above the checkpoint, and changing the reasoning effort between turns, which also invalidates the cache.6 Watch CacheWriteInputTokenCount against CacheReadInputTokenCount; if writes stay high after warm-up, the prefix is not as static as you think.
Step 3: route each request to the cheapest model that passes
The biggest structural saving is not sending routine work to an expensive model. The spread between tiers is large:
| Model (list, per million tokens) | Input | Cache read | Output | Bedrock batch support |
|---|---|---|---|---|
| Claude Haiku 5.5 (prompt up to 100K) | $0.10 | $0.01 | $0.50 | Not listed |
| Claude Haiku 5.5 (prompt over 100K) | $0.50 | $0.05 | $2.50 | Not listed |
| Claude Sonnet 5.5 | $2.00 | $0.10 | $10.00 | Not listed |
| Claude Opus 5.5 | $4.00 | $0.20 | $20.00 | Check model card |
| Claude Opus 5 | $5.00 | $0.50 | $25.00 | Yes |
Prices are Anthropic’s list rates as of October 2026; batch support is from the Bedrock model cards and batch documentation at the same date.24511 Sonnet 5.5 output costs 20 times Haiku 5.5 output. If even half your traffic can run on the small model, that dominates every other optimisation in this article.
There are three router designs we use, in rising order of complexity:
- Static rules. Route by endpoint or task type. Extraction, classification and short summaries go small; anything with tools or long reasoning goes large. Cheap, transparent, and often enough.
- A small classifier. A Haiku-class call that labels the request before dispatch. It adds a few hundred tokens and some latency per request, so include it in the cost model.
- A cascade. Try the small model first and escalate when a validator fails (schema check, confidence threshold, a grader). This works well when failures are detectable; it is expensive when they are not, because you pay for both calls.
Bedrock’s managed option, intelligent prompt routing, is worth knowing about but check whether it fits. It routes between two models in the same family, is optimised for English prompts, and its supported list currently covers Amazon Nova and Meta Llama models rather than Claude.12 AWS prices it at $1 per 1,000 requests and says it can reduce costs by up to 30%; treat that as the vendor’s claim and measure on your own traffic.1
Decide with your evals, not the leaderboard
Before we change any routing, we ask the team to fill in this table on their own evaluation set. The point is to stop reasoning from marketing pages; teams are regularly surprised by how much traffic the smaller tier handles.
| Request class | Candidate model | Eval pass rate | p95 latency | Cost per 1K requests |
|---|---|---|---|---|
| Intent classification, extraction | Haiku 5.5, low effort | Measure | Measure | Compute from logs |
| Grounded answer from retrieved context | Haiku 5.5 vs Sonnet 5.5 | Measure | Measure | Compute from logs |
| Multi-step tool use, planning | Sonnet 5.5 vs Opus 5.5 | Measure | Measure | Compute from logs |
Step 4: control output and reasoning spend
Output is the expensive side of the meter, and it is the side teams model worst. The levers, in the order we pull them:
- Set effort deliberately. On adaptive-thinking models, effort (set in
output_config) controls how much the model reasons, and at lower settings it may skip thinking on easy inputs.6 Pick it per request class, and hold it stable within a conversation so you don’t break the cache. - Cap
max_tokensper route. A classification route does not need the same ceiling as a report generator, and a lower ceiling also lowers your quota reservation.7 - Ask for structure. A JSON schema with short fields produces fewer tokens than a prose answer the application then parses.
- Stop early when streaming. If a guardrail or repetition check sees the response going wrong, cancel the stream rather than letting it run to the ceiling.
A quick way to size this lever: for every 100 output tokens you remove from a route, the monthly saving is requests x 100 / 1,000,000 x output price. On 400,000 Sonnet 5.5 requests a month that is 40 million tokens, or $400.
Worked example: a support assistant at one million requests a month
Here is the arithmetic for a realistic workload. The assumptions are ours and labelled as such; the prices are list prices on the global endpoint as of October 2026.2
| Assumption | Value |
|---|---|
| Requests per month | 1,000,000 |
| Static prefix (system prompt + tool definitions) | 6,000 tokens |
| Retrieved context | 3,000 tokens |
| Conversation history + question | 1,000 tokens |
| Output, including reasoning | 500 tokens |
| Cache hit rate on the prefix, once enabled | 90% (assumed) |
| Share of traffic that passes evals on Haiku 5.5 | 60% (assumed) |
Baseline: everything on Sonnet 5.5, no caching
- Input: 10,000 tokens x 1M requests = 10,000M tokens x $2.00 = $20,000
- Output: 500 x 1M = 500M tokens x $10.00 = $5,000
- Total: $25,000 a month
Add caching on the 6,000-token prefix
- Prefix tokens: 6,000M. Reads: 5,400M x $0.10 = $540. Writes: 600M x $2.50 = $1,500.
- Rest of input: 4,000M x $2.00 = $8,000. Output unchanged: $5,000.
- Total: $15,040 a month, about 40% lower.
Notice that at a 90% hit rate the writes cost more than the reads. Pushing the hit rate to 99% (steadier traffic, a stable prefix) brings the prefix cost from $2,040 down to $744.
Add routing: 60% of requests to Haiku 5.5
- Haiku slice (600K requests): prefix reads 3,240M x $0.01 = $32.40, writes 360M x $0.125 = $45, other input 2,400M x $0.10 = $240, output 300M x $0.50 = $150. Subtotal $467.40.
- Sonnet slice (400K requests): prefix reads 2,160M x $0.10 = $216, writes 240M x $2.50 = $600, other input 1,600M x $2.00 = $3,200, output 200M x $10.00 = $2,000. Subtotal $6,016.
- Classifier on Haiku 5.5 (300 input, 5 output tokens per request, too short to cache): 300M x $0.10 + 5M x $0.50 = $32.50.
- Total: $6,515.90 a month, about 74% below baseline.
Worked example
Monthly cost, one million requests
Illustrative workload at list prices, October 2026. Bars split each total into uncached input, cache reads and writes, and output.
Two things fall out of the numbers. First, after caching and routing, the Sonnet slice is 92% of the bill, and within it the uncached retrieval context ($3,200) and output ($2,000) are the biggest remaining lines. Trimming retrieved context from 3,000 to 2,000 tokens on that slice saves another $800 a month. Second, residency has a price: if you must use a US geographic inference profile instead of the global one, the 10% premium takes the total to about $7,167.3 Your numbers will differ; the method is the point.
Step 5: batch and service tiers for work that can wait
Bedrock batch inference processes a JSONL file from S3 asynchronously at 50% below on-demand pricing for selected models.113 It is the right home for overnight enrichment, backfills, evaluation runs and periodic re-summarisation. Three things to check before you plan around it:
- Model support. The batch-supported list includes Claude Opus 5, Sonnet 4.6 and Haiku 4.5, but the Sonnet 5.5 and Haiku 5.5 model cards list Standard tier only, with no Batch, Flex, Priority or Reserved support yet.1445 New models often launch this way, so check the card before promising a saving.
- Tool calling. Batch jobs using the Converse format reject records with
toolConfig; use the InvokeModel format if you need tools.13 - No caching. Prompt caching does not apply to batch, so the 50% discount is against full-price input.10
Each line of the input file is a record ID plus the model’s native request body:
{"recordId": "TICKET-000001", "modelInput": {"anthropic_version": "bedrock-2023-05-31", "max_tokens": 400, "messages": [{"role": "user", "content": [{"type": "text", "text": "Summarise this ticket thread: ..."}]}]}}bedrock = boto3.client("bedrock", region_name="us-east-1")
bedrock.create_model_invocation_job(
jobName="ticket-summaries-2026-10-24",
roleArn="arn:aws:iam::123456789012:role/BedrockBatchRole",
modelId="us.anthropic.claude-opus-5", # confirm Batch support on the model card
inputDataConfig={"s3InputDataConfig": {"s3Uri": "s3://acme-llm-batch/in/"}},
outputDataConfig={"s3OutputDataConfig": {"s3Uri": "s3://acme-llm-batch/out/"}},
)Output order is not guaranteed to match input order, so join results on recordId.15 As a sizing example: 200,000 documents a month at 4,000 input and 300 output tokens on Opus 5 is 800M x $5 + 60M x $25 = $5,500 on demand, or $2,750 in batch.211
Flex and Priority
For models that support them, Bedrock’s service tiers are set per request with a service_tier field: flex trades latency for a 50% discount on Standard pricing, priority buys faster responses at a 75% premium, and omitting the field (or default) means Standard.161 On-demand quota is shared across the three, and CloudWatch reports a ResolvedServiceTier dimension showing which tier actually served each request.16 Flex is a good fit for agent sub-tasks and evaluations that need an answer in minutes rather than seconds, where batch’s file-based workflow is awkward.
Step 6: commit to capacity last
Committed capacity is cheaper per token only when you keep it busy. Bedrock now has two forms:
- Reserved tier. You reserve input and output tokens-per-minute for one or three months, with minimums of 100,000 input and 10,000 output TPM. Overflow spills to Standard automatically, AWS targets 99.5% uptime, and billing continues until the reservation is deleted. When sizing it, add
CacheWriteInputTokensto input tokens, because both count.16 Access is through your AWS account team. - Provisioned Throughput. Hourly billing per model unit with no commitment, one month or six months; longer terms get a lower hourly rate. It is mandatory for serving customised models.17 Batch inference does not run on provisioned models.13
Our rule is to commit only to the floor. Measure the token rate you sustain for most of the day across a few weeks, commit to that, and let everything above it run on Standard. Then check the simple inequality before signing: the monthly commitment must be lower than what the same traffic would cost on demand after caching and routing. Teams that commit first lock in the unoptimised token volume and pay for it for the rest of the term.
What we don’t bother optimising
- Temperature. It has no effect on price. We mention it because we keep meeting teams who believe otherwise.
- Aggressive prompt compression. Shaving 10% off a system prompt that is already cached saves almost nothing and makes the prompt harder to maintain. Spend the effort on retrieval size instead.
- Switching providers for a small rate cut. The migration, re-evaluation and operational risk usually cost more than the saving. Revisit when a new model tier changes the economics, not when a rate moves a few percent.
The order we work in
When we’re asked to fix a Bedrock bill, the sequence is nearly always the same. The first three steps are code changes you can reverse in an afternoon; the last two depend on model support and a measured traffic floor.
Playbook
The order we work in
Steps 1–3 are code changes you can reverse. Steps 4–5 depend on model support and a measured traffic floor.
Checklist
- Cost Explorer views include the model provider’s Marketplace line, not just “Amazon Bedrock”.
- Every call carries an inference profile or request metadata that maps to a feature and team.
- Invocation logging is on in every region you call, so metadata is retained.
- An alarm watches hourly output tokens and throttles.
- Static content sits above a cache checkpoint; cache writes fall after warm-up.
- Each route has an explicit model, effort level and
max_tokens. - Token budgets were measured on the model you actually run (tokenizers changed in 4.7).
- Haiku 5.5 routes stay under the 100,000-token prompt threshold, or you priced the long-context rate.
- Latency-tolerant jobs run in batch or Flex where the model supports it.
- Global versus regional endpoints is a deliberate residency decision, priced at the 10% difference.
- Committed capacity covers the measured floor only, and is re-checked quarterly.
ForthClover runs this kind of cost review on production Bedrock systems, usually alongside the evaluation work that makes routing safe. If you want a second pair of eyes on yours, get in touch.
Sources
- AWS, Amazon Bedrock pricing — aws.amazon.com/bedrock/pricing/
- Anthropic, Claude API documentation — Pricing (model, caching, batch and residency rates) — platform.claude.com/docs/en/about-claude/pricing
- Anthropic, “Claude in Amazon Bedrock” (endpoints, regions, quotas, feature support) — platform.claude.com/docs/en/build-with-claude/claude-in-amazon-bedrock
- AWS, Amazon Bedrock model card — Claude Sonnet 5.5 — docs.aws.amazon.com/bedrock/latest/userguide/model-card-anthropic-claude-sonnet-5-5.html
- AWS, Amazon Bedrock model card — Claude Haiku 5.5 — docs.aws.amazon.com/bedrock/latest/userguide/model-card-anthropic-claude-haiku-5-5.html
- Anthropic, Claude API documentation — Extended thinking (thinking tokens, effort, caching) — platform.claude.com/docs/en/build-with-claude/extended-thinking
- AWS, “Monitor bedrock-runtime inference using CloudWatch metrics” — docs.aws.amazon.com/bedrock/latest/userguide/monitoring-runtime-metrics.html
- AWS, “Application inference profiles” (cost allocation) — docs.aws.amazon.com/bedrock/latest/userguide/cost-mgmt-application-inference-profiles.html
- AWS, “Per-request metadata tagging” — docs.aws.amazon.com/bedrock/latest/userguide/cost-mgmt-request-metadata.html
- AWS, “Prompt caching for faster model inference” — docs.aws.amazon.com/bedrock/latest/userguide/prompt-caching.html
- AWS, Amazon Bedrock model card — Claude Opus 5 — docs.aws.amazon.com/bedrock/latest/userguide/model-card-anthropic-claude-opus-5.html
- AWS, “Understanding intelligent prompt routing in Amazon Bedrock” — docs.aws.amazon.com/bedrock/latest/userguide/prompt-routing.html
- AWS, “Process multiple prompts with batch inference” — docs.aws.amazon.com/bedrock/latest/userguide/batch-inference.html
- AWS, “Supported Regions and models for batch inference” — docs.aws.amazon.com/bedrock/latest/userguide/batch-inference-supported.html
- AWS, “Format and upload your batch inference data” — docs.aws.amazon.com/bedrock/latest/userguide/batch-inference-data.html
- AWS, “Service tiers for optimizing performance and cost” — docs.aws.amazon.com/bedrock/latest/userguide/service-tiers-inference.html
- AWS, “Increase model invocation capacity with Provisioned Throughput in Amazon Bedrock” — docs.aws.amazon.com/bedrock/latest/userguide/prov-throughput.html
All sources were checked in October 2026. Worked-example figures are our own arithmetic on list prices and stated assumptions, not measurements from a client system.
