Actors and voices
List the actors and voices you can use, get their ids, pass them into a submit.
Read as MarkdownFind who speaks and in what voice. You get ids and facets, then pass the ids into a submit.
| Endpoint | Returns | Pages |
|---|---|---|
GET /actors | Actors this workspace may use | yes |
GET /voices | Voices this workspace may use | yes |
- Scope
read. Every live key has it. - Rate bucket
agent_read: 120 calls a minute per key, shared with other reads.
Brands and products have no API
Brands, products, new actors and new voices are made in the app at app.riffads.com. There is no REST, MCP or CLI route to create or read them.
Actors
GET/api/v1/actorsAPI key
The RiffAds cast plus the active actors your workspace made. Actors still processing, or disabled, are hidden.
| Parameter | Type | Default | Notes |
|---|---|---|---|
search | string | none | Name or description, case insensitive. % and _ are literal |
limit | integer | 25 | Clamped to 1 to 50. A page holds at most 48, so 49 and 50 return 48. limit=1000 gets a page, not an error |
cursor | string | none | The previous next_cursor, sent back exactly |
No other params. No gender, tag or age filter: match gender, age_band and tags yourself.
curl -sG https://app.riffads.com/api/v1/actors \
-H "Authorization: Bearer $RIFFADS_API_KEY" \
--data-urlencode "search=warm" \
--data-urlencode "limit=50"{
"ok": true,
"actors": [
{
"actor_id": "act_0193c8f0a1b24e7f9d3c5a6b7e8f0011",
"name": "Maya",
"description": "Warm, direct, speaks to camera at home",
"gender": "female",
"age_band": "adult",
"tags": ["kitchen", "morning", "standing", "casual"],
"default_voice_id": "voc_0193c8f0a1b24e7f9d3c5a6b7e8f0022",
"default_voice_name": "Maya (natural)",
"is_platform": true
}
],
"next_cursor": "eyJpc09yZyI6ZmFsc2UsImlzQ29yZSI6dHJ1ZSwiY3JlYXRlZEF0IjoiMjAyNi0wOS0wMVQxMDoxMjowMFoiLCJpZCI6ImFjdF8wMTkzIn0"
}Prop
Type
- Order: your actors first, then the core cast, then the rest. Newest first in each group.
- No
total. The body has onlyok,actorsandnext_cursor. Page untilnext_cursorisnull. - Plan gated. Higher plans see more of the cast. Your own actors are always listed.
No faces over the API
No preview image or clip comes back, ever. You get the id and the facets. To see faces, open app.riffads.com.
Voices
GET/api/v1/voicesAPI key
The RiffAds voice library plus voices your workspace cloned or designed. Active only, sorted by name.
| Parameter | Type | Default | Notes |
|---|---|---|---|
search | string | none | Name only, case insensitive. Tags are not searched |
language | string | none | Exact tag, like en or es. Not a prefix |
limit | integer | 25 | Clamped to 1 to 50 |
cursor | string | none | The previous next_cursor, sent back exactly |
curl -sG https://app.riffads.com/api/v1/voices \
-H "Authorization: Bearer $RIFFADS_API_KEY" \
--data-urlencode "language=en"{
"ok": true,
"voices": [
{
"voice_id": "voc_0193c8f0a1b24e7f9d3c5a6b7e8f0022",
"name": "Maya (natural)",
"language": "en",
"gender": "female",
"tags": ["young_adult", "american", "conversational"],
"is_cloned": false,
"is_premium": false,
"is_platform": true
}
],
"total": 61,
"next_cursor": "25"
}Prop
Type
totalcounts matches before paging.GET /actorshas nototal.- No preview audio comes back.
- Cloned voices have no language and no gender. A
languagefilter misses them. Find them by name.
The two cursors differ. Treat both as opaque.
The actor cursor is a base64url keyset. The voice cursor is an offset as a string. Send next_cursor back exactly, never build one. A bad cursor restarts from the top, not an empty page. Conventions.
From ids to a submit
actor_id and voice_id go at the top level of the submit body, not in config:
{
"capability_id": "actor_ultra",
"actor_id": "act_0193c8f0a1b24e7f9d3c5a6b7e8f0011",
"voice_id": "voc_0193c8f0a1b24e7f9d3c5a6b7e8f0022",
"approved_voice_generation_id": "gen_0193c8f0a1b24e7f9d3c5a6b7e8f0044",
"config": { "script": "Two weeks in, and I am not going back." },
"max_credits": 660
}- A talking actor is 2 generations. First
tts, thenactor_ultrawith thettsgeneration_idasapproved_voice_generation_id. Script, actor and voice must match thettsjob. Talking actor guide. voice_idis optional when the actor has adefault_voice_id.- Body
voice_idand configvoiceIdare different layers. Readconfig_schemafromGET /capabilities/{capability_id}. - Another workspace's id answers
404 not_found, same as a missing id. Neverforbidden.
Errors
Standard error envelope. See conventions.
| Code | HTTP | Retryable | Cause |
|---|---|---|---|
not_authorized | 401 | no | No key, revoked, or unknown |
rate_limited | 429 | yes | Over 120 agent_read calls a minute. Carries retry_after_seconds and Retry-After |
quota_exceeded | 429 | no | Key used its request allowance. Waiting a bit won't help |
required_plan | 403 | no | Plan doesn't include the agent API |
workspace_unavailable | 410 | no | Workspace deleted |
internal_error | 500 | yes | Our fault. Try again |
A balance internal_error says so, so it never reads as an empty wallet:
{
"error": {
"ok": false,
"code": "internal_error",
"message": "We could not read this workspace's credit balance. This is not a balance problem: try again.",
"retryable": true,
"credits_charged": 0
}
}MCP: list_actors and list_voices take the same params and return the same shape. MCP tools.