aethexDocs

API Reference

Voices API

Browse the TTS voice catalog, play short previews, and clone a voice from a recording.Read access. voices:read lists the catalog, looks up individual voices, fetches the recording prompt and reads clone jobs.Preview. tts:use powers POST /voices/preview, which bills per character at the same rate as POST /tts.Cloning. voices:write creates and deletes cloned voices. It is not in the default scope set: grant it to the key that will clone. A completed clone costs 5 credits. Speaking with a cloned voice is billed like any other voice. A cloned voice is private to your account.You see Aethex's global voice catalog plus any private voices on your account, including your clones. The catalog grows over time as we add new voices, so re-list when you want the latest options rather than hard-coding IDs in your app.

Base URL
https://api.aethexai.com/api/v1
Endpoints
10
Scopes
voices:readtts:usevoices:write
GET/voices

Browse every voice available to your account.

List Voices

Lists every voice you can use: the global catalog plus any private voices on your account. Filter by language, supports_dialect_style, tag, or country to narrow it down. Results come back in stable order (newest first), so paging with (limit, offset) is safe; keep paging until you receive fewer than limit rows. The response is a flat JSON array; no envelope, no cursor.Voice IDs are UUIDs in the modern API. The id field in every response object is a UUID — copy it directly into your voice_id fields. The sentinel "default" is only accepted on the TTS synthesis endpoint (POST /tts); POST /voices/preview and agent create/update require a real voice UUID (or legacy voice_key) from this list and return a 404/422 not-found error otherwise. Existing agents created with legacy slug-form IDs continue to work without migration. New code should use a UUID from this list.

Path & Query

6
  • languagestringoptional

    Show only voices in this language. Currently english or french. An unknown value returns an empty list so existing dashboards stay working.

  • supports_dialect_stylebooleanoptional

    Show only voices that honor your agent's dialect_style setting (formal / mixed / local). See Dialect style.

  • tagstringoptional

    Show only voices tagged with this token. Case-sensitive; the value must come from GET /voices/tag-vocabulary (any token from any bucket). Empty or whitespace-only input is treated as no filter. An unknown token returns an empty list rather than 422.

  • countrystringoptional

    Show only voices from this country, as an ISO 3166-1 alpha-2 code (NG, FR, US, ...). Case-insensitive. Empty or whitespace-only input is treated as no filter and returns every voice in the catalog. Hit GET /voices/countries for the supported set. An unknown code returns an empty list rather than 422.

  • limitintegeroptional

    How many voices to return per page. Default 100, range 0–500.

  • offsetintegeroptional

    How many voices to skip before this page. Default 0. Pair with limit for paging.

Errors

1
422Invalid pagination

limit is outside 0–500 or offset is negative.

Keep limit between 0 and 500 and use a non-negative offset.

GET/voices/countries

Enumerate the supported `country` codes for the `?country=` filter.

List Countries

Returns the closed set of ISO 3166-1 alpha-2 codes the voice catalog uses, paired with display names. Sorted by code. Use this to populate a country dropdown in your app rather than hard-coding a list. The set covers every country in Europe, the Americas, Africa, and the Middle East (149 codes); Asia outside the Middle East and Oceania may be added in future releases.

GET/voices/tag-vocabulary

Enumerate the closed set of `tag` tokens accepted by the catalog.

List Tag Vocabulary

Returns the canonical vocabulary of voice tags, grouped into four UI-facing buckets: tone, voice_texture, delivery_style, and business_persona. The bucket grouping is purely a UI affordance — the underlying storage is a flat list and any token from any bucket is a valid filter value for the ?tag= filter on GET /voices. Use this endpoint to populate a tag picker in your dashboard or to validate user-supplied tag input client-side before sending it as the ?tag= filter on GET /voices. The vocabulary is static configuration and changes infrequently — safe to cache for the lifetime of a page load.

GET/voices/:voice_id

Look up one voice by its ID.

Get Voice

Returns a single voice by ID. If you have a private voice with the same ID as a global one, the private version wins, so you can override a default without renaming.

