Normalize numbers, currency, phone numbers and units for text-to-speech
Rewrites digits in up to 20000 characters of text into spoken words for a TTS engine, for locales en-US and en-GB: cardinals, ordinals, years (with a preceding cue such as "in" or a month) and decades, decimals, percentages, currency with ISO 4217 minor units ("$12.50" -> "twelve dollars and fifty cents"), phone numbers read digit by digit, and SI/common units with locale spelling (meter/metre). Other locales return unsupported. Dates, times, fractions, decimal-comma numbers, and currencies or units outside the built-in tables are left unchanged and reported as witnesses with status unknown; bare four-digit numbers are read as cardinals and flagged because year versus quantity is ambiguous. Deterministic; no language model.
What you get
A voice agent that reads "$1,234.50" or "+1 555-123-4567" wrongly loses customer trust; this makes the spoken form explicit and flags what it could not read.
Call it
Send the JSON body below to https://agents.writerslogic.com/api/v1/speech-normalize. An unpaid request answers 402 with the price and how to pay; a request that fails with a 5xx status is not charged.
curl -i -X POST https://agents.writerslogic.com/api/v1/speech-normalize \
-H 'content-type: application/json' \
-d '{"text":"Call +1 555-123-4567 before the 3rd: it costs $12.50 (15% off).","locale":"en-US"}'
Input
| Field | Type | Required | Description |
|---|---|---|---|
text | string; length 1..20000 | yes | |
locale | string; length 0..16 | no | BCP 47 tag. en-US (default) and en-GB are supported; anything else returns unsupported. |
Example request body
{
"text": "Call +1 555-123-4567 before the 3rd: it costs $12.50 (15% off).",
"locale": "en-US"
}
Result
The response is { "data": ..., "_provenance": ... }. data carries these fields; _provenance is a signed W3C Verifiable Credential with a C2PA-style manifest, checked free at POST /api/v1/verify-provenance.
| Field | Type | Required | Description |
|---|---|---|---|
status | string; one of "pass", "fail", "unknown", "unsupported" | no | pass: every rule held. fail: a rule was violated (see witnesses). unknown: the input lacks the evidence to decide. unsupported: outside what this engine covers. Missing evidence is never a pass. |
locale | string | no | |
normalized | string | no | The text with every resolved token replaced by its spoken form. |
replacementCount | integer | no | |
replacements | array<object> | no | First 500 replacements in text order. |
truncated | boolean | no | |
witnesses | array<object> | no | |
versions | object | no | Every semantic dependency of this answer (engine, tables and their as-of dates, tokenizer, calendar, rounding profile). |
limits | array<string> | no | |
deterministic | boolean | no | Always true: pure code, no model. |
Pay and connect
Available through: x402 (USDC on Base), MCP. MCP clients reach it through the identifier-text-kit package.
Machine-readable
- This agent as JSON (schemas, example, OpenAPI operation)
- Free signed sample response
- OpenAPI 3.1 · Catalog · Index of every agent