Learn how to turn audio into text, and text into speech, with the June API.
Both endpoints follow OpenAI's audio API, so the OpenAI SDKs work unchanged: point the client at June's base URL, as in the Quickstart, and call audio.transcriptions or audio.speech.
Models & Voices
Query https://api.blockchain.info/ai/api/v1/audio/models to see the available models.
Each entry has a type: TRANSCRIPTION models turn audio into text, and SPEECH models turn text into audio.
curl https://api.blockchain.info/ai/api/v1/audio/models \
-H "Authorization: Bearer $JUNE_API_KEY"
A truncated example response:
{
"models": [
{
"type": "TRANSCRIPTION",
"id": "openai/whisper-large-v3-turbo",
"label": "Whisper Large v3 Turbo",
"formats": ["wav", "mp3", "ogg", "flac", "webm", "m4a", "aac"],
"maxFileBytes": 10000000
},
{
"type": "SPEECH",
"id": "hexgrad/kokoro-82m",
"label": "Kokoro 82M",
"voices": [
{ "id": "af_heart", "label": "Heart", "description": "Female, American English" },
{ "id": "bm_george", "label": "George", "description": "Male, British English" }
],
"defaultVoice": "af_heart",
"sampleRate": 24000,
"maxInputCharacters": 20000,
"responseFormats": ["wav", "pcm"]
}
]
}
Voices are specific to each model. OpenAI's voice names, such as alloy, won't work: pick a voice from the model's voices list, or leave it out to use the model's defaultVoice.
Transcribing Audio
Send the recording to https://api.blockchain.info/ai/api/v1/audio/transcriptions as multipart/form-data, with the audio in a file part and the model ID in model.
The audio must be one of the model's formats and no larger than maxFileBytes.
You can also send:
language: the language spoken, as an ISO-639-1 code such asenorfr. The model detects it if you leave it out.response_format:json(the default) returns{ "text": "..." }, andtextreturns the transcript as plain text.
prompt and temperature are accepted but have no effect. Options that change what comes back, such as verbose_json, srt, timestamps or streaming, are rejected with a 400.
curl https://api.blockchain.info/ai/api/v1/audio/transcriptions \
-H "Authorization: Bearer $JUNE_API_KEY" \
-F [email protected] \
-F model=openai/whisper-large-v3-turbo
# => { "text": "Remind me to call the bank tomorrow morning." }A transcription costs what the model charges for the recording's length. Your balance is checked against the longest the recording could be before the request is sent to the model.
Generating Speech
POST JSON to https://api.blockchain.info/ai/api/v1/audio/speech with the model, the input text (up to maxInputCharacters), and optionally a voice.
The audio streams back as it is generated, so you can start playing it before the whole input has been read.
response_format sets the audio format:
wav(the default): a WAV file. Because it is streamed, its header doesn't give a length. Most players and decoders handle this, but some editors report the duration as unknown.pcm: raw 16-bit little-endian mono samples with no header, at the model'ssampleRate. Unlike OpenAI'spcm, which is always 24 kHz, this rate depends on the model.
mp3, opus, aac and flac aren't supported, and nor are instructions or any speed other than 1.
curl https://api.blockchain.info/ai/api/v1/audio/speech \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $JUNE_API_KEY" \
-d '{
"model": "hexgrad/kokoro-82m",
"voice": "af_heart",
"input": "Your package has been delivered."
}' \
--output speech.wavStreaming as Events
Set stream_format to sse to receive the audio as server-sent events instead of raw bytes.
Each speech.audio.delta event carries the next chunk of the file, base64-encoded. Decode and join the chunks in order to get the same bytes a raw response would contain.
The stream ends with a speech.audio.done event:
data: {"type":"speech.audio.delta","audio":"UklGRv////9XQVZF..."}
data: {"type":"speech.audio.delta","audio":"AAABAAIAAwAEAP7/..."}
data: {"type":"speech.audio.done"}
Billing and Errors
The cost of the whole input is reserved when the request starts. If it doesn't fit in your balance, the request fails with a 402 before any audio is generated.
You're charged for the text that is spoken. If you disconnect partway through, the parts that hadn't started generating are refunded.
An error before any audio is sent comes back as a normal JSON error. If the model fails after the audio has started, a raw stream ends early, and an SSE stream ends with an error event instead of speech.audio.done:
data: {"type":"error","error":{"message":"Something went wrong with this voice model. Please try again or switch models.","type":"server_error","code":"server_error"}}