Skip to main content

Grok STT and TTS API: Transcribe, Narrate and Download

Try Grok STT and TTS in the Playground, then script a transcription-to-narration flow with stereo fixes, delivery tags and USD prices for adult audio.

Author
Lydia
Published
Read
8 min read
Updated
Two adults on an old stone and iron footbridge at golden hour, one holding a small audio recorder

Use Grok STT to transcribe an existing recording and Grok TTS to read a script in a preset voice. Try both in the SpicyAPI Playground first, then call them from code or an Agent. This is a saved-file workflow; for live back-and-forth voice you need a realtime transport. STT costs about $0.002 per minute of audio; TTS costs $0.018 per 1,000 characters. Based on our September 2026 tests, both routes handle adult recordings and scripts as written, with no refusals, masking or cut-off clips.

Prices, limits and what each route returns

Grok STTGrok TTS
Model IDxai/grok-stt/speech-to-textxai/grok-tts/text-to-speech
InputAudio URL, or an uploaded MP3/WAV up to 90 MB and 10 minutes; 1 second to 2 hoursText, 1–15,000 characters
Languages25, or auto-detect20 plus auto-detect
Rate$0.0000333334 per second$0.018 per 1,000 characters
ResultText plus word-timed transcriptOne audio file
Kept forUploaded audio 1 dayGenerated audio 14 days
Not availableSpeaker labelsVoice cloning or reference-voice input

A longer or larger recording needs a public URL. A URL can also point to M4A, FLAC, OGG, Opus, AAC, MP4 or MKV, but it must return the audio file itself, not a player or share page. Headerless PCM, μ-law and A-law are not accepted by STT.

An hour of audio costs about $0.12, and a 90-second recording about $0.003. The task first holds the two-hour maximum, about $0.24, and frees the difference once the real length is known. A 1,800-character script costs $0.0324; two full takes plus a 240-character pickup cost $0.06912. Spaces, punctuation and delivery tags all count as characters, and the quote shown before a TTS run is the final charge.

Try it in the Playground first

Transcribe. Open the Grok STT page and stay on the Playground tab.

  1. Under Input audio, upload your MP3 or WAV (up to 90 MB) or switch to Asset URL and press Add URL for a recording hosted elsewhere.
  2. Open Advanced parameters only if you need Language, Normalize text, Key terms, Keep filler words or Transcribe channels separately.
  3. Check the price estimate, then log in and run. The transcript appears in the Output panel, with a JSON view for the word timings.

Narrate. Open the Grok TTS page.

  1. Paste or edit the script in Text (the Sample script button fills an example), with any delivery tags.
  2. Choose a Voice; the menu labels each with name, gender and language. Open Advanced parameters for Speed, Output format, Bitrate and Language.
  3. Run it, play the take in the Output panel and use Download to keep it.

Try your hardest name or line here before you script a whole narration; what sounds wrong in the Playground will sound wrong from the API.

Transcription switches that change the result

Language (language) can be left out for detection. Normalize text (text_normalization) writes numbers, prices and dates as digits ("March 14", "$1,250") and requires language; leave it off when you need the exact spoken wording.

Keep filler words (filler_words: true) keeps "um" and "uh", which are dropped by default. Key terms (keyterms) bias spelling toward invented names and brands, up to 100 terms of 50 characters. Send them as objects, [{"term":"Mara"},{"term":"Jon"}], not as plain strings.

Transcribe channels separately (multichannel: true) transcribes each channel of a file separately, up to eight. With it off, a stereo recording with a different speaker on each side can come back with one speaker missing. Read output.transcript.channels for each side's words and timings; the combined text is one line per channel, not a finished dialogue. It does not separate two people mixed into one mono channel, and the route returns no speaker labels, so use separately recorded channels or a diarization tool for mono interviews.

Then call it from code

Install the Python SDK (pip install spicyapi, Python 3.11+), set SPICY_API_KEY, and run this transcription-to-narration flow. Replace the file path with a recording you are authorized to use.

python
import uuid

from spicyapi import SpicyClient, output_assets

client = SpicyClient()  # reads SPICY_API_KEY from the environment

# 1. Transcribe a local recording (uploads are free and kept for one day)
source = client.upload_file("./interview.mp3")
stt = client.create_task(
    model="xai/grok-stt/speech-to-text",
    input_data={"audio_url": source["uri"], "multichannel": True},
    idempotency_key=str(uuid.uuid4()),  # new key per new request; reuse only to retry the same one
)
done = client.wait_for_terminal(stt["taskId"])
if done["state"] != "succeeded":
    raise RuntimeError(f"STT task {stt['taskId']} ended as {done['state']}")
print(done["output"]["text"])  # edit this into your script

