Skip to content

Music & Audio

Audio generation and processing. Generate original music tracks and sound effects from text descriptions, convert text to natural-sounding speech with multiple voice options, and transcribe audio to text. Translation and dubbing are built by composing these endpoints — see the Dubbing Pipeline.

CapabilityDescriptionDuration/Limits
MusicAI composition (MiniMax, ElevenLabs)10–300 seconds
SFXSound effects1–30 seconds
TTSText-to-speech (IDA Voice, Google, Grok, Polly, GPT Audio)max 3000 chars/request
STTTranscriptionmax 240 minutes, auto language detect

Music Generation

FOTOhub generates full music tracks from a text description via two cloud providers. Requests are synchronous: the response carries a finished audio_url.

Endpoint scope

POST /v1/ai/generate/music generates music and nothing else. It reads model, prompt, duration, genre, mood, bpm, loop and instrumental — any other field in the body is ignored, including mode. There is no mastering, stem-separation or analysis mode on this endpoint, and no /music/compose endpoint. Sending mode does not switch behaviour: the request is still billed and served as a music generation.

Endpoint

POST /v1/ai/generate/music

Billing: 5 credits/min (minimax) or 12 credits/min (elevenlabs), per started minute

Parameters

ParameterTypeRequiredDefaultDescription
promptstringYesDetailed description of the music. Include genre, instruments, mood, energy level, and intended use case.
modelstringNo"minimax""minimax" or "elevenlabs". Any other value returns 400 with the supported list.
durationintegerNo30Duration in seconds. Range: 10–300. Under 10 returns 400; over 300 is clamped. Billed per started minute, so longer tracks cost more.
genrestringNo*Genre hint: "electronic", "jazz", "classical", "hip-hop", "ambient", "rock", "folk", "cinematic". Required for "elevenlabs" — that provider rejects a missing genre, so the call is refused with 400 before billing.
moodstringNoMood hint: "happy", "melancholic", "energetic", "calm", "dark", "uplifting", "mysterious".
bpmintegerNoautoTarget tempo in BPM. Range: 60–200; outside that returns 400. tempo is accepted as a deprecated alias.
loopbooleanNofalseGenerate a seamlessly loopable track.
instrumentalbooleanNotrueWhen true, generates instrumental-only (no vocals). Set false for vocal elements.

Pricing

Billed per started minute, per model — not on a duration ladder. A 90-second track is 2 minutes.

ModelCredits/minNotes
MiniMax Music5Cloud generation, default
ElevenLabs Music12Higher fidelity, genre required

Both endpoints are synchronous: the response carries a finished audio_url. If generation fails the charge is refunded automatically.

Response

json
{
  "model": "minimax",
  "usd_charged": 0.2250,
  "billing": {
    "method": "wallet",
    "usd_charged": 0.2250,
    "usd_charged": 0,
  },
  "audio_url": "https://s1.fotohub.app/storage/v1/object/public/generations/audio/mj_xyz789.mp3",
  "duration": 30,
  "format": "mp3"
}

Rounding

Billing rounds up to the whole minute, so a 30-second and a 60-second track both cost one minute. A 61-second track costs two.

Example

python
import requests

response = requests.post(
    "https://apis.fotohub.app/v1/ai/generate/music",
    headers={
        "Authorization": "Bearer fh_live_your_api_key",
        "Content-Type": "application/json"
    },
    json={
        "prompt": "Upbeat electronic dance track with pulsing synths, "
                  "crisp hi-hats, deep bass drops, and euphoric buildup "
                  "sections. Suitable for a product launch video.",
        "model": "minimax",
        "duration": 60,
        "genre": "electronic",
        "mood": "energetic",
        "bpm": 128,
        "instrumental": True
    }
)

result = response.json()
print(f"Audio URL: {result['audio_url']}")
print(f"Duration: {result['duration']}s")
print(f"USD charged: ${result['usd_charged']:.4f}")
typescript
const response = await fetch(
  "https://apis.fotohub.app/v1/ai/generate/music",
  {
    method: "POST",
    headers: {
      "Authorization": "Bearer fh_live_your_api_key",
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      prompt: "Upbeat electronic dance track with pulsing synths, " +
              "crisp hi-hats, deep bass drops, and euphoric buildup " +
              "sections. Suitable for a product launch video.",
      model: "minimax",
      duration: 60,
      genre: "electronic",
      mood: "energetic",
      bpm: 128,
      instrumental: true,
    }),
  }
);

const result = await response.json();
console.log("Audio URL:", result.audio_url);
console.log(`Duration: ${result.duration}s`);
console.log(`USD charged: $${result.usd_charged}`);
go
package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"net/http"
)

func main() {
	payload := map[string]interface{}{
		"prompt":       "Upbeat electronic dance track with pulsing synths, crisp hi-hats, deep bass drops, and euphoric buildup sections.",
		"model":        "minimax",
		"duration":     60,
		"genre":        "electronic",
		"mood":         "energetic",
		"bpm":          128,
		"instrumental": true,
	}
	body, _ := json.Marshal(payload)

	req, _ := http.NewRequest("POST", "https://apis.fotohub.app/v1/ai/generate/music", bytes.NewReader(body))
	req.Header.Set("Authorization", "Bearer fh_live_your_api_key")
	req.Header.Set("Content-Type", "application/json")

	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		panic(err)
	}
	defer resp.Body.Close()

	var result map[string]interface{}
	json.NewDecoder(resp.Body).Decode(&result)
	fmt.Printf("Audio URL: %s\n", result["audio_url"])
	fmt.Printf("Duration: %vs\n", result["duration"])
	fmt.Printf("USD charged: %.4f\n", result["usd_charged"])
}
bash
curl -X POST "https://apis.fotohub.app/v1/ai/generate/music" \
  -H "Authorization: Bearer fh_live_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "prompt": "Upbeat electronic dance track with pulsing synths, crisp hi-hats, deep bass drops, and euphoric buildup sections.",
    "model": "minimax",
    "duration": 60,
    "genre": "electronic",
    "mood": "energetic",
    "bpm": 128,
    "instrumental": true
  }'

Sound Effects

Endpoint

POST /v1/ai/generate/sfx

Billing: 3 credits (fixed, regardless of duration)

Parameters

ParameterTypeRequiredDefaultDescription
promptstringYesDescription of the sound effect. Be specific about source, environment, and characteristics.
durationintegerNo5Duration in seconds. Range: 1–30. Most SFX work best at 3–10 seconds.

