Assistants
Choosing a voice, model, and transcriber
Browse the three catalogues an assistant references (voices, language models, and transcribers) and pick the IDs you configure it with.
Before an assistant can take a call it needs three IDs: a voice to speak with, a language model to reason with, and a transcriber to hear with. All three come from read-only catalogues that OnCore maintains for you: browse a catalogue, pick a row, keep its id.
| Method | Path | Purpose |
|---|---|---|
| GET | /voices | List the voice catalogue |
| GET | /voices/{id} | Get one voice |
| GET | /models | List the language-model catalogue |
| GET | /models/{id} | Get one model |
| GET | /transcribers | List the transcriber catalogue |
| GET | /transcribers/{id} | Get one transcriber |
For the endpoint-by-endpoint schemas, see the Voices, Models & Transcribers reference.
How the catalogues work#
The three catalogues behave identically, so learning one teaches you all three:
- They are read-only. Only
GETis exposed; you choose from what OnCore offers rather than registering your own entries. - Every list is paginated and reports a
total, so you can tell when you have seen everything. - Every response uses the standard envelope: the payload sits in
data, alongsidesuccessandmetadata. See Conventions. - Store the
id, never the display name.nameis a label that can repeat (the same voice can appear more than once under different underlying models), whileidis the stable reference. Versioning explains why these catalogues are expected to grow.
All three list endpoints take the same two query parameters:
| Query param | Type | Required | Description |
|---|---|---|---|
limit | number | No | Page size. Default 50, maximum 500. |
offset | number | No | Items to skip. Default 0. |
Pick a voice#
GET /voices returns the catalogue; GET /voices/{id} returns a single entry once you know its ID.
curl "https://core-api.heysadie.ai/voices?limit=50" \
-H "Authorization: ApiKey YOUR_API_KEY"The list arrives in data.voices, with the catalogue size in data.total:
{
"success": true,
"data": {
"voices": [
{
"id": "0195f1e2-5555-7000-8000-000000000000",
"name": "Example Voice",
"provider": "example-provider"
}
],
"total": 42
},
"metadata": {
"timestamp": "2026-07-30T12:00:00.000Z",
"version": "1.0",
"path": "/voices"
}
}Each entry in data.voices carries these fields:
| Field | Type | Description |
|---|---|---|
id | string | Always present. The UUID you send as voiceId on an assistant. |
name | string | Always present. The voice's display label. |
provider | string | Always present. Which provider supplies the voice. |
body | n/a | Always present. The spec declares no type for this field. |
tags | n/a | Optional. The spec declares no type for this field. |
language | n/a | Optional. The spec declares no type for this field. |
tags and language are string arrays; body is provider-shaped
tags (on voices, models and transcribers) and language (on voices) are each an array
of strings, optional and nullable: expect null as readily as an empty array, and guard
for it.
body on a voice is genuinely untyped: it carries the provider's own payload for that
voice, so its shape varies by provider and no single schema describes it. Read it if you
need provider-specific detail, but do not write a type against it.
What each provider accepts in body, with the range for every setting, is documented
under Providers. Read the page for your provider before
changing a value: providers disagree on how they treat a setting they dislike, and on some
of them a value outside its range ends the call rather than being ignored.
GET /voices/{id} returns the same fields, but as a bare object in data rather than inside a voices array:
curl https://core-api.heysadie.ai/voices/0195f1e2-5555-7000-8000-000000000000 \
-H "Authorization: ApiKey YOUR_API_KEY"{
"id": "0195f1e2-5555-7000-8000-000000000000",
"name": "Example Voice",
"provider": "example-provider"
}If your callers do not all speak the same language, read Multi-language calls before you settle on a voice. Some voices in the catalogue speak one language and others speak several, and that choice decides who your assistant can serve.
Pick a language model#
GET /models lists the language models an assistant can reason with; GET /models/{id} returns one of them.
curl "https://core-api.heysadie.ai/models?limit=50" \
-H "Authorization: ApiKey YOUR_API_KEY"The list arrives in data.models, with the catalogue size in data.total:
{
"models": [
{
"id": "0195f1e2-6666-7000-8000-000000000000",
"name": "Example Model",
"model": "example-model-v1",
"provider": "example-provider"
}
],
"total": 12
}| Field | Type | Description |
|---|---|---|
id | string | Always present. The UUID you send as modelId on an assistant. |
name | string | Always present. |
model | string | Always present. |
provider | string | Always present. Which provider serves the model. |
tags | n/a | Optional. The spec declares no type for this field. |
name versus model
name is the human-readable label to show in a picker. model is the provider model identifier used by the voice runtime. Store the resource id as the assistant's modelId; display name with provider, and use model only when you need to inspect the underlying provider configuration.
GET /models/{id} returns the same fields as a bare object in data:
curl https://core-api.heysadie.ai/models/0195f1e2-6666-7000-8000-000000000000 \
-H "Authorization: ApiKey YOUR_API_KEY"Pick a transcriber#
The transcriber is the speech-to-text engine that turns what the caller says into text for the model. GET /transcribers lists the catalogue; GET /transcribers/{id} returns one entry.
curl "https://core-api.heysadie.ai/transcribers?limit=50" \
-H "Authorization: ApiKey YOUR_API_KEY"The list arrives in data.transcribers, with the catalogue size in data.total:
{
"transcribers": [
{
"id": "0195f1e2-7777-7000-8000-000000000000",
"name": "Example Transcriber",
"provider": "example-provider"
}
],
"total": 8
}| Field | Type | Description |
|---|---|---|
id | string | Always present. The UUID you send as transcriberId on an assistant. |
name | string | Always present. The transcriber's display label. |
provider | string | Always present. Which provider supplies the transcriber. |
tags | n/a | Optional. The spec declares no type for this field. |
A transcriber entry has no language field, so this page does not state which languages any given transcriber covers.
curl https://core-api.heysadie.ai/transcribers/0195f1e2-7777-7000-8000-000000000000 \
-H "Authorization: ApiKey YOUR_API_KEY"Use the three IDs#
Once you have one id from each catalogue, pass them to the assistant as voiceId, modelId, and transcriberId: on POST /assistants when you create it, or on PATCH /assistants/{id} to swap one later.
curl -X PATCH https://core-api.heysadie.ai/assistants/0195f1e2-2222-7000-8000-000000000000 \
-H "Authorization: ApiKey YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"voiceId": "0195f1e2-5555-7000-8000-000000000000",
"modelId": "0195f1e2-6666-7000-8000-000000000000",
"transcriberId": "0195f1e2-7777-7000-8000-000000000000"
}'Because the catalogues grow, resolve these IDs once and store them rather than looking them up on every call. Re-check them when you want a newly added voice or model. Assistants covers the rest of the configuration these three IDs sit alongside.
When a lookup fails#
All six endpoints return the standard error envelope, made up of success: false plus an error object with a machine-readable code, a human-readable message, and, for validation failures, a details array of { field, message } entries:
{
"success": false,
"error": {
"code": "NOT_FOUND",
"message": "Voice not found"
},
"metadata": {
"timestamp": "2026-07-30T12:00:00.000Z",
"version": "1.0",
"path": "/voices/0195f1e2-5555-7000-8000-000000000000"
}
}Each of the six can answer 400, 401, 403, 404, or 500. Branch on error.code, never on error.message. Errors lists every code and what it means.
Noisy callers#
Every call runs background noise reduction on the caller's audio before it reaches the transcriber. It is always on and there is nothing to configure: a caller in a car, a cafe or a warehouse is already handled, and you do not need to pick a transcriber for robustness to noise.
What it does not remove is a second person talking nearby, which the transcriber may still pick up as caller speech. If an assistant reacts to something the caller did not say, that is usually the cause rather than the transcriber choice.
Next steps#
- Create and configure an assistant: put the three IDs to work and set the rest of the assistant up.
- Expressive mode: how the voice you picked decides whether the assistant can steer its own delivery.
- Voices, Models & Transcribers reference: the generated schema for all six endpoints, always current with the live API.