Build a Voice Note Transcriber
Ship an endpoint that takes a voice note — including Yoruba, Hausa, or Igbo — and returns a clean transcript with speaker labels. About ten minutes.
By the end of this guide you'll have an endpoint your users can send a voice note to and get back a clean transcript — with speaker labels, and in African languages if you need them. Perfect for WhatsApp voice notes, voicemails, or meeting recordings. About ten minutes if you already have a Next.js app.
We'll use the Voice API's transcribe and diarize methods. The provider is inferred from the model, so switching between Deepgram (fast English), AssemblyAI (long-form + speakers), and Spitch (African languages) is a one-line change.
What you're building
{
"text": "Hey, just following up on the invoice. Can you send it over today?",
"duration": 4.2,
"language": "en",
"provider": "deepgram",
"segments": [
{ "speaker": "speaker_0", "text": "Hey, just following up on the invoice.", "start": 0.1, "end": 2.0 },
{ "speaker": "speaker_1", "text": "Can you send it over today?", "start": 2.3, "end": 4.2 }
]
}Prerequisites
- A Cencori project + API key (starts with
csk_...) npm install cencori
1. The endpoint
Create an API route that accepts an uploaded audio file and returns the transcript.
// app/api/transcribe/route.ts
import { Cencori } from 'cencori';
const cencori = new Cencori({ apiKey: process.env.CENCORI_API_KEY! });
export async function POST(req: Request) {
const form = await req.formData();
const file = form.get('file') as File;
const language = (form.get('language') as string) || 'en';
const result = await cencori.voice.diarize({
audio: await file.arrayBuffer(),
filename: file.name,
model: 'assemblyai-universal', // long-form + speaker labels
language,
});
return Response.json(result);
}That's the whole backend. diarize turns on speaker labels and returns verbose_json with segments.
2. Pick the right model
The provider is inferred from model, so tuning for cost, speed, or language is a one-line swap:
For a Nigerian WhatsApp bot handling voice notes in mixed languages, detect or ask the language and route accordingly:
const model = ['yo', 'ha', 'ig'].includes(language) ? 'spitch-stt' : 'nova-3';
const result = await cencori.voice.transcribe({
audio: await file.arrayBuffer(),
filename: file.name,
model,
language,
});3. A drop-in recorder (optional)
If you want a mic recorder in your UI without writing one, use the React component — it records, uploads, and renders the transcript (with speaker labels) for you:
import { VoiceRecorder } from 'cencori/react';
export function NoteTaker() {
return (
<VoiceRecorder
endpoint="/api/transcribe"
model="assemblyai-universal"
diarize
onTranscript={(text) => console.log(text)}
/>
);
}4. Reply with a voice note
Close the loop — turn your text reply back into audio in the same language:
const { audio } = await cencori.voice.speak({
input: 'Invoice sent — check your inbox.',
model: language === 'yo' ? 'spitch-tts' : 'aura-asteria-en',
language,
});
// send `audio` back as a WhatsApp voice noteWhat you get for free
Because it runs through the gateway, every transcription is:
- Billed and tracked — per-minute cost logged to your dashboard with the provider used
- PII-redacted — the input guard runs on the request
- BYOK-ready — plug in your own Deepgram/AssemblyAI/Spitch keys per project
- Portable — swap providers by changing the model, no code rewrite
That's a production voice-note pipeline in a single file.