Response

json
{
  "usd_charged": 0.1350,
  "billing": {
    "method": "wallet",
    "usd_charged": 0.1350,
    "usd_charged": 0,
  },
  "audio_url": "https://s1.fotohub.app/storage/v1/object/public/generations/sfx/sfx_r4nd0m.mp3",
  "duration": 5,
  "format": "mp3"
}

Example

python
import requests

response = requests.post(
    "https://apis.fotohub.app/v1/ai/generate/sfx",
    headers={
        "Authorization": "Bearer fh_live_your_api_key",
        "Content-Type": "application/json"
    },
    json={
        "prompt": "Sci-fi laser gun firing three rapid shots, "
                  "with a reverberating echo in a metallic corridor",
        "duration": 3
    }
)

result = response.json()
print(f"SFX URL: {result['audio_url']}")
typescript
const response = await fetch(
  "https://apis.fotohub.app/v1/ai/generate/sfx",
  {
    method: "POST",
    headers: {
      "Authorization": "Bearer fh_live_your_api_key",
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      prompt: "Sci-fi laser gun firing three rapid shots, " +
              "with a reverberating echo in a metallic corridor",
      duration: 3,
    }),
  }
);

const result = await response.json();
console.log("SFX URL:", result.audio_url);
go
package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"net/http"
)

func main() {
	payload := map[string]interface{}{
		"prompt":   "Sci-fi laser gun firing three rapid shots, with a reverberating echo in a metallic corridor",
		"duration": 3,
	}
	body, _ := json.Marshal(payload)

	req, _ := http.NewRequest("POST", "https://apis.fotohub.app/v1/ai/generate/sfx", bytes.NewReader(body))
	req.Header.Set("Authorization", "Bearer fh_live_your_api_key")
	req.Header.Set("Content-Type", "application/json")

	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		panic(err)
	}
	defer resp.Body.Close()

	var result map[string]interface{}
	json.NewDecoder(resp.Body).Decode(&result)
	fmt.Printf("SFX URL: %s\n", result["audio_url"])
}
bash
curl -X POST "https://apis.fotohub.app/v1/ai/generate/sfx" \
  -H "Authorization: Bearer fh_live_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "prompt": "Sci-fi laser gun firing three rapid shots, with a reverberating echo in a metallic corridor",
    "duration": 3
  }'

Text-to-Speech

Endpoint

POST /v1/ai/generate/speech

Billing: 1–2 credits per 1000 characters

Parameters

ParameterTypeRequiredDefaultDescription
textstringYesText to synthesize. Max 3000 characters, or 1200 for "ida-voice" / "ida-voice-pro" — see the length limits note below. Over the limit returns 400 before anything is billed.
modelstringNo"google"TTS engine: "google" (fast, cost-effective), "ida-voice-pro" (natural, premium), "ida-voice" (self-hosted, voice cloning) or "grok" (26 multilingual voices, cheapest). "elevenlabs" is accepted as a legacy alias for "ida-voice-pro".
voice_idstringNoVoice preset ID. Google: "pl-PL-Standard-A", "en-US-Neural2-F". IDA Voice: custom voice ID from dashboard. Grok: "eve", "ara", "leo" and 23 more — see Grok voices.
languagestringNo"en"Target language: "pl", "en", "de", "fr", "es".
speednumberNo1.0Speech speed multiplier. Range: 0.5–2.0.
pitchnumberNo0Pitch adjustment in semitones. Range: -10 to +10. Ignored by "grok".

Pricing

ModelCreditsUSDNotes
Grok Voice0.7$0.0375per 1000 characters, 26 multilingual voices
Google Cloud TTS1$0.0241per 1000 characters, fast
IDA Voice Pro2$0.0482per 1000 characters, natural voice, cloning

Billed per 1000 characters, not per request, and the block count is fractional above the first one — a 2500-character synthesis bills 2.5 blocks, not 3. The first block is always charged in full, so anything under 1000 characters costs one block. characters_processed in the response is the figure billed.

Length limits are transport limits

This endpoint is synchronous and the gateway cuts a proxied request at 100 seconds. "ida-voice" renders roughly 0.058s per character, so its 1200-character cap is about 70 seconds of synthesis plus headroom for the upload — a higher cap would sell a request that cannot finish. If a long call does time out the charge is refunded, but the request is still lost, so split long texts client-side.

Grok voices

All 26 Grok voices are multilingual — one voice speaks any supported language, so pick by character rather than by locale.

Female: ara, carina, celeste, eve, iris, luna, luxMale: altair, atlas, castor, cosmo, helios, helix, kepler, leo, lumen, naksh, orion, perseus, rex, rigel, sal, sirius, ursa, zagan, zenith

python
response = requests.post(
    "https://apis.fotohub.app/v1/ai/generate/speech",
    headers={"Authorization": "Bearer fh_live_your_api_key"},
    json={
        "text": "Witaj w FOTOhub!",
        "model": "grok",
        "voice_id": "eve",
        "language": "pl",
        "speed": 1.0,
    },
)
print(response.json()["audio_url"])

Grok responses report the voice used and the billed character count:

json
{
  "model": "grok",
  "usd_charged": 0.0315,
  "audio_url": "https://s1.fotohub.app/storage/v1/object/public/audio/.../grok-tts.mp3",
  "format": "mp3",
  "voice": "eve",
  "characters_processed": 61
}

Response

json
{
  "model": "google",
  "usd_charged": 0.0450,
  "billing": {
    "method": "wallet",
    "usd_charged": 0.0450,
    "usd_charged": 0,
  },
  "audio_url": "https://s1.fotohub.app/storage/v1/object/public/generations/speech/tts_k8m2n1.mp3",
  "duration": 12.4,
  "format": "mp3",
  "characters_processed": 847
}

Example

python
import requests

response = requests.post(
    "https://apis.fotohub.app/v1/ai/generate/speech",
    headers={
        "Authorization": "Bearer fh_live_your_api_key",
        "Content-Type": "application/json"
    },
    json={
        "text": "Witaj w FOTOhub! Nasza platforma umozliwia "
                "generowanie obrazow, wideo i muzyki za pomoca "
                "sztucznej inteligencji.",
        "model": "google",
        "voice_id": "pl-PL-Standard-B",
        "language": "pl",
        "speed": 1.0,
        "pitch": 0
    }
)

