If you are building a voice agent, you will hit the same fork in the road every developer does: use a managed AI-voice platform like Vapi, Retell AI, or Bland, or build on a programmable voice layer and bring your own LLM. This post lays out that decision.
TL;DR
- Vapi, Retell AI, and Bland are managed voice-agent platforms: STT, LLM, TTS, and telephony bundled behind one USD-billed API. They are the fastest way to a working demo.
- Sautikit is the programmable voice/telephony layer. You wire your own LLM (Gemini, OpenAI) to a live
<Stream>media fork, so you own the model, the prompt, and the per-minute cost.- Choose Sautikit when you want control, cost transparency in KES, M-Pesa top-up, and no USD lock-in; choose a managed bundle when a same-day demo matters more than owning the stack.
Vapi, Retell AI, and Bland are managed AI-voice-agent platforms. You configure an agent (system prompt, voice, tools) and the platform orchestrates speech-to-text, the LLM turn, and text-to-speech, then hands you telephony on top. This is genuinely convenient: you get a talking agent in an afternoon, batteries included. They bill in USD, typically per-minute at a blended rate that folds in model and voice costs.
Sautikit is a programmable voice API: the telephony and media layer, not the AI. You place and receive calls, run IVR logic with JSON voice actions, and fork live call audio to your own WebSocket with the <Stream> verb. The AI is yours: pipe the audio to Gemini or OpenAI, generate a reply, stream PCM back into the call. Billing is KES, prepaid, topped up over M-Pesa. Numbers activate instantly from KES 116.
The distinction is ownership. A managed bundle decides which STT, which LLM, and which TTS you get, and prices them together. Sautikit hands you the raw audio and gets out of the way.
| Dimension | Vapi / Retell / Bland | Sautikit |
|---|---|---|
| Control over the stack | Platform-orchestrated | You own STT + LLM + TTS |
| Pricing model | Blended USD per-minute | KES 3.00/min outbound, inbound free |
| LLM choice | Platform's supported set | Any (Gemini, OpenAI, self-hosted) |
| Telephony | Bundled | Native, programmable voice actions |
| Realtime audio | Managed pipeline | Raw PCM via <Stream> media fork |
| Billing currency | USD, card | KES, prepaid wallet |
| African / M-Pesa support | Limited | M-Pesa STK top-up, instant local numbers |
Managed platforms win on time-to-first-demo. Sautikit wins when you need to see and control every layer, and when the invoice needs to be in shillings, not dollars.
The bundle that saves you an afternoon can cost you flexibility. Three points show up once you are past the prototype:
Model lock-in. When a better or cheaper LLM ships, you switch it in one line on your own pipeline. On a managed platform you wait for it to be supported. If your agent's quality depends on a specific Gemini or fine-tuned model, owning the LLM call matters.
Cost opacity. A blended per-minute USD rate hides what you actually pay for STT, tokens, and TTS. With Sautikit you pay KES 3.00/min for the call (billed per second from the moment the call connects; inbound is free) and pay your model provider directly. Two line items you can each optimise, both visible.
Currency and payments. USD billing means FX exposure and a card requirement. Sautikit bills in KES from a prepaid wallet you top up over M-Pesa: no card, no dollar invoice. See /pricing for the current source of truth.
The pattern is: place or receive a call, return a <Stream> action that forks audio to your WebSocket, and run your own AI loop on the socket. Start by placing a call.
const res = await fetch("https://api.sautikit.com/v1/calls", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.SAUTIKIT_API_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": crypto.randomUUID(),
},
body: JSON.stringify({ from: "+254700000000", to: ["+254711111111"] }),
});
const { call_id, status, stream_url } = await res.json();
console.log(call_id, status); // "HD_..."-backed session, "ringing"Your voice callback returns the <Stream> action as raw XML, forking both tracks to your WebSocket at 16 kHz:
import express from "express";
const app = express();
app.post("/voice", (req, res) => {
res.type("application/xml").send(
`<Response>
<Stream name="agent"
url="wss://your.ws/audio"
track="both_tracks"
outputSamplingRate="16000"
statusEvents="stream-started stream-stopped stream-error" />
</Response>`
);
});
app.listen(3000);Now run the AI on the socket. Your WebSocket server must accept the audio.drachtio.org subprotocol; it receives binary PCM frames and plays audio back by sending binary PCM on the same socket. That return path is where you drop in Gemini or OpenAI.
import { WebSocketServer } from "ws";
const wss = new WebSocketServer({
port: 8080,
handleProtocols: () => "audio.drachtio.org",
});
wss.on("connection", (socket) => {
socket.on("message", async (frame, isBinary) => {
if (!isBinary) return; // control/status JSON
const reply = await runYourVoiceAI(frame); // Gemini/OpenAI -> PCM
socket.send(reply, { binary: true }); // play back into the call
});
});That runYourVoiceAI function is the whole point: it is your STT, your LLM, your TTS, chosen and tuned by you. For a full realtime build, see the AI voice agent pillar and the Gemini realtime flagship.
Reach for Sautikit when you want to own the AI stack end to end: pick the model that runs each turn, bill in KES with M-Pesa, provision numbers instantly, and keep per-minute cost transparent and low. The build above is an afternoon of work, and your AI tooling can drive the result directly — the hosted MCP server exposes the whole stack (numbers, calls, agents, broadcasts) to Claude or any MCP client, with human confirmation on anything that spends money.
A managed bundler gets a demo up the same day, but you inherit its model choices, USD card billing, and a per-minute platform fee stacked on top of telephony — and the migration section above shows what it takes to leave.
If your product also needs SMS, WhatsApp, or an agent desk beside the voice agent, keep them in one family: Helloduty is the multi-channel CX platform Sautikit plugs into, so voice stays focused while the rest of the channels live next door.
You bring your own AI pipeline. Sautikit forks the live call audio to your WebSocket via <Stream>; what you do with it (STT, LLM, TTS) is your choice. That is the trade for full control over model and cost.
Yes. Any model works, because Sautikit only handles telephony and the raw PCM media fork. Wire Gemini, OpenAI, or a self-hosted model into your WebSocket handler's return path.
Managed platforms charge a blended USD per-minute rate covering model and voice. Sautikit charges KES 3.00/min for the call (inbound free) and you pay your LLM provider separately: two visible, separately optimisable line items.
Sautikit is Kenya-first and expanding to more markets. M-Pesa top-up and instant local numbers reflect where we operate today; the API is the same wherever you build.
<Stream> action and connect your own LLM on the WebSocket.Start with Sautikit → · See pricing → · Need SMS, WhatsApp & an agent desk? Helloduty →