All 45 runtime parameters that govern the Translation Engine, and what each one actually decides — Bedrock token rates, token and duration estimation, spend controls, and customer pricing. Learn these and you can reprice or retune the whole service without touching a line of code.
Translation parameters control every cost, pricing, and operational aspect of the Translation Engine (TBTS). They are stored in the translation_parameters Aurora table — the authoritative source — and cached in Valkey as the tx:params hash for fast reads by ECS containers and Lambda workers.
translation_parameters, not application_parameters. This prevents a bad translation config change from affecting the LPO server, and vice versa.tx:params from Valkey on startup. Lambda workers load it on cold start.POST /admin/translate/params/reload flushes Valkey and reloads from Aurora immediately. All containers pick up changes on their next read.Important: The legacy Valkey keys translation:rate:{model}:input and translation:rate:{model}:output are superseded by tx:params. The app:config keys translation_markup_pct and translation_infra_per_pair are also superseded. All translation cost logic now reads exclusively from tx:params. The legacy keys are retained for backward compatibility only.
-- Aurora: authoritative source
SELECT key, value, description, category, updated_at, updated_by
FROM translation_parameters
ORDER BY category, key;
-- Valkey: fast cache (tx:params hash, 27-hour TTL)
HGETALL tx:params
-- Update a parameter (applies immediately to Aurora + Valkey + in-memory)
POST /admin/translate/params
{"key": "pricing.markup_pct", "value": "30", "updated_by": "cory"}
-- Force all containers to reload from Aurora
POST /admin/translate/params/reload
-- View parameters in the TBI Administration dashboard
Translation tab → Translation Parameters section
Every parameter accessor follows a three-level fallback to ensure the system never returns zero for a cost value:
tx:params hash — fast path, ~0.1ms, refreshed nightly by sync job (27-hour TTL)translation_parameters table — authoritative source, ~5ms, used when Valkey is unavailableThe Translation Engine tracks every token at the most granular level Bedrock reports. The ground-truth cost calculation for any translation job is:
BedrockCostForTokens — the single source of truth for all cost calculations:
cost = (uncached_input_tokens × input_rate_per_token)
+ (cached_tokens × cache_read_rate_per_token) ← 90% cheaper than input
+ (cache_write_tokens × cache_write_rate_per_token) ← one-time per cache population
+ (output_tokens × output_rate_per_token)
Where uncached_input = total_input - cached_tokens. This formula is used everywhere actual cost is recorded — finalize Lambda, SQS cost messages, Aurora bedrock_cost_usd column, and the daily spend counter in Valkey.
Here is the thing to understand before you read a single line of the formula below: customers pay a true flat 3.00 USD per document-language pair. For every model except Claude Opus 4.8, the cost-plus calculation below no longer runs at all — the flat 3.00 USD rate is applied directly, per pair. The formula survives for exactly one agent: Claude Opus 4.8, where cost-plus runs with 3.00 USD as a floor, so a large Opus document can price above it and is advertised as "From 3.00". So the formula is real, but only Opus ever exercises it; everything else is a flat rate.
That is a deliberate design choice worth appreciating rather than a rounding convenience. A cost-plus price on a small document produces a quote of a few cents, and a few cents cannot carry a Stripe fee, a confirmation email, and a support conversation. Pricing on the floor gives the customer something far more valuable than precision: a number they can predict before they ask. Nine documents into three languages is 27 pairs, so 81.00 USD, and they can work that out themselves without a quote call.
infra = InfraCostForJob(translatable_bytes_per_doc, num_languages) subtotal = total_bedrock_cost + infra service_fee = subtotal × (pricing.markup_pct / 100) total = subtotal + service_fee total_pairs = doc_count × language_count pair_floor = pricing.minimum_per_pair_usd × total_pairs final = max(total, pair_floor, pricing.minimum_quote_usd)
That formula now executes on a single path — Claude Opus 4.8
— and its last line is where the money is decided there: three candidates compete and the
largest wins, so the cost-based total takes the price only when it
beats the 3.00 USD per-pair floor. Opus 4.8 bills 5.50 USD per million
input tokens and 27.50 USD per million output tokens, the highest rates in the table and about
1.7 times Sonnet 4.6, so it is the one model whose token bill can climb past
the floor, on documents above about 200 KB. For every other agent there is no competition to resolve: the
price is 3.00 USD per pair, full stop.
What this looks like in the ledger. Measured across every recorded job, average Bedrock cost per pair by model: Sonnet 4.6 0.67 USD, Haiku 0.16 USD, DeepSeek V3 0.12 USD, Mistral Large 0.05 USD, Qwen3 235B 0.02 USD. Add infrastructure and a 30% markup and the highest of those is still comfortably under 1.00 USD, against a 3.00 USD floor. That gap is not a mistake to be tuned away — it is the margin that funds the mission, and it is why the price stays simple.
Two floors exist rather than one, and the distinction matters
when you are reading a quote. pricing.minimum_per_pair_usd scales
with the work — it is 3.00 USD multiplied by the pair count. pricing.minimum_quote_usd
is an absolute backstop on the whole quote, also 3.00 USD, which catches the smallest possible
job of one document into one language. On any job larger than a single pair, the per-pair floor
is the one doing the work.
Two optimization layers compound for internal document translation, and both act on the cost side rather than the price side — they widen the margin under the floor rather than changing what a customer pays:
| Optimization | Mechanism | Savings | Parameter |
|---|---|---|---|
| Delta processing | Skip pairs where the translation is already newer than the source | 70–90% reduction in work | Controlled by options.delta at job submission |
| Prompt caching | System prompt and protected terms are cached across calls | 90% off cached tokens | bedrock.*.cache_read_per_1m |
Batch inference used to be the third layer here and it is gone. Bedrock batch mode was permanently removed on June 20, 2026, along with the Standard delivery tier that depended on it. Every job now runs real-time in Express mode, which is the only delivery value the quote endpoint accepts — a request naming any other mode is rejected rather than silently downgraded. The lesson worth keeping is the one the removal teaches: batch traded a 50% token discount for a 12 to 24 hour SLA, and once the per-pair floor set the price, that discount stopped reaching the customer while the wait still did. Paying in latency for a saving nobody receives is a bad trade, so we stopped making it.
The actual per-token rates Amazon Bedrock charges us. Keep the distinction clear as you read: these are our costs, not what we charge customers. Customer pricing is the flat per-pair floor covered further down, and the gap between the two is the margin. Keys are named bedrock.<model>.realtime.<direction>_per_1m, with separate cache-read and cache-write keys for the Claude models that support prompt caching. Since October 2026 you no longer maintain these by hand: the nightly sync job reads them from the AWS Price List (us-east-2, the geographic rate our us. inference profiles are billed at) and writes any change here, holding a model's old values if its new ones look wrong.
Two multipliers are worth memorising because they drive every cost decision here. Prompt cache reads are 90% off on-demand input, which is why the system prompt and the protected-terms list are cached rather than resent. Cache writes are 1.25× on-demand, paid once when the cache is populated — a small premium that pays for itself immediately across a multi-language job.
The engine prices every job at the realtime rates, because Bedrock batch mode was permanently removed on June 20, 2026 and the quote endpoint accepts no other delivery mode. The nightly refresh also stores batch.* rates where AWS publishes them, so the data is there if that ever changes; nothing reads them today.
| Key | Default | Unit | Description |
|---|---|---|---|
bedrock.sonnet46.realtime.input_per_1m | 3.30 | USD / 1M tokens | Sonnet 4.6 input. The agent Auto uses for Amharic, Hausa, Mongolian, Pashto and Somali, and a customer's choice for nuance-heavy content. Before October 2026 this row held the global cross-Region rate (3.00 / 15.00); the refresh now stores the geographic rate we are actually billed, 10% higher. |
bedrock.sonnet46.realtime.output_per_1m | 16.50 | USD / 1M tokens | Sonnet 4.6 output. Output is 5× input on every model here, which is why estimation.output_input_ratio matters so much to a quote. |
bedrock.sonnet46.cache_read_per_1m | 0.33 | USD / 1M tokens | Sonnet 4.6 prompt cache read — 90% off input. Applied to the system prompt and protected-terms tokens on every cached request. |
bedrock.sonnet46.cache_write_per_1m | 4.125 | USD / 1M tokens | Sonnet 4.6 prompt cache write — 1.25× input, paid once when the cache is populated. |
bedrock.opus48.realtime.input_per_1m | 5.50 | USD / 1M tokens | Claude Opus 4.8 input, the Opus agent since October 2026, at about a third of the retired Opus 4 rate. Opus is the one model whose bill can climb past the flat per-pair floor. |
bedrock.opus48.realtime.output_per_1m | 27.50 | USD / 1M tokens | Claude Opus 4.8 output — the highest rate in the table. |
bedrock.opus48.cache_read_per_1m | 0.55 | USD / 1M tokens | Claude Opus 4.8 prompt cache read. |
bedrock.opus48.cache_write_per_1m | 6.875 | USD / 1M tokens | Claude Opus 4.8 prompt cache write, paid once per cache population. |
bedrock.opus5.* | stored only | USD / 1M tokens | A rate set the refresh fetches and stores so a later change of Opus model needs no new data. No agent is offered on it and nothing prices against it. |
bedrock.haiku55.realtime.input_per_1m | 0.11 | USD / 1M tokens | Claude Haiku 5.5 input, the fastest Claude agent and a customer's choice for high-volume work. |
bedrock.haiku55.realtime.output_per_1m | 0.55 | USD / 1M tokens | Claude Haiku 5.5 output. |
bedrock.haiku55.cache_read_per_1m | 0.011 | USD / 1M tokens | Claude Haiku 5.5 prompt cache read. |
bedrock.haiku55.cache_write_per_1m | 0.1375 | USD / 1M tokens | Claude Haiku 5.5 prompt cache write. |
bedrock.qwen3235b.realtime.input_per_1m | 0.22 | USD / 1M tokens | Qwen3 235B input — our standard: it translates our own library, and Auto picks it for every language it supports. It is also the least expensive model in the roster by a long way. |
bedrock.qwen3235b.realtime.output_per_1m | 0.88 | USD / 1M tokens | Qwen3 235B output. No prompt-caching keys exist for this model, so its cost is input plus output and nothing else. |
bedrock.mistrallarge.realtime.input_per_1m | 0.50 | USD / 1M tokens | Mistral Large input. |
bedrock.mistrallarge.realtime.output_per_1m | 1.50 | USD / 1M tokens | Mistral Large output. Note the unusually tight 3× input-to-output ratio, against 5× elsewhere. |
bedrock.deepseekv3.realtime.input_per_1m | 0.58 | USD / 1M tokens | DeepSeek V3 input. |
bedrock.deepseekv3.realtime.output_per_1m | 1.68 | USD / 1M tokens | DeepSeek V3 output. |
Only the three Claude agents carry cache keys — Sonnet 4.6, Opus 4.8 and Haiku 5.5. Qwen3 235B, Mistral Large and DeepSeek V3 are priced on input and output alone. That is not an omission in this table, it is the shape of what Bedrock offers, and it means the caching saving you can count on varies by which model a job routes to.
These ratios let the engine estimate a job's cost and duration before it runs, which is what makes a quote possible and a pre-flight spend check meaningful. They are not guesses — every one is derived from real Aurora translation_job_events data, and they get better the more jobs the system completes.
| Key | Default | Unit | Description |
|---|---|---|---|
estimation.tokens_per_byte | 0.64 | tokens / byte | Input tokens per translatable byte, and one of the more satisfying numbers in this system: it holds at 0.63–0.66 across every document type we have measured. That stability is what lets a byte count become a reliable cost estimate. Refresh it from the translation:actuals:{model} Valkey keys the nightly sync job writes. |
estimation.output_input_ratio | 0.76 | ratio | Output tokens divided by input tokens. Varies by document type: code-heavy docs ~0.46 (code passes through untranslated), prose-heavy docs ~1.01. The 0.76 average is a reasonable middle ground for mixed technical documentation. |
estimation.quote_padding_pct | 6 | percent | Padding applied to token estimates for customer quotes. A 6% buffer keeps quotes slightly conservative — actual cost is usually at or below the estimate. Absorbed by the markup buffer on prose-heavy documents. |
estimation.cache_hit_rate | 0.30 | fraction (0–1) | Expected fraction of input tokens served from the prompt cache. The system prompt plus the protected-terms list accounts for roughly 30% of total input tokens, and at 90% off that is a real saving on every single request. Refresh from the actual cache_hit_rate values in the translation:actuals:* Valkey keys. |
estimation.cached_system_tokens | 1200 | tokens | Approximate token count of the cacheable system prompt block (system instructions + protected terms list). This is the fixed overhead per request — identical for every doc/lang pair. Must be a multiple of 3 per Trinity Beast convention. |
How to keep these honest. The nightly sync job writes observed token ratios to Valkey keys such as translation:actuals:claude-sonnet-4.6. Review them in the TBI Administration dashboard under Translation → Token Usage and update the estimation parameters when the actuals have drifted. Use 5% as normal noise and 15% as the point where an update is warranted. This is the loop that keeps quotes accurate as the corpus and the model roster change, and it takes a couple of minutes.
Operational limits that prevent runaway Bedrock costs. The daily spend cap is a hard stop — no new jobs are accepted after it is reached. The token limit is a secondary guard that catches unusually large documents before they hit the dollar cap. For a customer, both caps (and the kill switch) are checked before the charge: accept answers 503 tbts_service_paused and nothing is charged or queued. The customer limits themselves (12 languages, 42 documents, 300 KB per document, 9 quotes per batch) are code constants in internal/txlimits, not parameters, so no row here can loosen them.
| Key | Default | Unit | Description |
|---|---|---|---|
controls.daily_spend_limit_usd | 600 | USD | Daily Bedrock spend cap. No new translation jobs are accepted after this limit is reached. Resets at midnight UTC. Must be a multiple of 3 (200×3). Tracked in Valkey key autoops:bedrock:spend:daily. |
controls.daily_token_limit | 51,000,000 | tokens | Daily combined token limit (input + output). Secondary guard — model-agnostic. Catches unusually large documents before they hit the dollar cap. 51M = 17M×3. Tracked in Valkey keys autoops:bedrock:tokens:input:daily and autoops:bedrock:tokens:output:daily. |
controls.max_docs_per_request | 42 | documents | A mirror of txlimits.MaxDocsPerQuote, set to '42' by the October 2026 migration and not read for enforcement. The enforced limit is the code constant: 42 documents for a customer quote and for POST /admin/translate alike. |
controls.max_active_jobs | 12 | jobs | Warning threshold for concurrent active translation jobs. Multiple of 3. At 12 or more the LPO adds a tx:warnings entry and still queues the job: it is advisory, not a hard stop. |
controls.max_queue_depth | 12 | jobs | Declared but not enforced: nothing reads this value, and accepted jobs queue without a cap. Kept for reference only. |
controls.customer_cancel_enabled | true | switch | Launch switch for POST /translate/cancel/{quote_id}. true lets customers cancel; anything else answers 404. |
controls.cost_per_chunk_floor | 0.03 | USD | Minimum cost-per-chunk floor used by the nightly sync job when calculating rolling averages. Prevents unrealistically low averages from skewing customer quotes during low-activity periods. |
controls.cost_per_chunk_ceiling | 0.09 | USD | Maximum cost-per-chunk ceiling used by the nightly sync job. Caps runaway averages caused by anomalous jobs (e.g., a single very large document). |
These parameters control what customers pay for TBTS translations. They are applied at quote time by CustomerPriceForPair() in the translation engine. Changing these takes effect immediately — no deploy needed.
| Key | Default | Unit | Description |
|---|---|---|---|
pricing.infra_per_pair_usd | 0.003 | USD / pair | Infrastructure cost per language pair. Covers ECS task time, S3 storage, CloudFront invalidation, Lambda invocations, and Step Function state transitions. Added to Bedrock cost before markup is applied. |
pricing.markup_pct | 30 | percent | Service fee markup applied to (Bedrock cost + infra cost). Covers support, margin, and operational overhead. Applied at quote time and in all customer-facing emails. This is the primary lever for adjusting customer pricing — change it here and it takes effect everywhere immediately. |
pricing.minimum_per_pair_usd | 3.00 | USD / pair | The number that actually sets the price. Multiplied by the total pair count to form a floor, and because the cost-based calculation lands under it for every model except Opus on large documents, this is what a customer pays. Change this one value and you have repriced the entire service. |
pricing.minimum_quote_usd | 3.00 | USD | Absolute floor on the whole quote, applied last. Where the per-pair floor scales with the work, this one catches the smallest job there is — one document into one language. It exists so no quote is ever worth less than the Stripe fee, email, and support it costs to fulfil. |
pricing.ecs_cost_per_minute | 0.00112 | USD / minute | Fargate task cost per minute, used to price the real compute time a job occupies. This is what makes the estimate duration-aware rather than a flat per-pair guess. |
pricing.infra_rate_per_second | 0.0003 | USD / second | Per-second infrastructure rate applied across job duration, alongside the ECS minute rate. |
pricing.fixed_job_overhead | 0.012 | USD / job | One-time overhead charged per job rather than per pair — queue handling, orchestration, and the finalize step, all of which happen once no matter how many pairs a job carries. |
Three parameters that used to live in this table are gone, and it is worth
knowing why rather than wondering where they went.
pricing.standard_tier_discount_pct and
pricing.express_tier_premium_pct priced the two delivery tiers,
and pricing.infra_markup_pct marked up the batch pipeline's
rolling cost averages. All three depended on Bedrock batch mode, which was permanently
removed on June 20, 2026. One delivery mode means nothing left to discount or add a premium
against, so keeping the levers would have meant three knobs that turn and change nothing —
the most expensive kind of documentation, because a reader trusts it.
The Opus-only price formula — everything else is a flat 3.00 USD/pair: this cost-plus calculation runs for a single agent, Claude Opus 4.8. Every other model skips it entirely and is priced at the flat 3.00 USD per-pair rate directly. For Opus, the floor is still the price on small documents and the formula only wins on large ones.
infra = InfraCostForJob(translatable_bytes_per_doc, num_languages) subtotal = total_bedrock_cost + infra service_fee = subtotal × (pricing.markup_pct / 100) total = subtotal + service_fee total_pairs = doc_count × language_count pair_floor = pricing.minimum_per_pair_usd × total_pairs final = max(total, pair_floor, pricing.minimum_quote_usd) ← Opus path only
The canonical implementation is
Params.CustomerPriceForJob, and its own comment states the
outcome plainly: a 3.00 USD per-pair floor, which only
Opus on large documents exceeds. There is one older function,
CustomerPriceForPair, kept solely so previously stored quote
records still resolve — it is deprecated and is not what prices a new job.
These six rows decide how a pair that could not be delivered becomes money back in the customer's account. The design keeps the customer in charge: a failed pair first gets one free retry, and only what is still undelivered is refunded, either when the customer chooses "Refund instead" or automatically once the window closes. The whole machine shipped switched off and was turned on on 2026-10-11, in one statement that also set refund.failed_pair_since, so no quote accepted before that moment is ever refunded by surprise. The free retry and the refund for a paid job that never started work from deploy, whatever these rows say.
| Key | Default | Unit | Description |
|---|---|---|---|
refund.failed_pair_enabled | false | switch | The launch switch for the automatic failed-pair refund, the "Refund instead" button and its API. Off until the live test passes. |
refund.failed_pair_window_hours | 72 | hours | How long a failed pair waits for the customer's free retry before it is refunded automatically. |
refund.failed_pair_max_attempts | 3 | attempts | Stripe attempts per quote before the refund is marked error for an operator. |
refund.sweep_interval_minutes | 15 | minutes | How often the refund sweeper ticks. A multiple of 3, clamped to 3–60, and re-read on every tick, so a change needs no restart. |
refund.failed_pair_since | (empty) | RFC 3339 UTC | Only quotes accepted after this moment enter the machine. Empty means off. Set in the same statement that turns the flag on. |
refund.start_failure_since | (empty) | RFC 3339 UTC | The start-failure catch-up covers quotes accepted after this moment. Stamped once by migration 03b at deploy, after every LPO task runs the new code. |
The easiest way to manage translation parameters is through the TBI Administration dashboard. Navigate to the Translation tab and scroll to the Translation Parameters section (admin only).
tx:params Valkey cache and reloads from Aurora. All ECS containers pick up changes on their next 5-minute poll cycle.-- List all parameters
GET /admin/translate/params
-- Filter by category
GET /admin/translate/params?category=customer_pricing
-- Update a parameter (applies immediately to Aurora + Valkey + in-memory)
POST /admin/translate/params
{"key": "pricing.markup_pct", "value": "30", "updated_by": "cory"}
-- Force all containers to reload from Aurora
POST /admin/translate/params/reload
-- View all parameters SELECT key, value, category, updated_at, updated_by FROM translation_parameters ORDER BY category, key; -- Update a parameter UPDATE translation_parameters SET value = '35', updated_at = NOW(), updated_by = 'cory' WHERE key = 'pricing.markup_pct'; -- After a direct SQL update, reload Valkey via the API: POST /admin/translate/params/reload
Important: Direct SQL updates to Aurora do NOT automatically update Valkey or in-memory values on running containers. Always follow a direct SQL update with a POST /admin/translate/params/reload call to ensure all containers pick up the change within their next 5-minute poll cycle.
The nightly sync job (trinity-beast-sync-job, BeastReconciler, runs at 1 AM EDT) performs four translation-related tasks, and the first one is new in October 2026:
Before anything is copied, the job asks AWS what each model costs today. It calls the public Price List (pricing:GetProducts, served from us-east-1 and filtered to us-east-2, where our Bedrock traffic runs) for all seven rate keys, checks every value, and writes any change into the bedrock_pricing rows of Aurora. Step 1 then carries the fresh rates into tx:params in the same run, and a final check confirms Valkey holds exactly what Aurora holds.
It is careful in the way a price source has to be. Each model is all-or-nothing: a fetch error, a missing dimension, an unknown unit, a value outside 0.0001–500 USD per million tokens, or a change of more than 3× in one night keeps that model's stored rates and adds one line to a single ops alert. Nothing in it can stop the rest of the nightly job. For a deploy, SYNC_ONLY=bedrock-rates runs only the refresh, the copy and the check, so the day's spend and token guards are never reset mid-day.
Diagram 6.1: Nightly Bedrock Rate Refresh
flowchart LR
subgraph AWS["AWS Price List (us-east-1 endpoint)"]
PL["GetProducts
us-east-2 rates, 7 models"]
end
subgraph SYNC["Sync job (BeastReconciler, 1 AM nightly)"]
CHK{"Every value plausible?
unit known, 0.0001-500,
no jump over 3x"}
KEEP["Keep stored rates
for that model"]
ALERT["One ops alert
for the whole run"]
VER{"Aurora = tx:params?"}
end
subgraph DATA["Stores"]
AUR[("Aurora
translation_parameters
bedrock_pricing rows")]
VK[("Valkey
tx:params, 27 h TTL")]
end
LPO["LPO containers
quote and cost math"]
PL --> CHK
CHK -->|"yes: write changes"| AUR
CHK -->|"no"| KEEP
KEEP --> ALERT
AUR -->|"Step 1 copies the table"| VK
VK --> VER
VER -->|"no"| ALERT
VK -->|"read first"| LPO
AUR -.->|"fallback"| LPO
style AWS fill:#3b2a5c,stroke:#a78bfa,color:#ffffff
style SYNC fill:#1e3a5f,stroke:#60a5fa,color:#ffffff
style DATA fill:#14403a,stroke:#10b981,color:#ffffff
style PL fill:#2e1065,stroke:#a78bfa,color:#e2e8f0
style CHK fill:#422006,stroke:#fbbf24,color:#e2e8f0
style KEEP fill:#422006,stroke:#fbbf24,color:#e2e8f0
style ALERT fill:#7f1d1d,stroke:#fca5a5,color:#e2e8f0
style VER fill:#422006,stroke:#fbbf24,color:#e2e8f0
style AUR fill:#064e3b,stroke:#10b981,color:#e2e8f0
style VK fill:#064e3b,stroke:#10b981,color:#e2e8f0
style LPO fill:#334155,stroke:#94a3b8,color:#e2e8f0
linkStyle 0,1,4 stroke:#10b981,stroke-width:2px
linkStyle 2,3,6 stroke:#fbbf24,stroke-width:2px
linkStyle 5 stroke:#60a5fa,stroke-width:2px
linkStyle 7,8 stroke:#94a3b8,stroke-width:2px
Reads all rows from the translation_parameters Aurora table and writes them to the tx:params Valkey hash with a 27-hour TTL, so the hash always outlives the next run. This ensures all containers have fresh parameter values, including the rates refreshed in step 0, even if the Valkey cache expired overnight.
Queries translation_job_events for the last 7 days, grouped by model and execution mode. Calculates the average cost-per-chunk for each combination and writes to Valkey:
| Valkey Key | Description |
|---|---|
translation:cost_per_chunk:{model} | Real-time path (backward compatible) |
translation:cost_per_chunk:{model}:batch | Batch inference path |
translation:cost_per_chunk:{model}:batch_cached | Batch + prompt caching path |
translation:cost_per_chunk | Blended average (all models, backward compat) |
The floor and ceiling from controls.cost_per_chunk_floor and controls.cost_per_chunk_ceiling are applied to these averages before they are written to Valkey. Note that the batch and batch_cached variants above are historical: batch inference was removed on June 20, 2026, so those keys are retained for backward compatibility and are no longer written with fresh data. There is also no longer an infrastructure markup applied at this stage — pricing.infra_markup_pct existed to mark up the batch pipeline's averages and went away with it.
Writes actual token ratios from real jobs to Valkey for operator review:
-- Key pattern: translation:actuals:{model}
-- Example: translation:actuals:claude-sonnet-4.6
Fields:
avg_input_tokens — average input tokens per pair
avg_output_tokens — average output tokens per pair
avg_cached_tokens — average cached tokens per pair
output_input_ratio — derived: avg_output / avg_input
cache_hit_rate — derived: avg_cached / avg_input
pair_count — number of pairs in the 7-day window
updated_at — when this was last calculated
Review these periodically and update estimation.output_input_ratio and estimation.cache_hit_rate in translation_parameters when the actuals have drifted from the stored defaults. This is the feedback loop that keeps every future quote grounded in what the engine really did rather than in what it was once assumed to do.
The 46 parameters read from the live translation_parameters table on 2026-10-10, plus the six refund rows and the controls.max_docs_per_request update of the October 2026 migration, and the rate rows the nightly refresh adds for the new Claude agents, sorted by category and key. Read the live table with GET /admin/translate/params for today's exact values and count.
| Key | Category | Default | Description |
|---|---|---|---|
bedrock.deepseekv3.realtime.input_per_1m | bedrock_pricing | 0.58 | DeepSeek V3 input (USD/1M tokens) |
bedrock.deepseekv3.realtime.output_per_1m | bedrock_pricing | 1.68 | DeepSeek V3 output (USD/1M tokens) |
bedrock.mistrallarge.realtime.input_per_1m | bedrock_pricing | 0.50 | Mistral Large input (USD/1M tokens) |
bedrock.mistrallarge.realtime.output_per_1m | bedrock_pricing | 1.50 | Mistral Large output (USD/1M tokens) |
bedrock.qwen3235b.realtime.input_per_1m | bedrock_pricing | 0.22 | Qwen3 235B input (USD/1M tokens) |
bedrock.qwen3235b.realtime.output_per_1m | bedrock_pricing | 0.88 | Qwen3 235B output (USD/1M tokens) |
bedrock.sonnet46.cache_read_per_1m | bedrock_pricing | 0.33 | Sonnet 4.6 prompt cache read (USD/1M tokens) |
bedrock.sonnet46.cache_write_per_1m | bedrock_pricing | 4.125 | Sonnet 4.6 prompt cache write (USD/1M tokens) |
bedrock.sonnet46.realtime.input_per_1m | bedrock_pricing | 3.30 | Sonnet 4.6 input (USD/1M tokens) |
bedrock.sonnet46.realtime.output_per_1m | bedrock_pricing | 16.50 | Sonnet 4.6 output (USD/1M tokens) |
bedrock.haiku55.* | bedrock_pricing | 0.11 / 0.55 / 0.011 / 0.1375 | Claude Haiku 5.5: realtime input and output, cache read and write (USD/1M tokens) |
bedrock.opus48.* | bedrock_pricing | 5.50 / 27.50 / 0.55 / 6.875 | Claude Opus 4.8, the live Opus agent: realtime input and output, cache read and write (USD/1M tokens) |
bedrock.opus5.* | bedrock_pricing | stored only | Rate set kept for a later change of Opus model; no agent is offered on it (USD/1M tokens) |
bedrock.{sonnet46,qwen3235b,deepseekv3,mistrallarge}.batch.* | bedrock_pricing | sonnet46 1.65 / 8.25 · qwen3235b 0.11 / 0.44 · deepseekv3 0.29 / 0.84 · mistrallarge 0.25 / 0.75 | Batch input and output rates, stored where AWS publishes them; nothing reads them while every job runs in real time (USD/1M tokens) |
estimation.cache_hit_rate | token_estimation | 0.30 | Expected fraction of input tokens served from cache |
estimation.cached_system_tokens | token_estimation | 1200 | Tokens in the cacheable system prompt block |
estimation.output_input_ratio | token_estimation | 0.76 | Output tokens divided by input tokens |
estimation.quote_padding_pct | token_estimation | 6 | Padding % applied to token estimates for quotes |
estimation.seconds_per_byte | token_estimation | 0.0014 | Seconds of processing per translatable byte |
estimation.speed_factor.claude-sonnet-4.6 | token_estimation | 1.0 | Duration multiplier for claude-sonnet-4.6 |
estimation.speed_factor.deepseek-v3 | token_estimation | 0.7 | Duration multiplier for deepseek-v3 |
estimation.speed_factor.mistral-large | token_estimation | 0.6 | Duration multiplier for mistral-large |
estimation.speed_factor.qwen3-235b | token_estimation | 0.6 | Duration multiplier for qwen3-235b |
estimation.startup_seconds | token_estimation | 10 | Fixed job startup time before the first pair moves |
estimation.tokens_per_byte | token_estimation | 0.64 | Input tokens per translatable byte |
controls.cost_per_chunk_ceiling | cost_controls | 0.09 | Upper bound applied to rolling cost-per-chunk averages |
controls.cost_per_chunk_floor | cost_controls | 0.03 | Lower bound applied to rolling cost-per-chunk averages |
controls.daily_spend_limit_usd | cost_controls | 600 | Hard daily Bedrock spend cap — no new jobs accepted past it |
controls.daily_token_limit | cost_controls | 51000000 | Secondary daily token guard, catches oversized documents early |
controls.max_active_jobs | cost_controls | 12 | Warning threshold for jobs running concurrently (advisory; jobs still queue) |
controls.max_docs_per_request | cost_controls | 42 | Mirror of txlimits.MaxDocsPerQuote; not read for enforcement |
controls.max_queue_depth | cost_controls | 12 | Declared, not enforced: accepted jobs queue without a cap |
controls.customer_cancel_enabled | controls | true | Launch switch for customer cancel (POST /translate/cancel/{quote_id}) |
pricing.ecs_cost_per_minute | customer_pricing | 0.00112 | Fargate task cost per minute (USD) |
pricing.fixed_job_overhead | customer_pricing | 0.012 | One-time per-job overhead (USD) |
pricing.infra_per_pair_usd | customer_pricing | 0.003 | Infrastructure cost per language pair (USD) |
pricing.infra_rate_per_second | customer_pricing | 0.0003 | Per-second infrastructure rate across job duration (USD) |
pricing.markup_pct | customer_pricing | 30 | Service fee markup % applied to cost |
pricing.minimum_per_pair_usd | customer_pricing | 3.00 | The flat per-pair price customers actually pay (USD) |
pricing.minimum_quote_usd | customer_pricing | 3.00 | Absolute floor on the whole quote (USD) |
refund.failed_pair_enabled | refund | false | Launch switch for the automatic failed-pair refund |
refund.failed_pair_max_attempts | refund | 3 | Stripe attempts before the refund is marked error |
refund.failed_pair_since | refund | (empty) | Only quotes accepted after it enter the machine; empty = off |
refund.failed_pair_window_hours | refund | 72 | Hours a failed pair waits for the free retry |
refund.start_failure_since | refund | (empty) | Start-failure catch-up horizon; stamped by migration 03b |
refund.sweep_interval_minutes | refund | 15 | Refund sweeper tick (multiple of 3, clamped 3–60) |