Assistants
Manage dictionaries
Create a dictionary of recognition terms or pronunciations, link it to an assistant, and check that the rules actually applied.
Overview#
A dictionary is a tenant-level list you write once and link to as many assistants as you like. This page covers creating one, reading what you already have, linking it, adding entries for a single assistant, and confirming a rule took effect on a real call.
If you have not read what dictionaries do and when a rule is ignored, start there. Whether an entry applies at all depends on the assistant's voice and transcriber, and that page has the tables. The generated field reference lives in the Assistants API.
Every response on this page arrives in the standard envelope, so read each payload from data:
{
"success": true,
"data": { },
"metadata": { "timestamp": "2026-01-01T00:00:00.000Z", "version": "1.0" }
}The dictionary itself is data, its ID is data.id, and nothing useful sits at the top level besides success. Errors reuse the same envelope with success: false and an error object; see Errors below.
Prerequisites#
- A tenant API key, sent as
Authorization: ApiKey YOUR_API_KEYon every request. Dictionaries are tenant-level resources, so a tenant key is the natural fit. An organization key also works if you add theX-Tenant-Idheader. Authentication covers both. - An assistant you can edit, with its voice and transcriber already chosen. Which of your rules take effect depends on them.
- A way to reach that assistant on a live call, so you can hear the result: a phone number linked to it, or browser calling.
- Recording enabled on that assistant, if you are checking a pronunciation. A pronunciation never shows up in a transcript, so the audio is the only proof.
recordingEnableddefaults totrue; if you turned it off, turn it back on before the test call. See Recording and transcripts.
Create a dictionary#
A dictionary's type is fixed when you create it and cannot be changed afterwards, because it decides the shape of every entry inside. Create a second dictionary rather than trying to convert one.
A keywords dictionary holds recognition terms, one term per entry. language is optional and uses the same codes a call can settle on as a pronunciation (fr, not french):
curl -X POST https://core-api.heysadie.ai/dictionaries \
-H "Authorization: ApiKey YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"type": "keywords",
"name": "Brand names",
"entries": [
{ "term": "Gree" },
{ "term": "Braemar" },
{ "term": "Rinnai" }
]
}'A pronunciations dictionary uses the other entry shape: a word, plus a respell and/or phonemes saying how to say it, and an optional language. language is one of the codes a call can settle on (fr, not french). Supplying both respell and phonemes is recommended, since phonemes only reach a subset of voices and the respelling covers the rest.
curl -X POST https://core-api.heysadie.ai/dictionaries \
-H "Authorization: ApiKey YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"type": "pronunciations",
"name": "French product names",
"entries": [
{ "word": "Quatre", "respell": "Kat", "phonemes": "k a t", "language": "fr" }
]
}'Both calls answer 200 with the created dictionary under data: data.id, data.type, data.name and data.entries. Keep data.id, since linking is by ID. Creating a dictionary attaches it to nothing on its own.
List and read dictionaries#
GET /dictionaries lists what your tenant has. Every row carries its full entries array, so this doubles as the way to see what is currently stored.
| Parameter | Type | Required | Description |
|---|---|---|---|
limit | number | No | Page size. Default 10, maximum 100. |
offset | number | No | Items to skip. Default 0. |
type | string | No | Return only keywords or only pronunciations. Omit to return both kinds. |
Dictionaries have their own pagination limits
limit caps at 100 here with a default of 10, not the platform-wide 50/500. Asking for more than 100 is rejected rather than clamped.
GET /dictionaries/{id} returns one dictionary, including every entry. Use it before an update, since updating replaces entries rather than merging them.
curl "https://core-api.heysadie.ai/dictionaries?type=keywords&limit=20" \
-H "Authorization: ApiKey YOUR_API_KEY"
curl https://core-api.heysadie.ai/dictionaries/0195f1e2-0000-0000-0000-000000000001 \
-H "Authorization: ApiKey YOUR_API_KEY"The list response puts the array at data.dictionaries and the total count at data.total. The single-dictionary response puts the dictionary itself at data.
Link dictionaries to an assistant#
dictionaryIds replaces the whole set, so send every dictionary the assistant should use, including ones already linked. Sending [] unlinks everything.
Read the current links first with GET /assistants/{id}: the assistant payload echoes them at data.dictionaryIds. Add your new ID to that array and send the result back, rather than sending the new ID alone.
The order matters. It is the precedence order. When two dictionaries define the same word, the one earlier in this array wins.
curl https://core-api.heysadie.ai/assistants/0195f1e2-0000-0000-0000-000000000000 \
-H "Authorization: ApiKey YOUR_API_KEY"
curl -X PATCH https://core-api.heysadie.ai/assistants/0195f1e2-0000-0000-0000-000000000000 \
-H "Authorization: ApiKey YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"dictionaryIds": [
"0195f1e2-0000-0000-0000-000000000001",
"0195f1e2-0000-0000-0000-000000000002"
]
}'The assistant response echoes dictionaryIds in the order stored. Every ID must be a dictionary belonging to your tenant. An unknown ID is rejected and the assistant's existing links are left alone.
Add entries for one assistant only#
Some words matter to a single assistant, such as the name it introduces itself with. Those go in dictionarySettings on the assistant itself, and they beat every linked dictionary.
curl -X PATCH https://core-api.heysadie.ai/assistants/0195f1e2-0000-0000-0000-000000000000 \
-H "Authorization: ApiKey YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"dictionarySettings": {
"sttKeyterms": [{ "term": "Aria" }],
"ttsPronunciations": [
{ "word": "Aria", "respell": "AR-ee-uh" }
]
}
}'This field replaces the whole document rather than merging into it, so send both lists whenever you send either. Send null to clear it.
Update or remove a dictionary#
Updating entries overwrites, it never merges
Sending entries on a PUT stores exactly the array you sent and discards everything that was there before. An entry you leave out is gone. To add one entry, read the dictionary with GET /dictionaries/{id}, append to the array you got back, and send the whole array. Omit entries entirely to rename a dictionary without touching its rules.
curl -X PUT https://core-api.heysadie.ai/dictionaries/0195f1e2-0000-0000-0000-000000000001 \
-H "Authorization: ApiKey YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Brand names",
"entries": [{ "term": "Gree" }, { "term": "Daikin" }]
}'The example above leaves the dictionary holding two terms, Gree and Daikin. Braemar and Rinnai from the create call are no longer stored, because they were not in the array.
type is not part of an update, and entries are always validated against the type the dictionary was created with. Create a second dictionary if you need the other shape.
Deleting a dictionary also unlinks it from every assistant using it. Those assistants keep their own entries and any other dictionaries they link.
curl -X DELETE https://core-api.heysadie.ai/dictionaries/0195f1e2-0000-0000-0000-000000000001 \
-H "Authorization: ApiKey YOUR_API_KEY"Check that a rule applied#
A rule can be stored correctly and still not apply, because the assistant's voice or transcriber does not support it. Confirm on a real call rather than assuming.
Place a test call#
Dial a phone number linked to the assistant, or open the page where you have browser calling set up. If no number is linked yet, search, buy and configure covers attaching one.
During the call, say the word you added a recognition term for, and ask the assistant something that forces it to say the word you wrote a pronunciation for. Note roughly when in the call you did each, so you can find them again.
Read the transcript#
Open the call in call activity. A recognition term worked if your spelling appears in the caller's turn rather than the misheard one.
Listen to the recording#
Pronunciations do not show up in the transcript, because the transcript records the words the assistant chose rather than the sound it made. The recording is the only place to confirm one, which is why it needs recordingEnabled on the assistant. Recording and transcripts covers where the link arrives.
If a pronunciation did not change the sound, check the assistant's voice against the support table in Dictionaries and recognition terms before changing the rule. A phoneme-only entry on a voice that cannot speak phonemes does nothing, and adding a respell is usually the fix.
Errors#
Every dictionary operation answers 200 on success (including create) and publishes 400, 401, 403, 404 and 500 for failures. Failures use the same envelope with success: false and an error object, so one handler covers all of them.
| Status | What it means here |
|---|---|
400 | The body or query failed validation: a keywords entry in a pronunciations dictionary, a pronunciation entry with neither respell nor phonemes, a language that is not one of the codes a call can settle on (for example french), more than 100 entries, limit above 100, or an update sending neither name nor entries. |
401 | The Authorization header is missing, malformed, or invalid. |
403 | The key is valid but not allowed to act on this resource. |
404 | No such dictionary for your tenant. A dictionary belonging to another tenant reads as missing rather than forbidden. |
500 | Something went wrong on OnCore's side. Retry, then report the metadata.timestamp if it persists. |
Two failures worth planning for:
- An unknown
dictionaryIdsentry on an assistant update is rejected outright. The whole array is refused and the assistant's existing links stay exactly as they were, so a bad ID cannot half-apply. - A rejected
PUTchanges nothing. Entries are validated against the storedtypebefore anything is written, so a failed update leaves the previous entries intact.
Errors documents the envelope and the error.code values in full, and the Assistants API reference carries the generated schemas.
Next steps#
- Dictionaries and recognition terms: which rules apply on which voices and transcribers.
- Recording and transcripts: where to find the recording that confirms a pronunciation.
- Choosing a voice, model, and transcriber: switch the voice if the rules you need are not supported.