Per-account lexicon: custom pronunciations on Audra — Audra
Phonemize fixes a pronunciation once; a lexicon fixes it forever. Audra's per-account lexicon is a set of up to 100 term-to-spoken-text overrides applied automatically to every render on your account — before normalization, before synthesis — so 'K8s' is always 'Kubernetes' and your company name is never mangled again.
This post is the lexicon API: PUT and GET on /v2/lexicon, entry semantics, how it interacts with normalization, and the workflow from one-off fix to permanent override.
Entries: term and spoken
Each entry has two fields. term is the word or phrase to match — up to 64 characters, matched case-insensitively on word boundaries, so 'Audra' matches inside a sentence without corrupting 'audraum' (there is no such word, which is the point). spoken is the speakable replacement, up to 120 characters of plain text or inline SSML.
curl
curl https://audratalks.com/v2/lexicon \
-X PUT \
-H "Authorization: Bearer sk-audra-..." \
-H "Content-Type: application/json" \
-d '{"entries":[{"term":"K8s","spoken":"Kubernetes"},{"term":"ACME","spoken":"ack-me"}]}'
Python
import requests
resp = requests.put(
"https://audratalks.com/v2/lexicon",
headers={"Authorization": "Bearer sk-audra-..."},
json={"entries": [
{"term": "K8s", "spoken": "Kubernetes"},
{"term": "ACME", "spoken": "ack-me"},
]},
timeout=30,
)
resp.raise_for_status()
print(resp.json()) # {"entries": [...], "max_entries": 100}
JavaScript
const res = await fetch("https://audratalks.com/v2/lexicon", {
method: "PUT",
headers: { Authorization: "Bearer sk-audra-...", "Content-Type": "application/json" },
body: JSON.stringify({ entries: [
{ term: "K8s", spoken: "Kubernetes" },
{ term: "ACME", spoken: "ack-me" },
]}),
});
if (!res.ok) throw new Error(await res.text());
console.log(await res.json()); // { entries: [...], max_entries: 100 }
PUT is a full replacement of the entries you send, not a merge — read current state with GET /v2/lexicon first if you are adding to an existing set. The response echoes the saved entries and max_entries. Delete a single override with DELETE /v2/lexicon/{term}.
What belongs in the lexicon
- Brand and product names the G2P guesses wrong ('Nginx' → 'engine-x', 'SQL' → 'sequel').
- Tickers and codes that should be spoken as words, or spelled: spoken 'APPL' → 'A P P L' or 'Apple'.
- Recurring client names across a portfolio of rendered content.
- House style: 'vs.' → 'versus', 'e.g.' → 'for example' — the lexicon is a text-level find-replace with perfect consistency.
Order of operations
Lexicon application happens before shared finance lexicon and before synthesis, but interacts with normalize: normalization expands URLs, emails, currency, and percentages. If normalize rewrites a token your lexicon targets, the normalized form is what hits the lexicon match. The reliable preflight: run your text through POST /v2/phonemize after saving the lexicon — its input field shows the exact text after lexicon and normalization, and it costs no credits.
Failure modes and fixes
- 400 on validation errors or exceeding 100 entries — keep the list curated; move one-off fixes to inline IPA markup instead.
- Entry not applying: usually a word-boundary mismatch (term inside a larger word, or punctuation touching it); test the exact sentence in /v2/phonemize.
- Shared finance lexicon still applying after your override: your account entries take precedence, but confirm via phonemize's input field.
One-off pronunciation preview: the phonemize post. Full parameter reference: /docs.