Cara Bikin Text-to-Speech Sendiri Pakai OpenRouter, Satu API Key buat Semua Provider (Tutorial 15 Menit)
12 September 2026·6 min read
Kalian mau nambahin suara ke aplikasi — bot Telegram yang bisa ngomong, video yang butuh narasi, atau sekadar iseng bikin audiobook dari draft blog. Masalahnya, tiap provider TTS punya cara request sendiri-sendiri, dan kalian nggak mau kunci diri ke satu vendor doang. OpenRouter ngeluncurin dukungan text-to-speech yang nyelesain itu dengan satu endpoint yang bisa manggil model TTS dari beberapa provider sekaligus, tinggal ganti nama model di body request.
Tutorial ini bawa kalian dari nol — bikin API key sampai punya file MP3 hasil text-to-speech yang jalan lewat cURL, Python, dan streaming SDK.
Yang kalian butuhkan
Apa
Buat apa
Biaya
Akun + API key OpenRouter
Autentikasi ke endpoint TTS
Gratis bikin akun, bayar per pemakaian model
Terminal atau code editor
Jalanin contoh cURL dan Python
Gratis
Python 3.8+
Lanjut ke integrasi kode (opsional)
Gratis
Library requests atau openai SDK
Kirim request dari script Python
Gratis, open source
Waktu: sekitar 15-20 menit dari bikin API key sampai punya file audio hasil TTS yang jalan di Python.
Peta perjalanannya
TAHAP 1 Pasang API key OpenRouter (3 menit)
TAHAP 2 Generate audio pertama pakai cURL (5 menit)
TAHAP 3 Pindahin request ke Python (5 menit)
TAHAP 4 Streaming + ganti model/voice (5 menit)
Total: ~18 menit
TAHAP 1 — Pasang API key OpenRouter
Bikin API key di dashboard OpenRouter, terus simpan di environment variable — jangan pernah ditulis langsung di source code. Di macOS atau Linux, set dulu buat sesi terminal yang lagi jalan:
prompt
export OPENROUTER_API_KEY="your-api-key"
Semua request nanti ngarah ke https://openrouter.ai/api/v1 sebagai base URL, dan key-nya dikirim lewat header Authorization: Bearer. Satu key ini nanti dipakai buat manggil model TTS dari provider mana pun tanpa perlu daftar ulang — mirip satu adaptor colokan universal yang bisa dipakai di banyak jenis stopkontak waktu kalian traveling, tinggal ganti ujung colokannya sesuai negara.
⚠️ Jangan commit API key ke git
Kalau kalian pakai .env file, pastikan masuk .gitignore. Key yang ke-push ke repo publik bisa dipakai orang lain dan biaya pemakaiannya dibebanin ke akun kalian.
TAHAP 2 — Generate audio pertama pakai cURL
Endpoint-nya POST /api/v1/audio/speech, kompatibel sama struktur OpenAI. Tiga field yang perlu kalian isi: model buat milih model suara, input isi teks yang mau diucapkan, dan voice buat milih suaranya — dalam praktiknya voice wajib diisi karena nggak semua model dokumentasiin default-nya.
Contoh di bawah pakai Mistral Voxtral Mini TTS dengan voice en_paul_neutral, dan hasilnya langsung disimpan ke output.mp3:
Flag --fail-with-body bikin cURL keluar dengan error kalau server balikin status 4xx atau 5xx. --dump-header nyimpen header response biar kalian bisa cek content type-nya. Sebelum diputer, cek dulu file-nya beneran isi audio:
prompt
ls -lh output.mp3
⚠️ Endpoint default-nya PCM, bukan MP3
Kalau kalian nggak set response_format secara eksplisit, endpoint OpenRouter default balikin PCM. Mistral Voxtral Mini TTS cuma nerima MP3 — jadi field ini wajib diisi manual, jangan andelin default.
TAHAP 3 — Pindahin request ke Python
Kalau mau dipakai di aplikasi beneran, pindahin ke Python. Install dulu requests kalau belum ada:
prompt
python -m pip install requests
Bagian penting di sini bukan cuma ngirim request, tapi validasi respons sebelum nulis ke file — biar kalian nggak nyimpen JSON error sebagai file MP3:
prompt
import os
from pathlib import Path
import requests
response = requests.post(
"https://openrouter.ai/api/v1/audio/speech",
headers={
"Authorization": f"Bearer {os.environ['OPENROUTER_API_KEY']}",
"Content-Type": "application/json",
},
json={
"model": "mistralai/voxtral-mini-tts-2603",
"input": "[ISI - teks yang mau diucapkan]",
"voice": "en_paul_neutral",
"response_format": "mp3",
},
timeout=60,
)
response.raise_for_status()
content_type = response.headers.get("Content-Type", "").split(";")[0]
if content_type != "audio/mpeg":
raise RuntimeError(f"Expected audio/mpeg, received {content_type}")
Path("output.mp3").write_bytes(response.content)
generation_id = response.headers.get("X-Generation-Id")
print(f"Saved output.mp3. Generation ID: {generation_id}")
raise_for_status() bikin exception muncul kalau API balikin error, jadi aplikasi kalian nggak lanjut nulis file dari respons yang gagal. Simpan juga X-Generation-Id-nya — berguna kalau nanti kalian perlu lacak request tertentu ke support OpenRouter.
⚠️ Jangan skip pengecekan content-type
Request yang gagal tetap balikin body — tapi isinya JSON, bukan audio. Kalau langsung ditulis ke file .mp3 tanpa dicek dulu, file-nya ada tapi nggak bisa diputer sama sekali.
TAHAP 4 — Streaming pakai OpenAI SDK, ganti model dan voice
Endpoint TTS OpenRouter ngikutin bentuk OpenAI Audio Speech API, jadi kalian bisa pakai openai Python client langsung dengan ganti base_url:
prompt
import os
from pathlib import Path
from openai import OpenAI
client = OpenAI(
api_key=os.environ["OPENROUTER_API_KEY"],
base_url="https://openrouter.ai/api/v1",
)
with client.audio.speech.with_streaming_response.create(
model="mistralai/voxtral-mini-tts-2603",
voice="en_paul_neutral",
input="[ISI - teks yang mau diucapkan]",
) as response:
response.stream_to_file(Path("output.mp3"))
Ganti suara cukup ganti value voice di satu baris — asal model yang sama support suara itu. Kalau kalian mau pindah provider sepenuhnya, ganti model dan voice-nya barengan, karena voice yang valid beda-beda per provider. Struktur request, autentikasi, dan cara validasi respons tetap sama persis, nggak peduli provider mana yang kalian pilih.
Checklist sebelum kalian pakai TTS-nya di produksi
API key disimpan di environment variable, bukan ditulis langsung di kode
response_format di-set eksplisit sesuai model yang dipakai
Ada validasi content-type sebelum file audio ditulis
X-Generation-Id disimpan buat keperluan tracing
Sudah dicoba ganti model atau voice minimal sekali biar tau alurnya
Kalau gagal
File MP3 ke-save tapi nggak bisa diputer — biasanya isinya JSON error, bukan audio, karena kalian nggak cek status response dulu. Solusinya, pakai --fail-with-body di cURL atau raise_for_status() di Python sebelum nulis file.
Audio-nya gagal diputer padahal request sukses — kemungkinan besar response_format nggak di-set, jadi yang balik format PCM sementara kalian nyimpennya sebagai .mp3. Set field itu eksplisit tiap request.
Muncul error "voice not supported" pas ganti suara — voice yang dipilih nggak ada di daftar model itu, tiap provider punya daftar voice sendiri-sendiri. Cek dokumentasi model dulu sebelum ganti.
Streaming berhenti di tengah tanpa pesan error jelas — sering kejadian kalau teksnya panjang dan timeout kependekan. Naikin nilai timeout atau pecah teks jadi beberapa request lebih kecil.
Setelah TTS-nya kalian jalan
Prinsip yang kepake di sini bukan cuma soal TTS — satu endpoint, satu cara autentikasi, tinggal ganti nama model buat pindah provider, itu pola yang sama yang bakal kalian temuin di hampir semua API multi-provider. Begitu kalian ngerti alurnya, integrasiin ke aplikasi lain jadi tinggal copy-paste dengan model berbeda. Kalau kalian butuh arah sebaliknya — suara jadi teks — OpenRouter juga punya panduan transkripsi dengan struktur endpoint yang sama.