Voice
Give your agent a voice — text in, MP3 out. Part of the GenieTé suite: one account, shared credits, at account.geniete.com.
Five minutes to first words
- Sign in once at the console — every GenieTé account starts with a free monthly credit allowance, no card needed.
- Create a speaker (one button). Copy its API key — shown once.
- Speak:
curl -sS https://voice.geniete.com/public/api/speak \ -H "Authorization: Bearer $VOICE_API_KEY" -H "Content-Type: application/json" \ -d '{"speaker_id":"'$SPEAKER_ID'","voice_id":"kanika","text":"Hello, world — out loud.","deliver":"url"}' - Open the returned
urlin any browser. That's it — you just gave your code a voice, and the link plays for anyone you send it to.
From here on, that key works from anywhere with an internet
connection — a cron job, a CI runner, a Raspberry Pi, a phone shortcut. No
server, no MP3 shuffling, no audio stack. Prefer Python?
pip install geniete-voice — open source at
github.com/geniete/clients;
AI agents can use the suite MCP server (uv tool install geniete-mcp).
Pick your delivery mode
One endpoint, four ways to receive — choose per request:
| You want… | Send | You get | Best for |
|---|---|---|---|
| the audio itself | (nothing extra) | MP3 bytes in the response | your code plays or processes the sound |
| a link to share | "deliver":"url" | a hosted URL (kept ~1 day) | chat messages, dashboards, narrated screens — no hosting on your side |
| a room to just talk | "return_audio":false | a tiny JSON ack | pumping speech to speaker pages you've left open — fire and forget |
| streamed frames | the WebSocket | binary MP3 as it generates | lowest-latency playback in your own app |
What Voice is (and where the sound comes out)
Voice is the speech organ for your agent stack: your code sends text, Voice returns MP3 audio. That's the whole contract — and it's deliberate. Where the audio plays is your choice: take the MP3 bytes yourself (pipe to a device, attach to a notification, save as a build artifact, narrate an AgentScreen) — or skip audio handling entirely and let a speaker page do the talking anywhere you've left one open.
A speaker is a keyed endpoint you create in the console — one per agent, app, or context. Each has its own API key (rotatable, revocable on the shared authorization plane) and its own usage trail, so "the deploy bot" and "the morning digest" stay separate identities even though they share your credits.
The speaker page — leave it on
Every speaker can have a live page: mint a listen link, open it on any device — a wall tablet, the office Mac, your phone — and leave it there. From then on, every speech you pump into that speaker plays on the page, live. A freshly opened page replays the speaker's last utterance, so it's never mute. While a page is open it holds a connection — 1 credit per 10 minutes to the speaker's owner (the rate card row), same as every live connection in the suite.
# mint a shareable listen link (owner key, default 30 days)
# optional: "ttl_seconds" bounds the link's life (1 hour – 90 days)
curl -sS -X POST https://voice.geniete.com/public/api/speakers/$SPEAKER_ID/listen-links -H "Authorization: Bearer $VOICE_API_KEY" -d '{"ttl_seconds": 86400}'
# → {"url": "https://voice.geniete.com/public/speakers/spk_…?t=lt_…", …}
# then, at any time, from anywhere — no audio handling in your code:
curl -sS https://voice.geniete.com/public/api/speak -H "Authorization: Bearer $VOICE_API_KEY" -H "Content-Type: application/json" -d '{"speaker_id":"'$SPEAKER_ID'","voice_id":"kanika",
"text":"Build 512 is green.","return_audio":false}'
# every open listen page for this speaker says it out loud
One link = one seat: opening a listen link in a new window moves the listening there — the previous window goes quiet and says so. Mint one link per device you want speaking simultaneously.
Idle pages close themselves: a listen page that hears nothing for 30 minutes disconnects (and says so) instead of holding a billed connection open for silence. One reload resumes listening.
"return_audio": false is pump mode: the response is a small
JSON ack (charge + characters) instead of the MP3 — your agent fires and
forgets; the rooms do the talking. Listen links and speaker pages are
free; you pay only for the speech itself.
Hosted links — no server required
Don't have anywhere to put an MP3? Add "deliver": "url" and
Voice hosts it for you: the response carries a direct link on the
GenieForge asset server — embeddable, shareable, streamable into any
<audio> tag — kept for about a day, then cleaned up
automatically. The link path is unguessable (it IS the access control),
so share it only with whoever should hear it.
curl -sS https://voice.geniete.com/public/api/speak -H "Authorization: Bearer $VOICE_API_KEY" -H "Content-Type: application/json" -d '{"speaker_id":"'$SPEAKER_ID'","voice_id":"kanika",
"text":"Sixty-second summary of today's run…","deliver":"url"}'
# → {"status":"spoken","url":"https://assets.genieforge.com/public/geniete/stage/voice/spk_…/…mp3",
# "url_retention_days":1,"charged_credits":5,…}
Rate card
| Action | Cost |
|---|---|
speak (per utterance) | 1 credit per 10 characters, rounded up, minimum 1 |
| examples | "Deploy finished." (16 chars) = 2 · a tweet-length line (280) = 28 · the 4,000-char maximum = 400 |
hosted link (deliver:"url", ~1 day) | free |
| open connection — speak or listen (per 10 minutes, billed to the speaker's owner) | 1 credit |
| minting listen links | free |
| Free plan daily ceiling (demo tier) | 400 characters · 5 speeches / day |
Charged only on success — a failed generation costs nothing, and your
request_id is the idempotency key, so a retry of the same
utterance never double-charges. Credits are the shared GenieTé balance;
plans, top-ups, and your monthly free allowance live at
account.geniete.com. Plans
differ in capacity (queue depth, concurrent connections) — every voice is
available on every plan.
HTTP reference
The one endpoint (see the walkthrough to get a key):
curl -sS https://voice.geniete.com/public/api/speak \
-H "Authorization: Bearer $VOICE_API_KEY" \
-H "Content-Type: application/json" \
-d '{"speaker_id":"'$SPEAKER_ID'","voice_id":"kanika","text":"Deploy finished. All checks green."}' \
-o speech.mp3
The response body is the MP3. Headers carry X-Voice-Charged-Credits
and X-Voice-Characters.
WebSocket
wss://voice.geniete.com/public/ws/speak
→ {"api_key":"vk_…","speaker_id":"spk_…"} (first frame = auth)
← {"type":"connected","speaker_id":"spk_…"}
→ {"type":"speak","request_id":"r1","voice_id":"kanika","text":"…"}
← {"type":"queued","request_id":"r1","position":2}
← {"type":"generating","request_id":"r1"}
← <binary MP3 frames>
← {"type":"done","request_id":"r1","bytes":183210,"charged_credits":19,"characters":184}
One job in flight per connection. request_id is yours —
it is also the charge-idempotency key, so a retry after a dropped
connection can never double-charge.
Voices
GET /public/api/voices lists the curated voices — the full roster
is available on every plan, Free included.
Integration recipes
1. Say it out loud when the job finishes
The classic: your agent completes something long-running and the room hears it.
# at the end of your agent's run
curl -sS https://voice.geniete.com/public/api/speak \
-H "Authorization: Bearer $VOICE_API_KEY" -H "Content-Type: application/json" \
-d '{"speaker_id":"'$SPEAKER_ID'","voice_id":"kanika","text":"Backtest complete. Sharpe one point four. Two anomalies flagged."}' \
-o /tmp/done.mp3 && afplay /tmp/done.mp3 # afplay = macOS; use mpg123/mpv on Linux
2. A speak() function for your agent (Python)
import requests
def speak(text: str, voice: str = "kanika") -> bytes:
"""Returns MP3 bytes. Raises for over-limit or out-of-credit."""
r = requests.post(
"https://voice.geniete.com/public/api/speak",
headers={"Authorization": f"Bearer {VOICE_API_KEY}"},
json={"speaker_id": SPEAKER_ID, "voice_id": voice, "text": text[:4000]},
timeout=120,
)
r.raise_for_status()
return r.content # play it, save it, ship it
open("digest.mp3", "wb").write(speak("Good morning. Three PRs merged overnight."))
3. As a tool your LLM agent can call
Give the model a voice the same way you give it any tool:
{
"name": "speak",
"description": "Say something out loud to the operator. Use for completions, alerts, and anything worth hearing rather than reading. Keep it under a few sentences.",
"parameters": {
"type": "object",
"properties": {
"text": {"type": "string", "description": "What to say (max 4000 chars)"},
"voice": {"type": "string", "enum": ["kanika", "intercom", "callum", "jean-jacque", "adam", "james"]}
},
"required": ["text"]
}
}
The tool handler is recipe #2's speak() plus your playback of choice.
4. Narrated screens — Voice × AgentScreen
The two products compose: show the chart, speak the takeaway — no hosting on your side, thanks to hosted links.
r = requests.post("https://voice.geniete.com/public/api/speak",
headers={"Authorization": f"Bearer {VOICE_API_KEY}"},
json={"speaker_id": SPEAKER_ID, "voice_id": "kanika",
"text": "Requests per minute doubled in the last hour. All healthy.",
"deliver": "url"})
requests.post("https://screens.geniete.com/public/api/publish",
headers={"Authorization": f"Bearer {SCREEN_KEY}"},
json={"screen_id": SCREEN_ID, "event": {
"type": "content.url", "title": "hear the summary",
"url": r.json()["url"],
"body": "60-second spoken takeaway of the chart above."}})
5. Nightly digest as a build artifact
# cron / CI step
python make_digest.py | head -c 4000 > digest.txt
curl -sS https://voice.geniete.com/public/api/speak \
-H "Authorization: Bearer $VOICE_API_KEY" -H "Content-Type: application/json" \
-d "$(jq -n --rawfile t digest.txt '{speaker_id: env.SPEAKER_ID, voice_id: "james", text: $t}')" \
-o artifacts/digest-$(date +%F).mp3
Processing
Requests are queued and processed in order — you see live
queued position updates, then generating, then your audio.
Per-plan capacity: simultaneous queued jobs (Free 1 · Starter 2 · Pro 5 · Team 10)
and concurrent connections (same numbers). If capacity is momentarily full you get
an honest queue_full — retry shortly.
FAQ
| Do I need a server? | No. deliver:"url" hosts the MP3 for you; speaker pages play it live on any device. |
| Who can call the API? | Anyone holding a speaker API key, from anywhere on the internet. Keys are created in the console, shown once, rotatable anytime. |
| What does it cost? | Speech: 1 credit / 10 characters; open connections (speak or listen): 1 credit / 10 min (rate card). Hosted links, minting, and failed generations are free. Every account gets a free monthly allowance; The Free plan is a demo tier: 400 characters and 5 speeches per day (hitting the ceiling never charges — try again tomorrow or upgrade). |
| Who hears it? | Whoever you choose: your code (bytes), anyone with the hosted link, or every device where a listen page is open. |
| Key leaked? | Rotate it in the console — the old key dies instantly (revocation is real, not cached). |
| Long text? | 4,000 characters per utterance, hard limit — split long content into utterances; this service does one utterance well. |
Errors
| Reason | Meaning |
|---|---|
text_too_long | Over 4,000 characters — split your content; this service does one utterance |
insufficient_credits | Balance can't cover the utterance — top up or upgrade |
queue_full / account_queue_full | Backpressure — retry shortly (account cap follows your plan) |
voice_unknown | Not in the voice catalog — check GET /public/api/voices |
upstream_failed | Generation failed before audio started — nothing charged, safe to retry with the same request_id |
Support
Sign in at account.geniete.com — your account pages show the support email address and the plan/balance/ledger details we'll ask about. Billing terms: genieinc.com.