# 2. Narrate the edited script
script = "Chapter Three. The storm kept them in the cabin. [breath] <slow>Neither of them pretended to be reading.</slow>"
tts = client.create_task(
    model="xai/grok-tts/text-to-speech",
    input_data={"text": script, "voice_id": "rex", "language": "en", "speed": 0.9},
    idempotency_key=str(uuid.uuid4()),  # new key per new request; reuse only to retry the same one
)
final = client.wait_for_terminal(tts["taskId"])
if final["state"] != "succeeded":
    raise RuntimeError(f"TTS task {tts['taskId']} ended as {final['state']}")

# 3. Copy the MP3 link to your own storage now; generated audio is kept for 14 days
print(output_assets(final)[0]["url"])

Reuse an idempotency key only to retry the same request after a lost response. Uploads, waiting, errors, retries and renewing an expired download link are in the Python SDK reference and the task guide.

Or let an Agent run it

If an assistant should do the transcribing and narrating for you, give it the CLI or the MCP server. Both show the price and ask you to confirm before a paid call. The Skill adds instructions on top of either.

  • CLI. spicyapi runs one task from a terminal (npx @spicyapi/cli works without installing):

``bash spicyapi files upload ./interview.mp3 # prints a spicy:// URI spicyapi tasks create --model xai/grok-stt/speech-to-text \ --input-json '{"audio_url": "spicy://YOUR-UPLOAD-URI", "multichannel": true}' --wait ``

  • MCP server. Add the MCP server to your assistant, then ask: "Transcribe ./interview.mp3 with Grok STT, with each channel separate." It calls spicyapi_upload_file, then spicyapi_task_create (which stops for your price confirmation), then spicyapi_task_wait.

``json { "mcpServers": { "spicyapi": { "command": "npx", "args": ["--yes", "--package=@spicyapi/mcp", "spicyapi-mcp"], "env": { "SPICY_API_KEY": "YOUR_SPICY_API_KEY" } } } } ``

  • Skill. npx skills add spicyapi-ai/spicy-skill installs the Agent Skill, which teaches a coding assistant to read the live schema and reuse idempotency keys. It cannot run tasks by itself, so use it with the CLI or MCP.

From transcript to script to voice

Edit the transcript before synthesis: fix names, punctuation and anything you want read differently. A short keyterm list is worth adding for invented names, but the transcript still reflects what the recording says, so check names against the audio.

TTS has 71 preset voices. eve is the default; eve, ara, leo, rex and sal speak every supported language, while the other 66 are tuned for one language and appear as opaque IDs in the API. Pick them from the voice menu on the Grok TTS model page, which labels each with name, gender and language. Try a short passage with your hardest name before synthesizing a whole narration.

Delivery is written into the script. Inline tags make a sound where you place them: [pause], [long-pause], [breath], [inhale], [exhale], [sigh], [laugh], [chuckle], [giggle], [cry]. Wrapping tags change how the enclosed words are read: <whisper>, <soft>, <slow>, <loud>, <build-intensity> and others. Tags are performed, not read aloud, but they count toward the price. For example:

json
{"text": "Chapter Three. The storm kept them in the cabin for two more days. [breath] By the second night, <slow>neither of them pretended to be reading anymore.</slow>", "voice_id": "rex", "speed": 0.9, "language": "en"}

speed runs from 0.7 to 1.5. bitrate applies only to MP3. Use MP3 for playback and WAV for editing; raw pcm, mulaw and alaw at 8 kHz are for phone systems and will not play in a browser. SSML is not supported; use the tags above.

For a two-character scene, synthesize each speaker's lines separately with different voices and edit them together; one request reads one voice. Keep natural pauses at the joins instead of trimming them to zero.

To check a take, run the generated audio back through STT and compare it with the script: obvious missing or changed words, a cut-off ending or a tag spoken aloud usually show up, and a short clip costs a fraction of a cent. Then listen to the opening, the ending and any line it flags. If Grok's presets are not enough, see the other TTS options.

Common problems and fixes

SymptomFix
Only one side of a stereo call appearsEnable multichannel and read output.transcript.channels
Two mono speakers cannot be separatedRecord on separate channels or use a diarization tool
keyterms rejectedSend objects with a term key, at most 100
Normalization request rejectedAdd a supported language code
MP3 bitrate rejected for WAVOmit bitrate
Raw audio will not playUse MP3 or WAV, or configure the raw format and sample rate in your player
STT rejects a URLIt must return the audio file itself, not an HTML page
Download link expiredQuery the same task again for a fresh asset URL
Download returns 403Send a User-Agent header; the default Python one is blocked
Task still shows runningKeep waiting on the same task ID; do not create a replacement job

STT word timestamps belong to the original recording. TTS returns audio without word timings, so changing the text or speed invalidates the old timestamps; align subtitles to the finished synthesized take.

Also in 日本語 · 한국어 · Deutsch · Français · Español · Português (Brasil) · Русский · Italiano · Polski

Try it yourself

Pay only for what you run — no plan, no subscription.

Made with MiniMax H3 · ByteDance Seedance 2.0 Fast