Path & Query

1
  • voice_idstringrequired

    The voice identifier — a UUID (preferred), from the id field returned by GET /voices; legacy voice_key slugs are still accepted.

Errors

1
404Voice not found

No voice with this ID is available on your account.

Re-list with GET /voices to pick a currently-available ID.

POST/voices/preview

Hear a voice. Returns a short WAV file.

Preview Voice

Synthesizes a short audio sample so you can hear what a voice sounds like before wiring it up to an agent. Returns a complete audio/wav file. Any voice on your account works; pick any id from GET /voices.Not a free TTS endpoint. The preview caps text at 300 characters and bills at the same per-character rate as POST /tts. For anything longer or production audio, use POST /tts.

Request body

2
  • voice_idstringrequired

    The voice you want to hear. Use any id from GET /voices (a UUID or legacy voice_key). The sentinel "default" is not accepted on this endpoint.

  • textstringoptional

    What the voice should say. 1–300 characters. Defaults to "Hello, this is a sample of my voice."

Errors

3
404Voice not found

The voice_id is not available on your account.

Pick a voice id from GET /voices (a UUID or legacy voice_key). The sentinel "default" is not valid here.

422Validation error

text is empty or longer than 300 characters, or voice_id is missing.

Keep text between 1 and 300 characters. For longer audio, use POST /tts.

429Rate limited

You hit your API key's rate limit.

Honor the Retry-After header and back off.

GET/voices/clone/script

Fetch what to show a speaker before they record a voice to clone.

Get the recording prompt

Returns the recording prompt in language (en or fr; any other value returns English). There is no passage to read: the speaker talks naturally, in their own words, and the recording is not checked against any text. text is the prompt to show them, estimated_duration_seconds a typical recording, and min_duration_seconds the least speech a recording must hold once silence at its start and end is trimmed. consent_statement is what every clone attests to, in the prompt's language, and consent_version names that text: show it to the speaker before recording, and send consent as true only once they agree. Requires voices:read.

Path & Query

1
  • languagestringoptional

    en (default) or fr.

POST/voices/clone

Upload a WAV of someone speaking and get back a clone job.

Clone a voice

Starts a clone job from a recording of the speaker talking naturally, in their own words. Send multipart/form-data with the recording as audio: a PCM WAV of 10 to 60 seconds, recorded at 8 to 48 kHz, at most 25 MiB. Record somewhere quiet, close to the microphone; 15 to 30 seconds of speech works well.Every clone needs the speaker's permission. Send consent as true to confirm the consent_statement from GET /voices/clone/script: the voice is your own, or its owner gave you permission to clone it. The job records when you confirmed it, which statement, and with which key.The job checks the recording (its level, background noise, clipping, and how much speech it holds), builds the voice, and speaks a test sentence with it. Poll GET /voices/clone/{job_id}, or pass webhook_url to be notified when the job ends. Once status is completed, its voice_id works anywhere a voice does on your account: POST /tts, agents and calls. Each account runs up to 3 clone jobs at a time.A completed clone costs 5 credits. Requires voices:write.

Request body

5
  • audiobinaryrequired

    The recording: a PCM WAV of 10 to 60 seconds, recorded at 8 to 48 kHz, at most 25 MiB.

  • namestringrequired

    A name for the voice, unique among your clones that have not failed.

  • languagestringoptional

    en (default) or fr: the language the voice speaks.

  • webhook_urlstringoptional

    An HTTPS URL to notify when the job ends, with the voice_clone.completed or voice_clone.failed event, signed with your account's webhook secret. Set a webhook secret first.

Errors

7
400Invalid recording or webhook

The file is empty, is not a PCM WAV, or was recorded below 8 kHz or above 48 kHz, or webhook_url was sent while the account has no webhook secret.

Send a 16-bit PCM WAV recorded at 8 to 48 kHz. Set a webhook secret before passing webhook_url.

403Cloning not allowed

The key does not carry voices:write, or your plan does not include voice cloning.

Create a key with voices:write. If the message names your plan, contact support.

