Feeef Cloud
AI API

Audio and video

Speech, transcription and asynchronous video generation.

OperationRequestResult
/v1/audio/speechJSON with model, input and supported voiceAudio bytes
/v1/audio/transcriptionsMultipart model and audio fileProvider transcription result
/v1/audio/translationsMultipart model and audio fileProvider translation result
/v1/videosMultipart model, prompt and supported parametersProvider video job
/v1/videos/{id}GETScoped video status
/v1/videos/{id}/contentGETCompleted 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.

On this page