result = response.json()
print(f"Audio URL: {result['audio_url']}")
print(f"Duration: {result['duration']}s")
print(f"Characters processed: {result['characters_processed']}")
typescript
const response = await fetch(
  "https://apis.fotohub.app/v1/ai/generate/speech",
  {
    method: "POST",
    headers: {
      "Authorization": "Bearer fh_live_your_api_key",
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      text: "Witaj w FOTOhub! Nasza platforma umozliwia " +
            "generowanie obrazow, wideo i muzyki za pomoca " +
            "sztucznej inteligencji.",
      model: "google",
      voice_id: "pl-PL-Standard-B",
      language: "pl",
      speed: 1.0,
      pitch: 0,
    }),
  }
);

const result = await response.json();
console.log("Audio URL:", result.audio_url);
console.log(`Duration: ${result.duration}s`);
console.log(`Characters: ${result.characters_processed}`);
go
package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"net/http"
)

func main() {
	payload := map[string]interface{}{
		"text":     "Witaj w FOTOhub! Nasza platforma umozliwia generowanie obrazow, wideo i muzyki za pomoca sztucznej inteligencji.",
		"model":    "google",
		"voice_id": "pl-PL-Standard-B",
		"language": "pl",
		"speed":    1.0,
		"pitch":    0,
	}
	body, _ := json.Marshal(payload)

	req, _ := http.NewRequest("POST", "https://apis.fotohub.app/v1/ai/generate/speech", bytes.NewReader(body))
	req.Header.Set("Authorization", "Bearer fh_live_your_api_key")
	req.Header.Set("Content-Type", "application/json")

	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		panic(err)
	}
	defer resp.Body.Close()

	var result map[string]interface{}
	json.NewDecoder(resp.Body).Decode(&result)
	fmt.Printf("Audio URL: %s\n", result["audio_url"])
	fmt.Printf("Duration: %vs\n", result["duration"])
	fmt.Printf("Characters processed: %v\n", result["characters_processed"])
}
bash
curl -X POST "https://apis.fotohub.app/v1/ai/generate/speech" \
  -H "Authorization: Bearer fh_live_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "text": "Witaj w FOTOhub! Nasza platforma umozliwia generowanie obrazow, wideo i muzyki za pomoca sztucznej inteligencji.",
    "model": "google",
    "voice_id": "pl-PL-Standard-B",
    "language": "pl",
    "speed": 1.0,
    "pitch": 0
  }'

IDA Voice Cloning

With IDA Voice Pro, you can use custom cloned voices. Upload a voice sample via the FOTOhub dashboard to create a custom voice_id, then reference it in API calls. Cloned voices support all languages with natural accent preservation.


Text-to-Speech (Polly)

Budget TTS with 106 neural/generative voices across 41 languages. 10-50x cheaper than premium providers.

Endpoints

GET  /v1/ai/tts/polly/voices
POST /v1/ai/tts/polly/synthesize

Billing: 1 credit per 10,000 characters

List Voices

GET /v1/ai/tts/polly/voices?language=pl-PL

Returns available voices filtered by language code.

Response:

json
{
  "voices": [
    {
      "id": "Ola",
      "name": "Ola",
      "language": "pl-PL",
      "language_name": "Polish",
      "gender": "Female",
      "engines": ["generative", "neural"]
    }
  ],
  "count": 5
}

Synthesize Speech

ParameterTypeRequiredDefaultDescription
textstringYesText to synthesize. Max 10,000 characters. Supports SSML.
voice_idstringNo"Ola"Voice ID from the voices list.
enginestringNo"neural"Engine: "neural", "generative", or "standard".
output_formatstringNo"mp3"Format: "mp3", "ogg_vorbis", or "pcm".
language_codestringNoLanguage hint (e.g., "pl-PL", "en-US").

Response: Audio stream (binary) with headers:

  • X-Credits-Used — credits charged
  • X-Characters — characters processed

Example

python
from fotohub import FotoHub

client = FotoHub(api_key="fh_live_...")
audio = client.tts.polly(
    text="Witaj w FOTOhub!",
    voice_id="Ola",
    engine="neural"
)
# audio is bytes (mp3)
with open("output.mp3", "wb") as f:
    f.write(audio)
typescript
const response = await fetch(
  "https://apis.fotohub.app/v1/ai/tts/polly/synthesize",
  {
    method: "POST",
    headers: {
      "Authorization": "Bearer fh_live_your_api_key",
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      text: "Witaj w FOTOhub! Generuje mowe za pomoca AI.",
      voice_id: "Ola",
      engine: "neural",
      output_format: "mp3",
    }),
  }
);

const audioBuffer = await response.arrayBuffer();
// Write to file (Node.js)
import { writeFileSync } from "fs";
writeFileSync("output.mp3", Buffer.from(audioBuffer));
go
package main

import (
	"bytes"
	"encoding/json"
	"io"
	"net/http"
	"os"
)

func main() {
	payload := map[string]interface{}{
		"text":          "Witaj w FOTOhub! Generuje mowe za pomoca AI.",
		"voice_id":      "Ola",
		"engine":        "neural",
		"output_format": "mp3",
	}
	body, _ := json.Marshal(payload)

	req, _ := http.NewRequest("POST", "https://apis.fotohub.app/v1/ai/tts/polly/synthesize", bytes.NewReader(body))
	req.Header.Set("Authorization", "Bearer fh_live_your_api_key")
	req.Header.Set("Content-Type", "application/json")

	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		panic(err)
	}
	defer resp.Body.Close()

	out, _ := os.Create("output.mp3")
	defer out.Close()
	io.Copy(out, resp.Body)
}
bash
curl -X POST "https://apis.fotohub.app/v1/ai/tts/polly/synthesize" \
  -H "Authorization: Bearer fh_live_your_api_key" \
  -H "Content-Type: application/json" \
  -o output.mp3 \
  -d '{
    "text": "Witaj w FOTOhub! Generuje mowe za pomoca AI.",
    "voice_id": "Ola",
    "engine": "neural",
    "output_format": "mp3"
  }'

Pricing

EngineCost (AWS)CreditsLanguages
Neural$0.016/1K chars1 per 10K chars41
Generative$0.030/1K chars1 per 10K chars41
Standard$0.004/1K chars1 per 10K chars41

Polish Voices

