Audio and video
Speech, transcription and asynchronous video generation.
| Operation | Request | Result |
|---|---|---|
/v1/audio/speech | JSON with model, input and supported voice | Audio bytes |
/v1/audio/transcriptions | Multipart model and audio file | Provider transcription result |
/v1/audio/translations | Multipart model and audio file | Provider translation result |
/v1/videos | Multipart model, prompt and supported parameters | Provider video job |
/v1/videos/{id} | GET | Scoped video status |
/v1/videos/{id}/content | GET | Completed video bytes |
Do not call response.json() on speech or video bytes. Save or stream binary responses with their returned content type. Voices, codecs, duration, resolution and reference-image support depend on the selected model's catalog constraints.
Video submissions are paid work. Cloud's worker polls the upstream job even if the initiating caller disconnects. A queued video object is not completed content; poll its status, then fetch /content after completion. IDs remain scoped to the creating project and tenant.
Audio/video prices may include seconds, input/output audio tokens, image tokens or provider cost. The task's verified billing is authoritative. Native Google prediction and long-running prediction use tasks with Google's payload format. Unsupported provider features are not automatically translated.
Live transcription uses a dedicated bounded WebSocket endpoint. The reviewed OpenAI ASR route supports transcript deltas and final usage per committed audio turn, with project authorization and exact duration billing. See live transcription for server authentication, browser tickets and session limits. Google Live and conversational Realtime remain unpublished until their separate usage contracts are reviewed.
The OpenAI live transcription guide describes transcript deltas and completed turns. Model-specific support for languages, delay, timestamps, speaker labels and audio encodings must be exposed as capabilities before a live route is offered in Cloud.
Generate Gemini 3.8 speech with Google style
Use the exact Cloud route ID, a Cloud project key, and a saved idempotency key.
This example works with the native Google schema and returns a JSON envelope
containing base64 WAV audio. The Cloud /v1/google/generateContent endpoint and
/v1beta/models/google/gemini-3.8-flash-tts:generateContent resource path accept
the same payload (the resource path supplies model).
import { randomUUID } from 'node:crypto'
import { writeFile } from 'node:fs/promises'
const key = randomUUID() // Persist before submission; reuse only for identical retries.
const response = await fetch('https://apis.cloud.feeef.org/v1/google/generateContent', {
method: 'POST',
headers: {
'x-goog-api-key': process.env.FEEEF_CLOUD_KEY,
'Content-Type': 'application/json',
'Idempotency-Key': key,
},
body: JSON.stringify({
model: 'google/gemini-3.8-flash-tts',
contents: [{ role: 'user', parts: [{
text: 'Hello. Voice generation is working.',
speech_metadata: { style: 'warm and friendly' },
}] }],
generationConfig: {
maxOutputTokens: 512,
responseModalities: ['AUDIO'],
speechConfig: { voiceConfig: { voice: 'Kore' } },
responseFormat: { audio: { mimeType: 'AUDIO_WAV', sampleRate: 24000 } },
},
}),
})
if (!response.ok) throw new Error(await response.text())
const result = await response.json()
const audio = result.candidates?.[0]?.content?.parts?.find(p => p.inlineData?.mimeType === 'audio/wav')?.inlineData
if (!audio) throw new Error('No WAV audio returned; inspect the task using X-AI-Request-Id')
await writeFile('google-speech.wav', Buffer.from(audio.data, 'base64'))
console.log(response.headers.get('x-ai-request-id'))Set a token limit large enough for your transcript, within the catalog maximum.
Cloud applies that catalog ceiling when a native Google SDK request omits
maxOutputTokens. An explicitly excessive limit is rejected. This default also
applies to Google-style text requests translated to another provider.
For two speakers, replace speechConfig.voiceConfig with
multiSpeakerVoiceConfig.speakerVoiceConfigs, and put each line in its own
parts entry with speech_metadata.speaker matching a configured speaker name:
{
"contents": [{ "role": "user", "parts": [
{ "text": "Hello Jane.", "speech_metadata": { "speaker": "Joe", "style": "cheerful" } },
{ "text": "Hello Joe.", "speech_metadata": { "speaker": "Jane", "style": "calm" } }
] }],
"generationConfig": {
"maxOutputTokens": 512,
"responseModalities": ["AUDIO"],
"speechConfig": { "multiSpeakerVoiceConfig": { "speakerVoiceConfigs": [
{ "speaker": "Joe", "voiceConfig": { "prebuiltVoiceConfig": { "voiceName": "Puck" } } },
{ "speaker": "Jane", "voiceConfig": { "prebuiltVoiceConfig": { "voiceName": "Kore" } } }
] } }
}
}Add model when submitting this body to /v1/google/generateContent. See
Google's native speech guide
for model-specific voice, delivery, language and output controls. Native fields
are preserved subject to the route's published limits.
Generate the same speech with OpenAI style
import OpenAI from 'openai'
import { randomUUID } from 'node:crypto'
import { writeFile } from 'node:fs/promises'
const ai = new OpenAI({
apiKey: process.env.FEEEF_CLOUD_KEY,
baseURL: 'https://apis.cloud.feeef.org/v1',
maxRetries: 0,
})
const key = randomUUID() // Persist before submission.
const response = await ai.audio.speech.create({
model: 'google/gemini-3.8-flash-tts',
input: 'Hello. Voice generation is working.',
voice: 'Kore',
instructions: 'warm and friendly',
response_format: 'wav',
}, { headers: { 'Idempotency-Key': key } })
await writeFile('openai-speech.wav', Buffer.from(await response.arrayBuffer()))This translated endpoint supports one voice and one delivery style. Its output
defaults to WAV when response_format is omitted; requesting MP3 is rejected.
Keep Google
style for two speakers, per-block styles, language and native output controls.
Anthropic Messages has no speech or video generation schema, so those operations
are not advertised under Anthropic style.
For asynchronous speech, send { "endpoint": "google/generateContent", "body": ... }
or { "endpoint": "audio/speech", "body": ... } to /v1/ai/tasks. Poll
GET /v1/ai/tasks/{id} without submitting again. Native Google audio is in
result.candidates[].content.parts[].inlineData; translated speech bytes are in
result._cloud_binary.data (base64), with content_type: "audio/wav".
Speech studio
Gemini 3.8 Flash TTS and Flash-Lite TTS expose a dialogue editor in the playground. Start a new dialog or use a template, select one or two speakers, and assign each speaker a voice. The voice picker searches Google's extended prebuilt library, custom voices belonging to the active Cloud project and tenant, and a Shared group of platform voices available to every project.
Each speech block has its own hand-typed delivery style (for example "warm, with a smile" or "whispering, slow"). The field appears only on routes advertising request_constraints.audio_outputs.styleDirection: { "perBlock": true, "maxChars": 500 } means every block may carry its own direction of up to 500 characters; perBlock: false means one direction applies to the whole request. Routes without styleDirection reject speech_metadata.style and OpenAI-style instructions. For compatibility, a route advertising only expressive: true is treated as { "perBlock": true, "maxChars": 500 }. For Gemini 3.8, the transcript remains in parts[].text; delivery goes in speech_metadata.style, and speaker assignment goes in speech_metadata.speaker. Expressions such as <gasp>, <laugh> and <short pause> stay inline at the intended position. Type < to open suggestions, use the arrow keys to select, Enter or Tab to insert, and Escape to dismiss. Other TTS models expose only their reviewed controls.
Previewing a speech block submits a billable generation through the same ledger as Run. Preview charges are included in the resulting request's verified billing. Custom Voice Design and Voice Replication use the separate voices API.
Speech task updates
The playground listens for project AI lifecycle notices and reads the original task when its state changes. While a task is pending, a read-only status check also runs every three seconds so speech works before realtime is activated. These checks never resubmit a generation or create another charge. Reconciliation states stop automatic checks and retain their request ID for operator review.
Speaker assignments survive switching temporarily to one-speaker mode. Unfinished
empty speech blocks are omitted from generation. Project-created voices use the
Google voiceConfig.voice field after project/tenant authorization; curated voices
continue using prebuiltVoiceConfig.voiceName.