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

  1. Sign in once at the console — every GenieTé account starts with a free monthly credit allowance, no card needed.
  2. Create a speaker (one button). Copy its API key — shown once.
  3. 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"}'
  4. Open the returned url in 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…SendYou getBest for
the audio itself(nothing extra)MP3 bytes in the responseyour 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":falsea tiny JSON ackpumping speech to speaker pages you've left open — fire and forget
streamed framesthe WebSocketbinary MP3 as it generateslowest-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,…}
The one hard limit: requests longer than 4,000 characters are rejected, never chunked or stitched — long-form synthesis audibly degrades and is deliberately out of scope. One utterance, done well.

Rate card

ActionCost
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 linksfree
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

ReasonMeaning
text_too_longOver 4,000 characters — split your content; this service does one utterance
insufficient_creditsBalance can't cover the utterance — top up or upgrade
queue_full / account_queue_fullBackpressure — retry shortly (account cap follows your plan)
voice_unknownNot in the voice catalog — check GET /public/api/voices
upstream_failedGeneration 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.