Available Polish voices: Ola (Female, neural+generative), Ewa (Female, generative), Maja (Female, standard), Jan (Male, standard), Jacek (Male, standard).


Text-to-Speech (GPT Audio 1.5)

Premium AI voice synthesis using OpenAI's GPT Audio 1.5 model. Natural-sounding speech with voice style instructions support — describe the tone, emotion, and pace you want.

Endpoint

POST /v1/ai/generate/speech/gpt

Billing: 2 credits per request

Parameters

ParameterTypeRequiredDefaultDescription
textstringYesText to synthesize. Max 10,000 characters.
voicestringNo"alloy"Voice: alloy, ash, ballad, coral, echo, fable, nova, onyx, sage, shimmer, verse
instructionsstringNoVoice style instructions. E.g., "Speak calmly like an audiobook narrator" or "Energetic sports commentator tone".

Pricing

ModelCreditsUSDNotes
GPT Audio 1.52$0.1072per request, WAV HD output

Response

json
{
  "usd_charged": 0.0900,
  "audio_url": "https://s1.fotohub.app/storage/v1/object/public/audio/gpt-tts/...",
  "transcript": "The text as spoken by the model",
  "model": "gpt-audio-1.5",
  "voice": "nova",
  "format": "wav",
  "usage": {
    "input_tokens": 32,
    "output_tokens": 216,
    "total_tokens": 248
  }
}

Example

python
from fotohub import FotoHub

client = FotoHub(api_key="fh_live_your_key")

result = client.audio.speech(
    text="Welcome to FOTOhub! Generate images, video, and music with AI.",
    voice="nova",
    instructions="Speak warmly and naturally, like a podcast host",
)
print(f"Audio: {result.audio_url}")
typescript
const response = await fetch(
  "https://apis.fotohub.app/v1/ai/generate/speech/gpt",
  {
    method: "POST",
    headers: {
      "Authorization": "Bearer fh_live_your_api_key",
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      text: "Welcome to FOTOhub! Generate images, video, and music with AI.",
      voice: "nova",
      instructions: "Speak warmly and naturally, like a podcast host",
    }),
  }
);

const result = await response.json();
console.log(`Audio: ${result.audio_url}`);
console.log(`Voice: ${result.voice}`);
console.log(`Tokens: ${result.usage.total_tokens}`);
go
package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"net/http"
)

func main() {
	payload := map[string]interface{}{
		"text":         "Welcome to FOTOhub! Generate images, video, and music with AI.",
		"voice":        "nova",
		"instructions": "Speak warmly and naturally, like a podcast host",
	}
	body, _ := json.Marshal(payload)

	req, _ := http.NewRequest("POST", "https://apis.fotohub.app/v1/ai/generate/speech/gpt", bytes.NewReader(body))
	req.Header.Set("Authorization", "Bearer fh_live_your_api_key")
	req.Header.Set("Content-Type", "application/json")

	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		panic(err)
	}
	defer resp.Body.Close()

	var result map[string]interface{}
	json.NewDecoder(resp.Body).Decode(&result)
	fmt.Printf("Audio: %s\n", result["audio_url"])
	fmt.Printf("Voice: %s\n", result["voice"])
}
bash
curl -X POST "https://apis.fotohub.app/v1/ai/generate/speech/gpt" \
  -H "Authorization: Bearer fh_live_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "text": "Welcome to FOTOhub! Generate images, video, and music with AI.",
    "voice": "nova",
    "instructions": "Speak warmly and naturally, like a podcast host"
  }'

Voice Style Instructions

GPT Audio 1.5 supports freeform instructions for voice style. You can control tone, pace, emotion, and speaking style. Examples:

  • "Speak slowly and clearly, like a meditation guide"
  • "Excited and energetic, like announcing a product launch"
  • "Professional news anchor tone, neutral and clear"
  • "Whispered, intimate storytelling voice"

Speech-to-Text (Voxtral)

LLM-quality transcription using Mistral Voxtral models. Better context understanding than traditional ASR.

Endpoints

POST /v1/ai/transcribe/voxtral/transcribe
POST /v1/ai/transcribe/voxtral/summarize

Billing: per started minute of input audio, in USD

Transcribe

ParameterTypeRequiredDefaultDescription
audiostringYesBase64-encoded audio (WAV, MP3, OGG, FLAC, WebM). Max 25MB, max 240 minutes.
modelstringNo"voxtral-small"Model: "voxtral-small" (24B, quality) or "voxtral-mini" (3B, fast).
languagestringNoLanguage hint for better accuracy.
promptstringNoContext/instruction for the model.

Response:

json
{
  "text": "Transcribed text content here...",
  "model": "voxtral-small",
  "minutes_billed": 2,
  "cost_usd": 0.04,
  "currency": "USD",
  "tokens": { "input": 1200, "output": 150 }
}

The duration is measured from the file itself and rounded up to whole minutes — a 95-second clip bills 2 minutes. minutes_billed is the figure the charge was computed from. If the header is unreadable the charge is one minute, the smallest honest amount. A failed transcription is refunded automatically, and every request rejected with a 400 is refused before the wallet is touched.

Summarize

Same parameters as transcribe, plus:

ParameterTypeRequiredDefaultDescription
formatstringNo"bullets"Summary format: "bullets" or "paragraph".

Returns both transcription and summary in a single call. Priced as the per-minute transcription plus one fixed summarisation charge — the summary is a single completion capped at 4096 tokens, so it does not grow with the length of the audio.

Pricing

ModelTranscribeSummarizeQualitySpeed
Voxtral Small 24B$0.020 / minute$0.020 / minute + $0.010High (LLM-quality context)~10s
Voxtral Mini 3B$0.005 / minute$0.005 / minute + $0.005Good (fast)~3s

Worked examples, Voxtral Small:

Audio lengthMinutes billedTranscribeSummarize
40 seconds1$0.020$0.030
95 seconds2$0.040$0.050
60 minutes60$1.200$1.210

Both legs are itemised per model in GET /v1/pricing.


Speech-to-Text (Transcription)

Endpoint

POST /v1/ai/transcribe

Billing: 0.3 credits per started minute of input audio, both models

Parameters

ParameterTypeRequiredDefaultDescription
audio_urlstringYesURL of audio file (MP3, WAV, M4A, MP4, FLAC, OGG, WebM). Max 240 minutes; longer returns 400 before billing.
modelstringNo"default""default" or "grok" (per-word timestamps). Both bill 0.3 credits per started minute.
languagestringNo"auto"Source language or "auto" for detection.

