Technical Documents Translated Perfectly — Code, Diagrams & All
"We use Amazon Bedrock to do what generic translation services can't."
Technical documentation is hard to translate. Generic translation services — including AWS Translate — don't understand the boundary between human language and machine language. They translate code blocks, corrupt variable names, localize version numbers, and hallucinate brand names.
We learned this the hard way. AWS Translate cost us over $800 in worthless translations before we caught it corrupting technical content across 11 languages. Silent failures. No warnings. No way to know without reading every translated document.
Real failure modes we caught:
function getName() → función obtenerNombre() (code no longer executes)PostgreSQL 17.7 → PostgreSQL (version number dropped)32 GB → 32 Go (unit localized in French)So we built our own translation engine. It uses Amazon Bedrock with sentinel preprocessing and multi-layer validation. You choose the AI agent — from fast and affordable to the highest quality available. The agent never sees protected content — it can't corrupt what it never touches. Every translation is validated before it ships.
Seven AI agents. Same protection. Your choice.
Every translation job lets you pick the agent that fits your needs. The engine is completely agent-agnostic — any model accessible through Amazon Bedrock can serve as a translation agent. We selected these six based on quality, regional availability across our failover chain (us-east-2, us-east-1, us-west-2), and distinct cost/quality tradeoffs.
Default agent: If no agent is specified in the request, the engine uses Claude Sonnet 4.6 — the balanced choice that handles all languages and document types well. You only need to specify an agent if you want to override this default.
| Agent | Tier | Speed | Strengths | Express/Pair |
|---|---|---|---|---|
| Qwen3 235B | 💰 Value | Fast | Best price-to-quality ratio. Excellent for CJK, South Asian scripts, and high-volume batches. 235B MoE with 22B active — fast and remarkably capable. | ~$0.04 |
| Mistral Large 3 | 💰 Value | Fast | European language specialist. Native-level French, German, Spanish, Italian, Portuguese — including idiomatic expressions and formal registers. | ~$0.06 |
| DeepSeek V3 | 💰 Value | Fast | Complex reasoning at budget prices. Excels with technical docs, API references, and scientific content. 671B MoE architecture. | ~$0.07 |
| Claude Haiku 3.5 | ⚡ Standard | Fastest | Fastest turnaround in the Anthropic family. Excellent instruction-following for code/structure preservation. Latin-script languages. | ~$0.13 |
| Claude Sonnet 4.6 DEFAULT | 🏆 Premium | Moderate | Balanced quality across all languages. Deep linguistic understanding for complex scripts. Our default for a reason. | ~$0.44 |
| Claude Opus 4 | 👑 Elite | Thorough | Maximum fidelity. Legal, medical, compliance. Every word weighed, every nuance preserved. Complex grammar (Finnish, Hungarian, Turkish). | ~$2.11 |
All six agents share the same protection: Sentinel preprocessing extracts code blocks, brand terms, version numbers, and technical identifiers before the agent sees your document. The validation pipeline checks every translation regardless of which agent produced it. The difference is the depth of linguistic reasoning and the speed/cost tradeoff — not the safety of your content.
AI translation that understands the difference between human language and machine language.
Your code blocks stay code. Your version numbers stay exact. Your brand names stay yours. Validated before delivery — not after you find the bug in production.
Want to see the quality? You're looking at it.
This entire website — cpmp-site.org — is available in 12 languages. Every page, every document, every piece of technical documentation was translated by the same engine we're offering you. That's 440 document-language pairs in production.
Switch languages in the header. Read the Document Library in Japanese. Check the API Reference in German. Browse the Infrastructure Specification in Arabic (RTL). Code blocks intact. Version numbers exact. Brand names preserved.
This isn't a demo. This is production proof at scale.
| Document Type | Supported | Notes |
|---|---|---|
| HTML documentation | ✅ Yes | Full support including embedded code, diagrams, tables |
| Markdown files | 🔜 Planned | Phase 2 — convert to HTML, translate, convert back |
| Plain text | ✅ Yes | Wrapped in minimal HTML for processing |
| JSON (i18n bundles) | ✅ Yes | Key-value translation with key preservation and inline HTML protection (links, styled elements) |
| ❌ No | Not planned — extract to HTML first |
Supported languages (300+):
The translation engine supports any language that Claude can translate — over 300 languages and dialects. The table below shows our validated tier (languages tested in production with full sentinel and validator coverage). Any other language Claude supports can be requested — it will use the same engine with default settings.
| Code | Language | Script | Direction | Region |
|---|---|---|---|---|
| Western European | ||||
es | Spanish | Latin | LTR | Spain, Latin America |
pt | Portuguese | Latin | LTR | Portugal, Brazil |
fr | French | Latin | LTR | France, Canada, Africa |
de | German | Latin | LTR | Germany, Austria, Switzerland |
it | Italian | Latin | LTR | Italy, Switzerland |
nl | Dutch | Latin | LTR | Netherlands, Belgium |
| Nordic & Eastern European | ||||
sv | Swedish | Latin | LTR | Sweden, Finland |
pl | Polish | Latin | LTR | Poland |
ru | Russian | Cyrillic | LTR | Russia, CIS |
tr | Turkish | Latin | LTR | Turkey |
| East Asian | ||||
ja | Japanese | Kanji/Kana | LTR | Japan |
zh | Chinese (Simplified) | Hanzi | LTR | China, Singapore |
ko | Korean | Hangul | LTR | South Korea |
| South & Southeast Asian | ||||
hi | Hindi | Devanagari | LTR | India |
pa | Punjabi | Gurmukhi | LTR | India, Pakistan |
th | Thai | Thai | LTR | Thailand |
vi | Vietnamese | Latin | LTR | Vietnam |
id | Indonesian | Latin | LTR | Indonesia |
| Middle Eastern (RTL) | ||||
ar | Arabic | Arabic | RTL | Middle East, North Africa |
ur | Urdu | Nastaliq | RTL | Pakistan, India |
300+ languages. Day one. No "coming soon." If Claude can translate it, we offer it. The 21 validated languages above have production-tested sentinel configurations and per-language chunk tuning. All other languages use intelligent defaults and the same validation pipeline.
Any-to-any translation: Source language is auto-detected — submit a Japanese document and translate it to Spanish without specifying the source. No pivot through English. The engine detects the source language in <10ms using Unicode script analysis and word frequency heuristics. Or specify source_lang explicitly if you prefer.
Simple, transparent, usage-based pricing. No monthly fees. No commitments. Pay only for what you translate — priced per token, per language.
Cost is determined by the actual token usage of your document's translatable content. Code blocks, diagrams, and protected elements are excluded from the token count — you only pay for what the AI agent actually translates. A 100 KB document that's 60% code blocks costs far less than a 100 KB document that's all prose.
Why token-based pricing is fairer: Token pricing directly reflects the work the AI performs. Documents with large code blocks, Mermaid diagrams, or technical identifiers have less translatable content — and cost proportionally less. You pay for linguistic reasoning, not for content the engine skips over.
| Agent | Tier | Input/1M | Output/1M | 50KB Doc (Express) | 50KB Doc (Batch) |
|---|---|---|---|---|---|
| Qwen3 235B | 💰 Value | $0.22 | $0.88 | ~$0.04 | ~$0.02 |
| Mistral Large 3 | 💰 Value | $0.50 | $1.50 | ~$0.06 | ~$0.03 |
| DeepSeek V3 | 💰 Value | $0.58 | $1.68 | ~$0.07 | ~$0.04 |
| Claude Haiku 3.5 | ⚡ Standard | $0.80 | $4.00 | ~$0.13 | ~$0.07 |
| Claude Sonnet 4.6 (default) | 🏆 Premium | $3.00 | $15.00 | ~$0.44 | ~$0.31 |
| Claude Opus 4 | 👑 Elite | $15.00 | $75.00 | ~$2.11 | ~$1.48 |
Rates are stored in Aurora (translation_parameters) and cached in Valkey. The GET /translate/models endpoint returns input_rate_per_1m, output_rate_per_1m, speed_factor, and estimated_cost_per_pair for each agent — use these to build real-time cost estimates in your integration.
$3.00 minimum per translated document: Every translated document has a floor price of $3.00, regardless of size or agent. The estimates above show the underlying AI cost — when any value falls below $3.00, your quote reflects $3.00 for that translation. Larger documents naturally exceed this floor and are priced at their actual calculated cost. Your quote always shows the exact price before you approve.
Cost estimation before you commit: When you request a quote, the response includes estimated token counts, processing duration, and total cost based on document analysis. You see exactly what you'll pay — broken down into Bedrock AI cost, infrastructure cost (duration-based), and service fee — before translation begins. The 30% service fee funds the infrastructure and the mission.
Agent-agnostic architecture: The translation engine treats AI models as interchangeable agents. Any model accessible through Amazon Bedrock's invoke_model API — whether Anthropic, Qwen, Mistral, DeepSeek, Amazon, or Meta — can serve as a translation agent. The engine auto-detects the provider's request/response format. As new models become available on Bedrock, we add them with zero code changes — just a database entry.
Volume pricing is available for high-usage customers. Contact us for custom rates if you're translating more than 1,000 chunks per month.
How we compare to alternatives for a typical 50 KB technical document translated into 11 languages (Sonnet agent, ~6 chunks):
| Service | Cost | Quality | Turnaround |
|---|---|---|---|
| Trinity Beast Translation (Sonnet) | ~$2.82 | Validated, code-safe | ~60 seconds |
| AWS Translate | ~$1.50 | Broken for technical docs | ~30 seconds |
| Google Cloud Translation | ~$1.80 | Similar issues to AWS | ~30 seconds |
| DeepL API | ~$2.20 | Better prose, still corrupts code | ~45 seconds |
| Human translation (budget) | $2,000–4,000 | Variable quality | 2–3 weeks |
| Human translation (premium) | $8,000–12,000 | High quality | 4–6 weeks |
The value proposition: We cost slightly more than generic machine translation, but we actually work for technical content. You're not paying for translation — you're paying for translation that doesn't break your documentation. Code blocks intact. Version numbers exact. Brand names preserved. Validated before delivery.
Each quote and acceptance has a clear ceiling. Need more? Submit additional quotes — there is no limit on how many quotes you can create.
| Limit | Value | What It Means |
|---|---|---|
| Documents per quote | 60 | Maximum HTML source documents in a single quote request. |
| Document size | 500 KB | Maximum HTML source size per document. Larger documents should be split. |
| Languages per quote | 11 | Up to 11 target languages per quote. The engine scales one container per language for maximum parallelism. |
| Quotes per acceptance | 9 | A single batch acceptance can process up to 9 quotes — one consolidated Stripe charge, one consolidated email receipt. |
| Batch threshold | 100+ translated documents | Orders producing 100 or more translated documents (e.g., 10 documents × 10 languages = 100) automatically qualify for Batch pricing — 30% off, 12–24h delivery. |
| Minimum per translation | $3.00 | Every translated document has a floor price of $3.00, regardless of size or agent. Larger documents that exceed this floor are priced at their actual calculated cost. |
| Active jobs | 3 | The engine processes 3 jobs concurrently. Additional accepted quotes queue automatically and start as slots free up. |
| Queue depth | 12 | Maximum jobs waiting behind the active 3. Beyond this, the engine returns a temporary back-pressure response — try again in a few minutes. |
| Daily spend cap | $600 | Engine-wide cost protection. Jobs are deferred when the cap is reached, resuming the next day. |
The math: A single acceptance can process up to 9 quotes of 60 documents each — 540 documents per acceptance, each translated into up to 11 target languages. Orders producing 100 or more translated documents (for example, 10 documents into 10 languages) automatically receive Batch pricing — 30% off, delivered within 12–24 hours. These ceilings are sized to keep quality consistent and delivery fast; they will scale up as the service registers with OpenAPI directories and we expand capacity.
Email policy: One email per accepted batch — never one per quote when batched. Customers are not flooded with separate confirmations for each quote in a multi-quote acceptance. The receipt summarizes every job in the batch with cost-by-language details.
All API requests require authentication via API key. Include your key in the X-API-Key header:
curl -H "X-API-Key: your-api-key-here" \
https://api.cpmp-site.org/translate/languages
API keys are managed through your Trinity Beast Account Dashboard. Create an account at cpmp-site.org/dashboard — translation-only customers are first-class citizens. If your email is also tied to a Price API subscription, you'll see those options too. The dashboard adapts to what you have.
Every response — success or error — follows the Unified Messaging Envelope format. All 12 fields are always present. No exceptions.
{
"status": "✅ [LPO] [us-east-2] [BeastMain] [/translate] [202]",
"status_code": 202,
"endpoint": "/translate",
"cluster_node": "BeastMain",
"region": "us-east-2",
"language": "en",
"api_key_id": "ak_demo123",
"ip_address": "203.0.113.42",
"agent_profile_arn": "arn:tbi:us-east-2:211998422884:agent-profile/tbi-dashboard/v1",
"timestamp": "2026-05-18T22:30:00Z",
"data": { ... },
"error": ""
}
The language field reflects the customer's api_lang preference (set in Account Dashboard). Error messages are translated into that language. The envelope metadata (brackets, identifiers) stays English always.
Transparency: Every response tells you which container handled it (cluster_node), which region (region), and exactly when (timestamp). You always know where your request went and when it was processed.
POST /translate
{
"source_url": "https://example.com/docs/api-reference.html",
"source_lang": "auto",
"target_langs": ["es", "ja", "zh"],
"agent": "claude-sonnet-4.6",
"protected_terms": ["MyProduct", "DataSync API"],
"callback_url": "https://example.com/webhook/translate-done",
"idempotency_key": "api-ref-2026-05"
}
| Field | Type | Required | Description |
|---|---|---|---|
source_url | string | Yes | URL to the source document (must be publicly accessible or a presigned S3 URL) |
source_lang | string | No | Source language code. Default: "auto" (auto-detected via Unicode script analysis + word frequency heuristics). Supports 300+ languages as source. |
target_langs | array | "all" | Yes | Array of language codes, or "all" for all 21 validated languages (excluding source language). Any other language code Claude supports can also be specified. |
agent | string | No | AI agent to use. Options: "claude-haiku-3.5" (Good), "claude-sonnet-4.6" (Better), "claude-opus-4" (Best). Default: "claude-sonnet-4.6" — used when this field is omitted. |
protected_terms | array | No | Additional brand names or terms that must not be translated (added to global list for this job only) |
callback_url | string | No | Webhook URL to POST when job completes |
idempotency_key | string | No | Prevents duplicate submissions (24h TTL) |
Any-to-any translation: The engine translates directly between any two supported languages — no pivot through English. A Spanish document can be translated directly to Japanese, Arabic, or any other language. Claude handles this natively. Source language is auto-detected when not specified, so customers don't need to declare it unless they want to override the detection.
Returns the standard UME envelope (see section 3.1) with this data payload:
"data": {
"job_id": "019e3d489ea4-15d9082769939137",
"job_status": "queued",
"source_doc": "api-reference.html",
"source_size_kb": 52,
"target_langs": ["es", "ja", "zh"],
"chunks": 6,
"estimated_cost": "$0.77",
"estimated_time_seconds": 180
}
The error field contains a localized message in the customer's api_lang:
"error": "🛑 [LPO] [us-east-2] [BeastMirror] [/translate] [400] El campo target_langs es obligatorio. Use \"all\" o un array como [\"es\", \"ja\"]"
GET /translate/{job_id}
"data": {
"job_id": "019e3d489ea4-15d9082769939137",
"job_status": "translating",
"source_doc": "api-reference.html",
"progress": {
"total_pairs": 3,
"completed": 1,
"failed": 0,
"in_progress": 2
},
"started_at": "2026-05-18T22:30:00Z",
"elapsed_seconds": 45
}
"data": {
"job_id": "019e3d489ea4-15d9082769939137",
"job_status": "succeeded",
"source_doc": "api-reference.html",
"completed_at": "2026-05-18T22:33:07Z",
"duration_seconds": 187,
"pairs_succeeded": 3,
"pairs_failed": 0,
"chunks_per_lang": 6,
"cost": "$0.77",
"outputs": {
"es": "https://api.cpmp-site.org/translate/download/019e3d489ea4/es/api-reference.html",
"ja": "https://api.cpmp-site.org/translate/download/019e3d489ea4/ja/api-reference.html",
"zh": "https://api.cpmp-site.org/translate/download/019e3d489ea4/zh/api-reference.html"
}
}
Job statuses: queued → translating → deploying → succeeded | partial | failed
DELETE /translate/{job_id}
Cancels a running job. Already-completed pairs are still available for download. You are not charged for cancelled pairs.
"data": {
"job_id": "019e3d489ea4-15d9082769939137",
"job_status": "cancelled",
"pairs_completed_before_cancel": 1,
"pairs_cancelled": 2,
"outputs": {
"es": "https://api.cpmp-site.org/translate/download/019e3d489ea4/es/api-reference.html"
}
}
Returns 409 Conflict if the job is already complete.
GET /translate/languages (public, no auth required)
Returns all supported languages with metadata:
"data": {
"language_count": 21,
"validated_languages": [
{"code": "es", "name": "Spanish", "native_name": "Español", "script": "Latin", "direction": "ltr"},
{"code": "ja", "name": "Japanese", "native_name": "日本語", "script": "Kanji/Kana", "direction": "ltr"},
{"code": "ar", "name": "Arabic", "native_name": "العربية", "script": "Arabic", "direction": "rtl"}
],
"additional_languages": "300+ supported via Claude — specify any valid language code",
"pricing": {
"model": "per-token",
"see_endpoint": "/translate/models"
},
"limits": {
"max_file_size_kb": 500,
"max_languages_per_quote": 12,
"max_quotes_per_acceptance": 9
}
}
The 21 validated languages have production-tested sentinel configurations and per-language chunk tuning. Any other language Claude supports can be requested using its ISO 639-1 code — the engine applies intelligent defaults.
GET /translate/models (public, no auth required)
Returns the available AI agents with token-based pricing, speed, and quality metadata:
"data": {
"models": [
{
"id": "claude-haiku-3.5",
"name": "Claude Haiku 3.5",
"tier": "Good",
"input_rate_per_1m": 1.0,
"output_rate_per_1m": 5.0,
"estimated_cost_per_pair": 0.03,
"speed": "fast",
"quality": "good",
"description": "Fast and affordable. Best for Latin-script languages and straightforward documents."
},
{
"id": "claude-sonnet-4.6",
"name": "Claude Sonnet 4.6",
"tier": "Better",
"input_rate_per_1m": 3.0,
"output_rate_per_1m": 15.0,
"estimated_cost_per_pair": 0.08,
"speed": "moderate",
"quality": "excellent",
"description": "Balanced speed and quality. Handles complex scripts and technical documents well. Default choice."
},
{
"id": "claude-opus-4",
"name": "Claude Opus 4",
"tier": "Best",
"input_rate_per_1m": 5.0,
"output_rate_per_1m": 25.0,
"estimated_cost_per_pair": 0.05,
"speed": "slow",
"quality": "exceptional",
"description": "Highest quality translations. Best for critical documents and complex grammar."
}
],
"default": "claude-sonnet-4.6",
"pricing_note": "Rates are per 1M tokens. estimated_cost_per_pair is for a typical 50KB document (one language). Actual cost depends on document size and content density."
}
Use the id value in the agent field when submitting a translation job. If omitted, the engine uses claude-sonnet-4.6 automatically.
GET /translate/usage
"data": {
"period": "2026-05",
"chunks_translated": 847,
"chunks_failed": 12,
"total_cost": "$36.17",
"our_cost": "$36.17",
"default_agent": "claude-sonnet-4.6",
"jobs_submitted": 18,
"jobs_succeeded": 15,
"jobs_partial": 2,
"jobs_failed": 1
}
Transparency: Notice the our_cost field. We show you what we paid Bedrock so you can see our margin. No hidden fees. No mystery pricing.
The translation service is built on the same infrastructure that powers our internal documentation translation. It's battle-tested on 440 document-language pairs.
Diagram 4.1: Translation Request Flow
sequenceDiagram
participant C as Customer
participant L as LPO Server (Go)
participant St as Stripe
participant Q as SQS Queue
participant W as BeastTranslate (Bedrock)
participant S3 as S3 (Output)
C->>L: POST /translate (API key auth)
L->>L: Validate + Analyze chunks
L-->>C: Quote (chunks, cost, languages)
C->>St: Pay quote (Stripe Checkout)
St-->>L: Payment confirmed (webhook)
L->>Q: Enqueue job
L-->>C: 202 Accepted (job_id)
Q->>W: Worker polls SQS directly
W->>W: Parallel language processing (×11)
W->>S3: Write translated docs
W->>L: Update Aurora (job record)
C->>L: GET /translate/:id
L-->>C: Status + Download URLs
Key components:
Every translated chunk passes through 5 validation checks before it's accepted:
| Validator | What It Checks | Failure Action |
|---|---|---|
| Protected Terms | Brand names, product names survive unchanged | Retry with stronger prompt |
| Version Numbers | 17.7, 4.6, v2.0 exact match | Retry with explicit instruction |
| URLs/IPs/ARNs | Technical identifiers unchanged | Retry |
| Tag Counts | HTML structure preserved — exact tag boundary scanning, no regex | Retry up to 3×, then fail with diagnostic detail |
| Protected Zones | Content inside translate="no" zones unchanged — character scanning with exact attribute matching | Retry up to 3×, then fail with zone content |
| Sentinel Restoration | All placeholder tokens restored correctly | Hard fail (data corruption) |
The key insight: Bedrock makes the right kind of mistakes — visible and recoverable. The validators catch issues before output ships. AWS Translate's failures were silent and structural — you only found them by reading every translated document.
No regex in tag validation: The tag count and protected zone validators use character scanning with exact boundary matching. We control these tags — we know a tag starts with < and ends with >. No partial matches, no false positives from text content that happens to contain tag-like strings.
Diagnostic depth: When a translation fails validation, the system captures the exact model output, the sentinel-processed input, and which specific items failed. This enables rapid root-cause analysis — we can see exactly what the model produced and why it didn't pass. No guessing, no "try again and hope."
Translated documents are stored in S3 under your customer folder:
s3://trinity-beast-translations/
{customer_id}/
{job_id}/
source.html (original, for reference)
es/document.html (Spanish output)
ja/document.html (Japanese output)
zh/document.html (Chinese output)
manifest.json (job metadata)
Retention: 30 days. Download URLs are presigned and valid for 72 hours (3 days). You can re-request download URLs anytime within the 30-day window.
Before any translation work begins, your document passes through a validation gate and structural analysis. This catches defects that would cause translation failures, and determines the optimal way to split your document for translation — rejecting early saves you money and prevents corrupted output.
If your document has repairable issues, they're fixed silently — you never know. If it has unrecoverable issues, you get an actionable rejection report with exact locations and fix suggestions. Zero Bedrock tokens burned on broken documents.
For documents without translate="no" annotations, enable the customer prescan to auto-detect protected zones:
{
"docs": ["my-technical-doc.html"],
"langs": ["es", "ja", "de"],
"options": {
"customer_prescan": true
}
}
The prescan identifies code blocks, inline code, technical identifiers, and brand terms in your document — then protects them automatically during translation. Your document doesn't need any special markup. The engine figures out what's code and what's prose.
When you request a translation quote, the engine performs a structural analysis of your document — automatically determining the optimal way to split it for translation. This is done on your behalf; no preparation is required from you.
What the analysis does:
Why this matters for cost:
Translation is priced per token — the translatable content in your document determines the token count. The analysis ensures your document is split at natural boundaries — never mid-paragraph, never mid-table, never mid-code-block. Smarter splitting means better context for the AI agent, which means higher quality output. A 100 KB document with large code blocks has far fewer translatable tokens than a 100 KB prose document, because the engine recognizes that protected content doesn't consume translation tokens.
The chunk plan is included in your quote response:
{
"quote_id": "019e4f...",
"document": "my-api-docs.html",
"analysis": {
"total_size_kb": 98.4,
"translatable_chunks": 6,
"protected_ratio": 0.42,
"estimated_translatable_content_kb": 57.1
},
"estimated_input_tokens": 36544,
"estimated_output_tokens": 27773,
"cost_per_language": 0.36,
"languages": 11,
"total_cost": 3.96
}
You see exactly how the engine will process your document before you commit. No surprises.
Source language is auto-detected — no need to specify it. The engine uses Unicode script analysis and word frequency heuristics to identify the source language (300+ languages supported, <10ms, no API calls). Submit a Japanese document and translate it to Spanish without specifying source_lang. No pivot through English required.
{
"docs": ["japanese-guide.html"],
"langs": ["es", "fr", "de"],
"source_lang": "auto"
}
We built this to be observable and controllable in ways that AWS Translate isn't. Every job, every pair, every event — tracked and actionable.
Poll GET /translate/{job_id} for live progress. You see exactly which languages are done, which are in progress, and which failed — not just "processing" for 10 minutes.
"data": {
"job_id": "019e3d489ea4-15d9082769939137",
"job_status": "translating",
"progress": {
"total_pairs": 11,
"completed": 7,
"failed": 0,
"in_progress": 4,
"details": {
"es": "succeeded", "pt": "succeeded", "fr": "succeeded",
"de": "succeeded", "ru": "succeeded", "ja": "succeeded",
"zh": "succeeded", "hi": "in_progress", "ar": "in_progress",
"ur": "in_progress", "it": "in_progress"
}
}
}
DELETE /translate/{job_id} cancels the job immediately. Already-completed pairs are still available. You're not charged for cancelled pairs. AWS Translate batch jobs? Once submitted, you wait.
POST /translate/{job_id}/retry — if a job completes with partial status (some pairs failed), retry just the failed ones. No need to re-translate the whole document.
{
"status": "✅ [LPO] [us-east-2] [BeastMain] [/translate/019e3d489ea4-15d9082769939137/retry] [202]",
"status_code": 202,
"endpoint": "/translate/019e3d489ea4-15d9082769939137/retry",
"cluster_node": "BeastMain",
"region": "us-east-2",
"language": "en",
"api_key_id": "ak_demo123",
"ip_address": "203.0.113.42",
"agent_profile_arn": "arn:tbi:us-east-2:211998422884:agent-profile/tbts/v1",
"timestamp": "2026-05-18T23:00:00Z",
"data": {
"original_job_id": "019e3d489ea4-15d9082769939137",
"retry_job_id": "019e3d5a1b2c-retry001",
"pairs_retrying": ["ko", "ur"],
"estimated_cost": "$0.51"
},
"error": ""
}
Every event is logged in Aurora with millisecond timestamps:
| Event Type | What It Records |
|---|---|
job_submitted | Customer, source URL, target languages, estimated cost |
job_started | Step Function execution ARN, start time |
lang_started | Language code, worker task ID |
lang_succeeded | Language code, duration, output S3 path, chunk count |
lang_failed | Language code, error type, retry count, last error message |
job_completed | Final status, total duration, pairs succeeded/failed, actual cost |
job_cancelled | Cancelled by (customer/system), pairs completed before cancel |
You can query your job history via GET /translate/history — last 50 jobs with full event logs.
/translate/usageGET /translate/health — public endpoint showing service status:
{
"status": "✅ [LPO] [us-east-2] [BeastMirror] [/translate/health] [200]",
"status_code": 200,
"endpoint": "/translate/health",
"cluster_node": "BeastMirror",
"region": "us-east-2",
"language": "en",
"api_key_id": "ak_demo123",
"ip_address": "203.0.113.42",
"agent_profile_arn": "arn:tbi:us-east-2:211998422884:agent-profile/tbts/v1",
"timestamp": "2026-05-18T23:15:00Z",
"data": {
"service_status": "operational",
"queue_depth": 3,
"active_jobs": 2,
"avg_completion_time_seconds": 145,
"last_successful_job": "2026-05-18T23:12:00Z",
"bedrock_status": "available",
"daily_spend": "$127.35",
"daily_limit": "$600.00"
},
"error": ""
}
The difference: AWS Translate gives you a job ID and says "check back later." We give you real-time progress, mid-job cancellation, failed-pair retry, full audit trail, and spend controls. Observable. Controllable. Resilient.
We maintain a 40-document technical library translated into 11 languages. These documents change daily as we ship new features. Rather than re-translating entire documents on every update, our engine uses an internal delta system that identifies exactly which sections changed and only processes those.
This is not a customer-facing feature — it is an internal optimization that keeps our operational costs low, which in turn keeps your translation prices competitive. You always submit fresh documents and receive complete translations. Behind the scenes, we apply the same engineering discipline to our own documentation pipeline.
The Trinity Beast Account Dashboard is where customers create accounts, manage services, and track usage. Translation-only customers are first-class citizens — you don't need a Price API subscription to use translation.
Dashboard URL: cpmp-site.org/dashboard
| Customer Type | Dashboard Shows |
|---|---|
| Translation only | Translations tab, Usage tab, Account Settings |
| Price API only | API Keys tab, Usage tab, Account Settings |
| Both services | All tabs — Translations, API Keys, Usage, Account Settings |
| Subscriber (paid plan) | All of the above + Subscription tab, Billing History |
When a job completes, we POST to your callback_url (if provided). Webhook payloads use the full UME envelope — same 12 fields as every API response:
POST https://your-server.com/webhook/translate-done
Content-Type: application/json
X-Trinity-Signature: sha256=abc123...
{
"status": "✅ [LPO] [us-east-2] [BeastWebhook] [webhook/translation.completed] [200]",
"status_code": 200,
"endpoint": "webhook/translation.completed",
"cluster_node": "BeastWebhook",
"region": "us-east-2",
"language": "en",
"api_key_id": "ak_demo123",
"ip_address": "203.0.113.42",
"agent_profile_arn": "arn:tbi:us-east-2:211998422884:agent-profile/webhook-engine/v1",
"timestamp": "2026-05-18T22:35:00Z",
"data": {
"event": "translation.completed",
"job_id": "019e3d489ea4-15d9082769939137",
"job_status": "succeeded",
"source_doc": "api-reference.html",
"pairs_succeeded": 3,
"pairs_failed": 0,
"cost": "$0.77",
"duration_seconds": 187,
"outputs": {
"es": "https://api.cpmp-site.org/translate/download/019e3d489ea4/es/api-reference.html",
"ja": "https://api.cpmp-site.org/translate/download/019e3d489ea4/ja/api-reference.html",
"zh": "https://api.cpmp-site.org/translate/download/019e3d489ea4/zh/api-reference.html"
}
},
"error": ""
}
The X-Trinity-Signature header contains an HMAC-SHA256 signature of the request body using your API key as the secret. Verify this to ensure the webhook is authentic.
UME everywhere: Webhooks use the same 12-field envelope as API responses. The cluster_node shows BeastWebhook so you know it came from our webhook delivery system. The endpoint shows the event type. Same shape, same parsing logic, same observability.
| Event | When It Fires | Endpoint Value |
|---|---|---|
translation.started | Job begins processing | webhook/translation.started |
translation.completed | Job finishes (succeeded, partial, or failed) | webhook/translation.completed |
translation.cancelled | Job was cancelled by customer | webhook/translation.cancelled |
If a job fails, the webhook still uses UME — but with the error field populated:
{
"status": "🛑 [LPO] [us-east-2] [BeastWebhook] [webhook/translation.completed] [200]",
"status_code": 200,
"endpoint": "webhook/translation.completed",
"cluster_node": "BeastWebhook",
"region": "us-east-2",
"language": "en",
"api_key_id": "ak_demo123",
"ip_address": "203.0.113.42",
"agent_profile_arn": "arn:tbi:us-east-2:211998422884:agent-profile/webhook-engine/v1",
"timestamp": "2026-05-18T22:40:00Z",
"data": {
"event": "translation.completed",
"job_id": "019e3d489ea4-15d9082769939137",
"job_status": "partial",
"source_doc": "api-reference.html",
"pairs_succeeded": 9,
"pairs_failed": 2,
"cost": "$2.35",
"duration_seconds": 312,
"outputs": {
"es": "https://api.cpmp-site.org/translate/download/019e3d489ea4/es/api-reference.html",
"pt": "https://api.cpmp-site.org/translate/download/019e3d489ea4/pt/api-reference.html",
"fr": "https://api.cpmp-site.org/translate/download/019e3d489ea4/fr/api-reference.html",
"de": "https://api.cpmp-site.org/translate/download/019e3d489ea4/de/api-reference.html",
"ru": "https://api.cpmp-site.org/translate/download/019e3d489ea4/ru/api-reference.html",
"ja": "https://api.cpmp-site.org/translate/download/019e3d489ea4/ja/api-reference.html",
"zh": "https://api.cpmp-site.org/translate/download/019e3d489ea4/zh/api-reference.html",
"hi": "https://api.cpmp-site.org/translate/download/019e3d489ea4/hi/api-reference.html",
"ar": "https://api.cpmp-site.org/translate/download/019e3d489ea4/ar/api-reference.html"
},
"failed_pairs": {
"ur": "Validator failed: tag count mismatch after 3 retries",
"ko": "Bedrock timeout after 15 minutes"
}
},
"error": ""
}
Note: status_code is 200 because the webhook delivery succeeded. The job status (partial) and failed_pairs tell you what happened with the translation. The error field in the envelope is empty because this isn't an envelope-level error — it's a job-level partial failure.
Every account can configure up to 150 brand terms that are automatically protected during translation. These terms are never translated, transliterated, or modified in any way — they appear exactly as written in every target language.
Generic translation services don't know your brand names. "Acme Corp" becomes "アクメ株式会社" in Japanese. "DataForge" becomes "DatenSchmiede" in German. Product names, person names, and technical identifiers get localized when they shouldn't be. Our sentinel preprocessing system prevents this entirely.
https://api.cpmp-site.org/dashboard| Constraint | Value |
|---|---|
| Maximum terms per account | 150 |
| Maximum characters per term | 100 |
| Duplicates | Automatically removed |
| Scope | Account-level — applies to every job |
The sentinel preprocessing system automatically protects technical content regardless of your brand terms list:
<pre> and <code> elements)Brand terms add protection for prose-level content — names and identifiers that appear in regular text paragraphs where the AI agent would otherwise translate or transliterate them.
Example: If your brand terms include "CloudSync API" and "DataForge", then the sentence "DataForge uses CloudSync API for real-time synchronization" translates to Japanese as "DataForge は CloudSync API を使用してリアルタイム同期を行います" — brand terms untouched, prose naturally translated.
GET /dashboard/api/protected-terms → Returns current terms list
PUT /dashboard/api/protected-terms → Replaces terms list
Body: {"terms": ["Acme Corp", "DataForge", "CloudSync API"]}
Every API response speaks your language. When you set your api_lang preference in the Account Dashboard, all human-readable messages — errors, confirmations, validation feedback — are returned in that language. Data elements stay English always.
Data stays English. Messages get localized.
Field names, IDs, status values, timestamps, amounts, quote IDs, job IDs — always English regardless of your language preference. Only the human-readable text (error descriptions, validation messages, informational labels) renders in your api_lang. This means your integration code never changes — parse the same JSON structure regardless of language.
| Category | Localized? | Example |
|---|---|---|
| Error messages | ✅ Yes | "La cotización ha expirado" (Spanish) |
| Validation feedback | ✅ Yes | "見積もりが見つかりません" (Japanese) |
| Email subjects & body | ✅ Yes | "Ihre Übersetzung ist fertig" (German) |
| Field names | ❌ No | quote_id, job_status, total_price |
| Status values | ❌ No | "accepted", "pending", "expired" |
| UME envelope brackets | ❌ No | ✅ [LPO] [us-east-2] [BeastMain] |
| Timestamps & amounts | ❌ No | "2026-07-08T14:00:00Z", "$3.96" |
Two language settings control your experience:
api_lang — Controls API response messages. Set in Account Dashboard → Settings → API Language. Default: en.preferred_lang — Controls emails (receipts, completion notifications, newsletters). Set in Account Dashboard → Settings → Communication Language. Default: en.API messages and emails are available in all 12 core languages:
en · es · pt · fr · de · ru · hi · ur · it · ar · ja · zh
If your api_lang is set to a language not in this list, messages fall back to English.
A customer with api_lang: "ja" sees validation errors in Japanese:
{
"status": "🛑 [LPO] [us-east-2] [BeastMain] [/translate/accept-batch] [409]",
"status_code": 409,
"endpoint": "/translate/accept-batch",
"cluster_node": "BeastMain",
"region": "us-east-2",
"language": "ja",
"api_key_id": "ed5ff412-4de1-4fb4-a96d-1f7053834f61",
"ip_address": "203.0.113.42",
"agent_profile_arn": "arn:tbi:us-east-2:211998422884:agent-profile/tbts/v1",
"timestamp": "2026-07-08T14:00:00Z",
"data": {
"status": "validation_failed",
"message": "バッチ内の一部の見積もりが処理できませんでした。エラーを確認し、有効な見積もりのみで再送信してください。",
"errors": [
{
"quote_id": "019f3a1b2c3d",
"error": "見積もり 019f3a1b2c3d は有効期限が切れています。新しい見積もりをリクエストしてください。"
}
],
"valid": 2,
"invalid": 1
},
"error": ""
}
The same request from a customer with api_lang: "es":
{
"status": "🛑 [LPO] [us-east-2] [BeastMain] [/translate/accept-batch] [409]",
"status_code": 409,
"endpoint": "/translate/accept-batch",
"cluster_node": "BeastMain",
"region": "us-east-2",
"language": "es",
"api_key_id": "ed5ff412-4de1-4fb4-a96d-1f7053834f61",
"ip_address": "203.0.113.42",
"agent_profile_arn": "arn:tbi:us-east-2:211998422884:agent-profile/tbts/v1",
"timestamp": "2026-07-08T14:00:00Z",
"data": {
"status": "validation_failed",
"message": "Algunas cotizaciones no pudieron procesarse. Revise los errores y reenvíe solo las cotizaciones válidas.",
"errors": [
{
"quote_id": "019f3a1b2c3d",
"error": "La cotización 019f3a1b2c3d ha expirado. Solicite una nueva."
}
],
"valid": 2,
"invalid": 1
},
"error": ""
}
The integration contract stays identical. Parse data.errors[].quote_id and data.errors[].error — same structure, same field names, same logic. The only difference is the human-readable string values. Your code doesn't need language-specific branches.
The batch acceptance endpoint validates every quote BEFORE charging your payment method. If any quote in your batch is invalid, the entire batch is rejected with structured errors — no partial charges, no guessing which ones failed.
Validate everything. Charge nothing. Return all errors in one round-trip.
When you submit a batch of 9 quotes, all 9 are validated against Aurora before Stripe is touched. If quotes #3 and #7 have problems, you get both errors back immediately — fix them and resubmit. Your card is never charged for a batch that can't fully execute.
The pre-validation gate catches four categories of problems:
| Error Type | Meaning | Resolution |
|---|---|---|
not_found | The quote ID does not exist or belongs to a different account | Verify the quote ID — check GET /translate/quotes for your active quotes |
already_processed | This quote was already accepted and paid for (includes the date it was processed) | Remove it from your batch — the job is already running or complete |
expired | The quote's 24-hour validity window has passed | Request a new quote — pricing may have changed |
validation_failed | Batch-level summary message when one or more quotes failed validation | Review the per-quote errors in the errors array |
When pre-validation fails, the response uses HTTP 409 with structured error detail:
{
"status": "🛑 [LPO] [us-east-2] [BeastMirror] [/translate/accept-batch] [409]",
"status_code": 409,
"endpoint": "/translate/accept-batch",
"cluster_node": "BeastMirror",
"region": "us-east-2",
"language": "en",
"api_key_id": "ed5ff412-4de1-4fb4-a96d-1f7053834f61",
"ip_address": "203.0.113.42",
"agent_profile_arn": "arn:tbi:us-east-2:211998422884:agent-profile/tbts/v1",
"timestamp": "2026-07-08T14:30:00Z",
"data": {
"status": "validation_failed",
"message": "Some quotes in your batch could not be processed. Please review the errors below and resubmit with valid quotes only.",
"errors": [
{
"quote_id": "019f3a1b2c3d",
"error": "Quote 019f3a1b2c3d has expired. Please request a new quote."
},
{
"quote_id": "019f3a2e4f5g",
"error": "Quote 019f3a2e4f5g has already been processed on July 7, 2026 at 2:15 PM EST. Please remove it from your batch."
}
],
"valid": 7,
"invalid": 2
},
"error": ""
}
// Pseudocode — handling the 409 pre-validation response
response = POST("/translate/accept-batch", { quote_ids: [...] })
if response.status_code == 409:
// No charge was made. Fix the issues and retry.
for error in response.data.errors:
log(f"Quote {error.quote_id} failed: {error.error}")
// Remove invalid quotes and resubmit
valid_ids = [id for id in quote_ids if id not in failed_ids]
retry_response = POST("/translate/accept-batch", { quote_ids: valid_ids })
elif response.status_code == 200:
// All quotes valid, payment processed, jobs submitted.
task_id = response.data.task_id
// Poll task status for consolidated completion.
Idempotent by design: If a quote has already been processed, the error includes when it was processed and tells you to remove it. This prevents double-charging — even if your retry logic accidentally re-submits a completed quote, it will never be charged twice.
When all quotes pass validation and payment succeeds:
{
"status": "✅ [LPO] [us-east-2] [BeastMain] [/translate/accept-batch] [200]",
"status_code": 200,
"endpoint": "/translate/accept-batch",
"cluster_node": "BeastMain",
"region": "us-east-2",
"language": "en",
"api_key_id": "ed5ff412-4de1-4fb4-a96d-1f7053834f61",
"ip_address": "203.0.113.42",
"agent_profile_arn": "arn:tbi:us-east-2:211998422884:agent-profile/tbts/v1",
"timestamp": "2026-07-08T14:30:00Z",
"data": {
"status": "accepted",
"batch_size": 3,
"quote_ids": ["019f3a1b2c3d", "019f3a2e4f5g", "019f3a3h6i7j"],
"task_id": "019f3b4k8l9m",
"jobs": [
{"quote_id": "019f3a1b2c3d", "doc_name": "api-reference.html", "job_id": "019f3c5n0p1q"},
{"quote_id": "019f3a2e4f5g", "doc_name": "user-guide.html", "job_id": "019f3c6r2s3t"},
{"quote_id": "019f3a3h6i7j", "doc_name": "quick-start.html", "job_id": "019f3c7u4v5w"}
],
"payment_id": "pi_3TgvABC123...",
"amount_usd": 11.88,
"eta": {
"estimated_seconds": 180,
"bottleneck_language": "ar",
"estimated_completion": "2026-07-08T14:33:00Z"
}
},
"error": ""
}
Notice the task_id — this is your handle for tracking the entire batch as a unit. The eta object shows estimated completion time based on the bottleneck language (the one that will take longest).
When you accept multiple quotes in a single batch, the engine creates a parent Task that tracks all resulting jobs as a unit. One acceptance = one Task = N jobs. One notification when everything finishes — not N individual emails.
Without the Task Organizer, accepting 9 quotes (each with 11 languages) would generate 9 separate completion emails — one per job as it finishes. That's noise, not signal. The Task Organizer holds notification until all jobs in the batch reach a terminal state (succeeded, failed, or cancelled), then sends a single consolidated email with the full picture.
Track your batch with GET /translate/task/{task_id}:
{
"status": "✅ [LPO] [us-east-2] [BeastMain] [/translate/task/019f3b4k8l9m] [200]",
"status_code": 200,
"endpoint": "/translate/task/019f3b4k8l9m",
"cluster_node": "BeastMain",
"region": "us-east-2",
"language": "en",
"api_key_id": "ed5ff412-4de1-4fb4-a96d-1f7053834f61",
"ip_address": "203.0.113.42",
"agent_profile_arn": "arn:tbi:us-east-2:211998422884:agent-profile/tbts/v1",
"timestamp": "2026-07-08T14:35:00Z",
"data": {
"task_id": "019f3b4k8l9m",
"state": "in_progress",
"total_jobs": 3,
"completed_jobs": 1,
"failed_jobs": 0,
"cancelled_jobs": 0,
"notification_sent": false,
"jobs": [
{"job_id": "019f3c5n0p1q", "state": "succeeded", "completed_at": "2026-07-08T14:33:12Z", "succeeded_pairs": 11, "failed_pairs": 0, "bedrock_cost": 3.96},
{"job_id": "019f3c6r2s3t", "state": "translating", "completed_at": "", "succeeded_pairs": 0, "failed_pairs": 0, "bedrock_cost": 0},
{"job_id": "019f3c7u4v5w", "state": "queued", "completed_at": "", "succeeded_pairs": 0, "failed_pairs": 0, "bedrock_cost": 0}
]
},
"error": ""
}
| State | Meaning |
|---|---|
queued | Task created, jobs are queued for processing |
in_progress | At least one job has started translating |
succeeded | All jobs completed successfully |
partial | All jobs finished, but some had failures (download what succeeded, retry what failed) |
failed | All jobs failed |
cancelled | Task was cancelled — completed jobs remain available |
When all jobs in a Task finish, the customer receives a single email summarizing the entire batch. The email renders in the customer's preferred_lang — subject line, title, all labels, download links, and footer.
What the email contains:
Email i18n coverage: Every string in the completion email — from the subject line ("Su traducción está lista") to the footer ("El 100% de los ingresos financia la libertad...") — is translated into all 12 supported languages. 18 distinct string fields, each available in 12 languages. The email reads naturally in every supported language, not like a translation.
If you provided a callback_url on any quote in the batch, a single webhook fires when the Task completes:
POST https://your-server.com/webhook/translate-done
Content-Type: application/json
X-Trinity-Signature: sha256=...
{
"status": "✅ [LPO] [us-east-2] [BeastWebhook] [webhook/task.completed] [200]",
"status_code": 200,
"endpoint": "webhook/task.completed",
"cluster_node": "BeastWebhook",
"region": "us-east-2",
"language": "en",
"api_key_id": "ed5ff412-4de1-4fb4-a96d-1f7053834f61",
"ip_address": "203.0.113.42",
"agent_profile_arn": "arn:tbi:us-east-2:211998422884:agent-profile/webhook-engine/v1",
"timestamp": "2026-07-08T14:38:00Z",
"data": {
"event": "task.completed",
"task_id": "019f3b4k8l9m",
"task_state": "succeeded",
"total_jobs": 3,
"completed_jobs": 3,
"failed_jobs": 0,
"total_pairs_succeeded": 33,
"total_pairs_failed": 0,
"total_cost": 11.88,
"duration_seconds": 312,
"jobs": [
{"job_id": "019f3c5n0p1q", "doc_name": "api-reference.html", "state": "succeeded", "pairs": 11},
{"job_id": "019f3c6r2s3t", "doc_name": "user-guide.html", "state": "succeeded", "pairs": 11},
{"job_id": "019f3c7u4v5w", "doc_name": "quick-start.html", "state": "succeeded", "pairs": 11}
]
},
"error": ""
}
DELETE /translate/task/{task_id} cancels all remaining jobs in the batch. Already-completed jobs are unaffected — their translations remain available for download. You are not charged for cancelled pairs.
The workflow: Submit quotes → accept as a batch → get a task_id → poll task status or wait for the webhook → download when done. One payment, one tracking handle, one notification. Clean.
Timeline: 1-2 sessions
Deliverables:
POST /translate — submit job (wraps internal translation engine)GET /translate/{job_id} — check status + get output URLsDELETE /translate/{job_id} — cancel running jobGET /translate/languages — list supported languages (public)Timeline: 1 session
Deliverables:
GET /translate/usage — current month usageusage:translate:{customer_id}:{month})Timeline: 1-2 sessions
Deliverables:
Timeline: 1 session
Deliverables:
| Risk | Impact | Mitigation |
|---|---|---|
| Abuse (huge documents) | Cost overrun, resource exhaustion | File size limit (5 MB), rate limit (10 jobs/hour per customer) |
| Abuse (spam submissions) | Queue flooding, cost | Require valid API key, daily spend cap per customer ($100 default) |
| Bad input (malformed HTML) | Worker crashes, partial output | Validate document structure before queuing, return clear error |
| Bedrock outage | Jobs fail | Retry with exponential backoff, notify customer on persistent failure |
| Customer data privacy | Trust, compliance | Isolated folders per customer, 30-day auto-delete, no content logging |
| Cost underestimation | Negative margin | Per-chunk pricing is driven from Valkey (actual Bedrock costs). Prices auto-adjust if model costs change. No manual margin calculation needed. |
| Complex scripts timeout | Arabic, Urdu, Hindi take longer | Per-language chunk size tuning (3000 chars for Indic/Arabic scripts), numeric pattern extraction to prevent model from dropping values, preprocessor sibling-awareness to ensure all code tags are extracted. All 21 validated languages tested in production. |
Infrastructure cost: Nearly zero incremental cost. The translation engine runs on a persistent container (ECS Fargate) that idles at near-zero CPU when not processing jobs. We only pay for active translation time. S3 storage for customer outputs is pennies. The only fixed cost is the existing infrastructure we already run.
What we're selling: AI-powered document translation that actually works for technical content.
Why it's viable:
Revenue potential:
Time to market: 4-6 sessions to MVP. Core API in 1-2 sessions.
Bottom line: We solved this problem for ourselves. Now we can solve it for others — and let the service help pay for the ministry's infrastructure.