409Name already used

Another clone of yours with this name is pending, processing or completed.

Pick another name, or delete the clone that holds it.

413Recording too large

The file is larger than 25 MiB.

Record a shorter take, or at a lower sample rate.

422Recording too short or too long

The recording is under 10 seconds or over 60 seconds.

Record 15 to 30 seconds of speech. min_duration_seconds from GET /voices/clone/script is the floor.

422Consent not confirmed

consent is missing or not true.

Show the speaker the consent_statement from GET /voices/clone/script, and send consent as true once they agree.

429Clone limit reached

Your account already has 3 clone jobs running or has reached the number of clones its plan allows, or voice cloning is at capacity for the language.

Wait for a job to finish or delete a clone you no longer need. At capacity, try again later.

POST/voices/clone/by-upload

Start a clone job from a recording staged with a presigned upload.

Clone a voice from an upload

Use this when the recording was staged through POST /uploads/presign with kind: "audio/voice-clone" (WAV only, at most 25 MiB). Send the returned upload_id with the same fields as POST /voices/clone, consent included; the job, its checks and its billing are the same. The staged file is consumed once the job is created or the request is refused; a server error leaves it in place so you can retry. Requires voices:write.

Request body

5
  • upload_idstringrequired

    The upload_id returned by POST /uploads/presign for an audio/voice-clone upload.

  • namestringrequired

    A name for the voice, unique among your clones that have not failed.

  • languagestringoptional

    en (default) or fr: the language the voice speaks.

  • webhook_urlstringoptional

    An HTTPS URL to notify when the job ends, with the voice_clone.completed or voice_clone.failed event, signed with your account's webhook secret. Set a webhook secret first.

Errors

5
403Cloning not allowed

The key does not carry voices:write, or your plan does not include voice cloning.

Create a key with voices:write. If the message names your plan, contact support.

409Name already used

Another clone of yours with this name is pending, processing or completed.

Pick another name, or delete the clone that holds it.

422Upload or recording rejected

The upload_id is unknown, expired or for another kind, or the recording is under 10 or over 60 seconds.

Presign a new audio/voice-clone upload and record 15 to 30 seconds of speech.

422Consent not confirmed

consent is missing or not true.

Show the speaker the consent_statement from GET /voices/clone/script, and send consent as true once they agree.

429Clone limit reached

Your account already has 3 clone jobs running or has reached the number of clones its plan allows, or voice cloning is at capacity for the language.

Wait for a job to finish or delete a clone you no longer need. At capacity, try again later.

GET/voices/clone/:job_id

Poll a clone job until it is `completed` or `failed`.

Get a clone job

status moves from pending to processing, then to completed or failed; most jobs finish within a couple of minutes. On completed, voice_id is the new voice.clean_duration_s is how much speech the recording held once edge silence was trimmed. wer is set only on jobs from before recordings became free speech, and is null otherwise. Listen to the voice before you rely on it.On failed, error_code says why and error_message what to do. clipping, too_quiet, low_snr (background noise), too_short and unsupported_audio (the recording could not be read) mean recording again. billing_blocked and billing_failed mean the account needs credits. probe_unavailable, publish_failed, capacity_timeout, timed_out and internal_error are on our side: try again later. Requires voices:read.

Path & Query

1
  • job_idstringrequired

    The id of the clone job.

Errors

1
404Clone job not found

No clone job with this id exists on your account.

Use the id returned when the job was created.

DELETE/voices/clone/:job_id

Delete a clone job, the voice it made and its recording.

Delete a clone

Deletes the job, the voice it produced and the stored recording; the voice stops working at once. Refused while the job is still running, or while one of your agents uses the voice. Requires voices:write.

Path & Query

1
  • job_idstringrequired

    The id of the clone job.

Errors

2
404Clone job not found

No clone job with this id exists on your account.

Use the id returned when the job was created.

409Clone in use

The job is still pending or processing, or an agent uses the voice. The message names the agents.

Wait for the job to finish, or move those agents to another voice, then delete again.