The duration is measured from the file itself, then rounded up to whole minutes — a 90-second clip bills 2 minutes. minutes_billed in the response is the figure charged. If the header is unreadable the charge is one minute, the smallest honest amount. A failed transcription is refunded automatically.

No translate or dub mode

This endpoint transcribes in the source language. It reads only audio_url, language and modelmode, timestamps and diarize are ignored, so sending mode: "translate" or mode: "dub" returns a plain transcript and still bills for it. To translate, pass the transcript to /v1/ai/chat/completions; to dub, feed the translation to /v1/ai/generate/speech. The Dubbing Pipeline below shows both steps.

Grok transcription

model: "grok" returns a words array with a start/end offset for every word — useful for subtitles and word-accurate seeking. It bills 0.3 credits per started minute and does not do diarization or emotion analysis.

json
{
  "model": "grok",
  "usd_charged": 0.0135,
  "text": "Transkrypcja publicznego API ze znacznikami czasu.",
  "language": "pl",
  "duration": 3.7,
  "words": [
    { "text": "Transkrypcja", "start": 0.08, "end": 0.88 },
    { "text": "publicznego", "start": 0.96, "end": 1.59 },
    { "text": "API", "start": 1.73, "end": 2.11 }
  ]
}

Response

json
{
  "usd_charged": 0.1350,
  "billing": {
    "method": "wallet",
    "usd_charged": 0.1350,
    "usd_charged": 0,
  },
  "text": "Dzien dobry, chcialbym zamowic projekt graficzny dla mojej firmy...",
  "language_detected": "pl",
  "duration_minutes": 2.8,
  "segments": [
    {
      "start": 0.0,
      "end": 3.2,
      "text": "Dzien dobry, chcialbym zamowic",
      "speaker": null
    },
    {
      "start": 3.2,
      "end": 6.8,
      "text": "projekt graficzny dla mojej firmy...",
      "speaker": null
    }
  ],
  "confidence": 0.96
}

Example

python
import requests

response = requests.post(
    "https://apis.fotohub.app/v1/ai/transcribe",
    headers={
        "Authorization": "Bearer fh_live_your_api_key",
        "Content-Type": "application/json"
    },
    json={
        "audio_url": "https://s1.fotohub.app/storage/v1/object/public/uploads/meeting-recording.mp3",
        "language": "auto",
        "mode": "transcribe",
        "timestamps": True,
        "diarize": True
    }
)

result = response.json()
print(f"Detected language: {result['language_detected']}")
print(f"Full transcript: {result['text']}")

for segment in result["segments"]:
    speaker = segment.get("speaker", "Unknown")
    print(f"[{segment['start']:.1f}s - {segment['end']:.1f}s] "
          f"Speaker {speaker}: {segment['text']}")
typescript
const response = await fetch(
  "https://apis.fotohub.app/v1/ai/transcribe",
  {
    method: "POST",
    headers: {
      "Authorization": "Bearer fh_live_your_api_key",
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      audio_url: "https://s1.fotohub.app/storage/v1/object/public/uploads/meeting-recording.mp3",
      language: "auto",
      mode: "transcribe",
      timestamps: true,
      diarize: true,
    }),
  }
);

const result = await response.json();
console.log(`Detected language: ${result.language_detected}`);
console.log(`Full transcript: ${result.text}`);

for (const segment of result.segments) {
  const speaker = segment.speaker ?? "Unknown";
  console.log(
    `[${segment.start.toFixed(1)}s - ${segment.end.toFixed(1)}s] ` +
    `Speaker ${speaker}: ${segment.text}`
  );
}
go
package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"net/http"
)

func main() {
	payload := map[string]interface{}{
		"audio_url":  "https://s1.fotohub.app/storage/v1/object/public/uploads/meeting-recording.mp3",
		"language":   "auto",
		"mode":       "transcribe",
		"timestamps": true,
		"diarize":    true,
	}
	body, _ := json.Marshal(payload)

	req, _ := http.NewRequest("POST", "https://apis.fotohub.app/v1/ai/transcribe", bytes.NewReader(body))
	req.Header.Set("Authorization", "Bearer fh_live_your_api_key")
	req.Header.Set("Content-Type", "application/json")

	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		panic(err)
	}
	defer resp.Body.Close()

	var result map[string]interface{}
	json.NewDecoder(resp.Body).Decode(&result)
	fmt.Printf("Detected language: %s\n", result["language_detected"])
	fmt.Printf("Full transcript: %s\n", result["text"])
}
bash
curl -X POST "https://apis.fotohub.app/v1/ai/transcribe" \
  -H "Authorization: Bearer fh_live_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "audio_url": "https://s1.fotohub.app/storage/v1/object/public/uploads/meeting-recording.mp3",
    "language": "auto",
    "mode": "transcribe",
    "timestamps": true,
    "diarize": true
  }'

Dubbing Pipeline

A common production workflow: transcribe source audio, translate to another language, then synthesize speech in the target language. This 3-step pipeline gives you full control over each stage (edit the transcript, fix translations, choose voices).

Workflow

  1. Transcribe — extract text from source audio with timestamps
  2. Translate — convert transcript to the target language
  3. Synthesize — generate speech in the target language using Premium TTS

Example

python
import requests

BASE = "https://apis.fotohub.app"
HEADERS = {
    "Authorization": "Bearer fh_live_your_api_key",
    "Content-Type": "application/json"
}

# Step 1: Transcribe the source audio
transcribe_resp = requests.post(
    f"{BASE}/v1/ai/transcribe",
    headers=HEADERS,
    json={
        "audio_url": "https://s1.fotohub.app/storage/v1/object/public/uploads/lecture-pl.mp3",
        "language": "pl",
        "mode": "transcribe",
        "timestamps": True
    }
)
transcript = transcribe_resp.json()
print(f"Transcribed ({transcript['language_detected']}): {transcript['text'][:100]}...")

# Step 2: Translate (using mode: translate for English, or use your own translation)
translate_resp = requests.post(
    f"{BASE}/v1/ai/transcribe",
    headers=HEADERS,
    json={
        "audio_url": "https://s1.fotohub.app/storage/v1/object/public/uploads/lecture-pl.mp3",
        "mode": "translate"
    }
)
translation = translate_resp.json()
translated_text = translation["text"]
print(f"Translated to EN: {translated_text[:100]}...")

# Step 3: Synthesize with Premium TTS (GPT Audio 1.5)
speech_resp = requests.post(
    f"{BASE}/v1/ai/generate/speech/gpt",
    headers=HEADERS,
    json={
        "text": translated_text,
        "voice": "onyx",
        "instructions": "Professional lecturer tone, clear and authoritative"
    }
)
result = speech_resp.json()
print(f"Dubbed audio: {result['audio_url']}")
total_usd_charged = (transcript["usd_charged"] +
                 translation["usd_charged"] +
                 result["usd_charged"])
print(f"Total credits: {total_usd_charged}")
typescript
const BASE = "https://apis.fotohub.app";
const HEADERS = {
  "Authorization": "Bearer fh_live_your_api_key",
  "Content-Type": "application/json",
};

// Step 1: Transcribe the source audio
const transcribeResp = await fetch(`${BASE}/v1/ai/transcribe`, {
  method: "POST",
  headers: HEADERS,
  body: JSON.stringify({
    audio_url: "https://s1.fotohub.app/storage/v1/object/public/uploads/lecture-pl.mp3",
    language: "pl",
    mode: "transcribe",
    timestamps: true,
  }),
});
const transcript = await transcribeResp.json();
console.log(`Transcribed (${transcript.language_detected}): ${transcript.text.slice(0, 100)}...`);

// Step 2: Translate to English
const translateResp = await fetch(`${BASE}/v1/ai/transcribe`, {
  method: "POST",
  headers: HEADERS,
  body: JSON.stringify({
    audio_url: "https://s1.fotohub.app/storage/v1/object/public/uploads/lecture-pl.mp3",
    mode: "translate",
  }),
});
const translation = await translateResp.json();
const translatedText = translation.text;
console.log(`Translated to EN: ${translatedText.slice(0, 100)}...`);

// Step 3: Synthesize with Premium TTS (GPT Audio 1.5)
const speechResp = await fetch(`${BASE}/v1/ai/generate/speech/gpt`, {
  method: "POST",
  headers: HEADERS,
  body: JSON.stringify({
    text: translatedText,
    voice: "onyx",
    instructions: "Professional lecturer tone, clear and authoritative",
  }),
});
const result = await speechResp.json();
console.log(`Dubbed audio: ${result.audio_url}`);
const totalUSDCharged = transcript.usd_charged + translation.usd_charged + result.usd_charged;
console.log(`Total credits: ${totalUSDCharged}`);
go
package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"net/http"
)

const base = "https://apis.fotohub.app"

func post(url string, payload map[string]interface{}) map[string]interface{} {
	body, _ := json.Marshal(payload)
	req, _ := http.NewRequest("POST", url, bytes.NewReader(body))
	req.Header.Set("Authorization", "Bearer fh_live_your_api_key")
	req.Header.Set("Content-Type", "application/json")

	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		panic(err)
	}
	defer resp.Body.Close()

	var result map[string]interface{}
	json.NewDecoder(resp.Body).Decode(&result)
	return result
}

func main() {
	// Step 1: Transcribe
	transcript := post(base+"/v1/ai/transcribe", map[string]interface{}{
		"audio_url":  "https://s1.fotohub.app/storage/v1/object/public/uploads/lecture-pl.mp3",
		"language":   "pl",
		"mode":       "transcribe",
		"timestamps": true,
	})
	fmt.Printf("Transcribed (%s): %s...\n", transcript["language_detected"], transcript["text"])

	// Step 2: Translate
	translation := post(base+"/v1/ai/transcribe", map[string]interface{}{
		"audio_url": "https://s1.fotohub.app/storage/v1/object/public/uploads/lecture-pl.mp3",
		"mode":      "translate",
	})
	translatedText := translation["text"].(string)
	fmt.Printf("Translated to EN: %s...\n", translatedText[:100])

	// Step 3: Synthesize with Premium TTS
	result := post(base+"/v1/ai/generate/speech/gpt", map[string]interface{}{
		"text":         translatedText,
		"voice":        "onyx",
		"instructions": "Professional lecturer tone, clear and authoritative",
	})
	fmt.Printf("Dubbed audio: %s\n", result["audio_url"])
}
bash
# Step 1: Transcribe
curl -s -X POST "https://apis.fotohub.app/v1/ai/transcribe" \
  -H "Authorization: Bearer fh_live_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "audio_url": "https://s1.fotohub.app/storage/v1/object/public/uploads/lecture-pl.mp3",
    "language": "pl",
    "mode": "transcribe",
    "timestamps": true
  }' | jq '.text' > transcript.txt

# Step 2: Translate
curl -s -X POST "https://apis.fotohub.app/v1/ai/transcribe" \
  -H "Authorization: Bearer fh_live_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "audio_url": "https://s1.fotohub.app/storage/v1/object/public/uploads/lecture-pl.mp3",
    "mode": "translate"
  }' | jq -r '.text' > translated.txt

# Step 3: Synthesize with Premium TTS
TRANSLATED=$(cat translated.txt)
curl -X POST "https://apis.fotohub.app/v1/ai/generate/speech/gpt" \
  -H "Authorization: Bearer fh_live_your_api_key" \
  -H "Content-Type: application/json" \
  -d "{
    \"text\": \"$TRANSLATED\",
    \"voice\": \"onyx\",
    \"instructions\": \"Professional lecturer tone, clear and authoritative\"
  }"

Pipeline Costs

The manual dubbing pipeline costs approximately 5 credits per minute of source audio: 1 credit (transcription) + 2 credits (translation) + 2 credits (GPT Audio TTS). For automated single-step dubbing with voice preservation, use mode: "dub" directly (5 credits/min).


Supported Languages

All audio services support the following 23 languages for transcription, translation, TTS, and dubbing.

CodeLanguageTranscriptionTTSTranslationDubbing
arArabicYesYesYesYes
daDanishYesYesYesYes
deGermanYesYesYesYes
elGreekYesYesYesYes
enEnglishYesYesYesYes
esSpanishYesYesYesYes
fiFinnishYesYesYesYes
frFrenchYesYesYesYes
heHebrewYesYesYesYes
hiHindiYesYesYesYes
itItalianYesYesYesYes
jaJapaneseYesYesYesYes
koKoreanYesYesYesYes
msMalayYesYesYesYes
nlDutchYesYesYesYes
noNorwegianYesYesYesYes
plPolishYesYesYesYes
ptPortugueseYesYesYesYes
ruRussianYesYesYesYes
svSwedishYesYesYesYes
swSwahiliYesYesYesYes
trTurkishYesYesYesYes
zhChineseYesYesYesYes

Language Auto-Detection

When language is set to "auto" (default for transcription), FOTOhub automatically detects the spoken language from the first 30 seconds of audio. The detected language code is returned in the response as language_detected.


Model Comparison

Quick reference for choosing the right model for your use case.

CategoryModelPriceBest For
MusicMiniMax5 credits / minJingles, drafts, full tracks
MusicElevenLabs Music12 credits / minHigher fidelity, genre required
SFXElevenLabs SFX3 creditsSound effects, foley — fixed per generation
TTSGrok Voice0.7 credits / 1K charsCheapest, 26 multilingual voices
TTSGoogle Cloud TTS1 credit / 1K charsBudget TTS, fast
TTSIDA Voice / Pro2 credits / 1K charsNatural voice, cloning
TTSGPT Audio 1.52 credits / requestPremium quality, voice instructions
TTSPolly (Neural)1 credit / 10K charsBulk narration, 106 voices
TranscriptionDefault0.3 credits / minDiarization, emotion analysis
TranscriptionGrok0.3 credits / minPer-word timestamps
TranscriptionVoxtral Small$0.020 / minLLM-quality context
TranscriptionVoxtral Mini$0.005 / minFast transcription

Choosing a TTS Model

  • Grok Voice (0.7 cr/1K) — cheapest, one voice speaks any language
  • Google Cloud TTS (1 cr/1K) — fast, cost-effective, good for UI narration and notifications
  • IDA Voice Pro (2 cr/1K) — natural prosody, supports voice cloning, best for branded voices
  • GPT Audio 1.5 (2 cr/request) — highest quality, supports freeform style instructions, ideal for podcasts and audiobooks
  • Polly (1 cr/10K chars) — cheapest for bulk content, 106 voices across 41 languages

  • Voice Cloning — create and use cloned voices, emotional TTS, voice forensics
  • Shorts & Clips — audio-driven video clips with caption generation
  • Voice Agents — two-way spoken conversations instead of one-shot TTS: define a persona, voice and tools, then mint browser session tokens
  • Realtime Voice — the integration guide for those sessions: WebSocket transport, mic capture, PCM16 playback, tool calls

Pricing Summary

ServiceModelPriceUnit
MusicMiniMax5 creditsper started minute
MusicElevenLabs12 creditsper started minute
Sound EffectsElevenLabs SFX3 creditsfixed per generation
TTSGrok Voice0.7 creditsper 1000 characters
TTSGoogle Cloud1 creditper 1000 characters
TTSIDA Voice / Pro2 creditsper 1000 characters
TTSGPT Audio 1.52 creditsper request
TTSPolly (Neural)1 creditper 10,000 characters
TranscriptionDefault0.3 creditsper started minute
TranscriptionGrok0.3 creditsper started minute
TranscriptionVoxtral Mini$0.005per started minute
TranscriptionVoxtral Small$0.020per started minute
Voxtral summarizeMini / Small+ $0.005 / + $0.010once per request, on top of the per-minute rate

Character-billed endpoints charge fractional blocks above the first (2500 chars = 2.5 blocks); minute-billed endpoints round up to the whole minute, so a 95-second file bills 2 minutes. Every response reports what was charged — cost_usd on the all endpoints use usd_charged — alongside characters_processed or minutes_billed.

GET /v1/pricing returns the live figures with their units and an itemised breakdown per leg, which is the authoritative source if this table and the API ever disagree.

Error Responses

StatusCodeDescription
400bad_requestInvalid parameters: unsupported format, duration out of range, invalid voice_id.
402insufficient_fundsWallet balance will not cover the request. The body carries required_usd, balance_usd, shortfall_usd and topup_url.
413file_too_largeAudio file exceeds 500MB. Compress or split before uploading.
422unprocessable_audioFile corrupted, unsupported codec, or no detectable speech.
429rate_limit_exceededAudio limits: 20 req/min (TTS/SFX), 10 req/min (music), 5 req/min (transcription/dubbing).

Gemini Generative TTS (Vertex AI)

Google Gemini generative speech model on Vertex AI. Features natural-language style direction ("read this cheerfully with an energetic tone"), multi-speaker dialogue scripts, and 30 prebuilt neural voices. Output format is 24 kHz mono WAV.

Billed in USD from prepaid wallet based on Google's exact token rates. Audio output is billed at 25 audio tokens per second of speech.

Endpoints

1. List Gemini Models & Token Pricing

GET /v1/ai/tts/gemini/models
Response Example
json
{
  "models": [
    {
      "id": "gemini-2.5-flash-tts",
      "name": "Gemini 2.5 Flash TTS",
      "available": true,
      "max_characters": 3000,
      "price_usd_per_1m_text_tokens": "0.15",
      "price_usd_per_1m_audio_tokens": "3.00",
      "preview": false
    },
    {
      "id": "gemini-2.5-pro-tts",
      "name": "Gemini 2.5 Pro TTS",
      "available": true,
      "max_characters": 5000,
      "price_usd_per_1m_text_tokens": "0.50",
      "price_usd_per_1m_audio_tokens": "10.00",
      "preview": false
    }
  ],
  "configured": true,
  "audio_tokens_per_second": 25
}

2. List Gemini Voices

GET /v1/ai/tts/gemini/voices

Returns the 30 prebuilt Gemini voices (Puck, Charon, Kore, Fenrir, Aoede, Leda, Zephyr, etc.) and the maximum allowed speakers for multi-speaker synthesis (max_speakers: 2).


3. Synthesize Speech with Gemini

POST /v1/ai/tts/gemini/synthesize
Request Parameters
FieldTypeRequiredDefaultDescription
textstringYesText to synthesize. For dialogue, prefix lines with speaker names.
modelstringNo"gemini-2.5-flash-tts"Gemini TTS model ID.
voicestringNo"Puck"Prebuilt voice name (used for single-speaker).
stylestringNo""Natural language performance instructions (e.g. "calm and whispering", "energetic podcast host").
speakersobject[]NonullArray of {speaker, voice} mappings for dialogue (max 2 speakers).
temperaturefloatNo1.0Sampling temperature (0.0 to 2.0).
Response

Returns raw binary audio with Content-Type: audio/wav. Billing details are returned in custom headers:

  • X-Cost-USD: Dollar amount charged to wallet.
  • X-Input-Tokens: Text tokens processed.
  • X-Audio-Tokens: Audio tokens generated.
  • X-Audio-Seconds: Speech duration in seconds.
  • X-Model: Model used.
  • X-Truncated: "1" if audio hit output token ceiling, otherwise "0".
python
import requests

headers = {
    "Authorization": "Bearer YOUR_JWT_TOKEN",
    "Content-Type": "application/json",
}
payload = {
    "text": "Welcome to FOTOhub. What would you like to build today?",
    "voice": "Kore",
    "style": "warm, welcoming and enthusiastic",
}

resp = requests.post(
    "https://apis.fotohub.app/v1/ai/tts/gemini/synthesize",
    headers=headers,
    json=payload,
)

with open("welcome.wav", "wb") as f:
    f.write(resp.content)

print(f"Cost: ${resp.headers.get('X-Cost-USD')}, Duration: {resp.headers.get('X-Audio-Seconds')}s")
typescript
const resp = await fetch("https://apis.fotohub.app/v1/ai/tts/gemini/synthesize", {
  method: "POST",
  headers: {
    Authorization: "Bearer YOUR_JWT_TOKEN",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    text: "Welcome to FOTOhub. What would you like to build today?",
    voice: "Kore",
    style: "warm, welcoming and enthusiastic",
  }),
});

const audioBlob = await resp.blob();
console.log(`Cost: $${resp.headers.get("X-Cost-USD")}`);
go
package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"os"
)

func main() {
	payload := map[string]string{
		"text":  "Welcome to FOTOhub. What would you like to build today?",
		"voice": "Kore",
		"style": "warm, welcoming and enthusiastic",
	}
	body, _ := json.Marshal(payload)
	req, _ := http.NewRequest("POST", "https://apis.fotohub.app/v1/ai/tts/gemini/synthesize", bytes.NewReader(body))
	req.Header.Set("Authorization", "Bearer YOUR_JWT_TOKEN")
	req.Header.Set("Content-Type", "application/json")

	resp, _ := http.DefaultClient.Do(req)
	defer resp.Body.Close()

	out, _ := os.Create("welcome.wav")
	defer out.Close()
	io.Copy(out, resp.Body)
	fmt.Printf("Cost: $%s\n", resp.Header.Get("X-Cost-USD"))
}
bash
curl -X POST https://apis.fotohub.app/v1/ai/tts/gemini/synthesize \
  -H "Authorization: Bearer YOUR_JWT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "text": "Welcome to FOTOhub. What would you like to build today?",
    "voice": "Kore",
    "style": "warm, welcoming and enthusiastic"
  }' \
  --output welcome.wav

Azure Speech Neural TTS

Microsoft Azure Speech Services with 700+ neural voices across 140 languages and dialects. Full support for SSML, emotion styles, speaking rate, pitch, and role-play voices.

Billed in USD from wallet balance per 1,000 characters submitted (tts-azure rate).

Endpoints

1. List Azure Voices

GET /v1/ai/tts/azure/voices?language=pl-PL
Query Parameters
  • language: Optional locale prefix (e.g. pl-PL, en-US, de-DE).

2. Synthesize with Azure

POST /v1/ai/tts/azure/synthesize
Request Parameters
FieldTypeRequiredDefaultDescription
textstringYesPlain text or <speak>...</speak> SSML markup (max 50,000 chars).
voice_idstringNo"pl-PL-MarekNeural"Azure voice identifier.
output_formatstringNo"audio-24khz-96kbitrate-mono-mp3"Output format (audio/mpeg or audio/wav).
stylestringNonullExpressive style (e.g. cheerful, sad, customerservice, newscast).
ratestringNo"0%"Speech rate adjustment (e.g. "+10%", "-15%").
pitchstringNo"0%"Pitch adjustment (e.g. "+5Hz", "-2st").
Response Headers
  • Content-Type: audio/mpeg or audio/wav
  • X-Cost-USD: Dollar cost
  • X-Characters: Character count processed
python
import requests

headers = {
    "Authorization": "Bearer YOUR_JWT_TOKEN",
    "Content-Type": "application/json",
}
payload = {
    "text": "Cześć! Twoje zamówienie zostało pomyślnie zrealizowane.",
    "voice_id": "pl-PL-AgnieszkaNeural",
    "style": "cheerful",
}
resp = requests.post(
    "https://apis.fotohub.app/v1/ai/tts/azure/synthesize",
    headers=headers,
    json=payload,
)
with open("order.mp3", "wb") as f:
    f.write(resp.content)
typescript
const resp = await fetch("https://apis.fotohub.app/v1/ai/tts/azure/synthesize", {
  method: "POST",
  headers: {
    Authorization: "Bearer YOUR_JWT_TOKEN",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    text: "Cześć! Twoje zamówienie zostało pomyślnie zrealizowane.",
    voice_id: "pl-PL-AgnieszkaNeural",
    style: "cheerful",
  }),
});
const audioBlob = await resp.blob();
go
package main

import (
	"bytes"
	"encoding/json"
	"io"
	"net/http"
	"os"
)

func main() {
	payload := map[string]string{
		"text":     "Cześć! Twoje zamówienie zostało pomyślnie zrealizowane.",
		"voice_id": "pl-PL-AgnieszkaNeural",
		"style":    "cheerful",
	}
	body, _ := json.Marshal(payload)
	req, _ := http.NewRequest("POST", "https://apis.fotohub.app/v1/ai/tts/azure/synthesize", bytes.NewReader(body))
	req.Header.Set("Authorization", "Bearer YOUR_JWT_TOKEN")
	req.Header.Set("Content-Type", "application/json")

	resp, _ := http.DefaultClient.Do(req)
	defer resp.Body.Close()
	out, _ := os.Create("order.mp3")
	defer out.Close()
	io.Copy(out, resp.Body)
}
bash
curl -X POST https://apis.fotohub.app/v1/ai/tts/azure/synthesize \
  -H "Authorization: Bearer YOUR_JWT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "text": "Cześć! Twoje zamówienie zostało pomyślnie zrealizowane.",
    "voice_id": "pl-PL-AgnieszkaNeural",
    "style": "cheerful"
  }' \
  --output order.mp3