Inbound line for existing borrowers — payments, fees, arrears, settling early.
Phone calls answered in under a second,
in the language the caller switches to.
Sphoro Voice runs your inbound and outbound calls in fifteen South Asian languages — Hindi, Tamil, Telugu, Marathi, Bengali and the rest — each with its own prompt, voice and recognizer, and a caller who opens in English and finishes in Hindi is followed mid-call rather than restarted. A human notices delay above roughly 800 milliseconds, so every stage streams into the next instead of waiting for it. Your carrier, your model keys, your account if you want it there.
60 minutes free · No credit card · 38 agent templates · Self-hosting available
+91 98••• 41207 → Reception
Thirty-eight agents with the prompt already written.
A blank agent is a text box and a shrug. Nearly every phone agent anyone builds is one of a few dozen well-understood things, and the difference between a good one and a bad one is almost entirely the system prompt — which is exactly the part a blank form asks a newcomer to invent. Each of these arrives with a real prompt, a greeting, the filler line that covers a slow lookup, and the tools it expects to find.
Respectful outbound calls about overdue invoices.
Outbound reminder with a keypad option to pay or speak to someone.
Outbound call after a direct debit is returned or a card is declined.
Chases outstanding identity or address documents, without ever sounding like a scam.
Lost cards, unrecognised transactions, statements and payments.
Answers borrowing questions, explains the process, books time with an adviser.
First notice of loss — takes the facts without judging the cover.
Qualifies inbound enquiries and routes the good ones to a rep.
Outbound calls to book meetings, with a clean exit when it is a no.
Books demos with warm leads and confirms the details.
Follows up property enquiries, qualifies budget, books viewings.
Fields support enquiries, answers from your documentation, escalates.
Walks through troubleshooting one step at a time, escalates with detail.
Order lookups, delivery estimates, and the start of a return.
Answers the main line, routes to the right department, takes messages.
Medical front desk — appointments, intake details, triage to a human.
Hotel front desk — guest requests, local recommendations, issues.
Takes messages outside business hours and escalates real emergencies.
Answers, offers numbered options, and routes on the keypress.
A pure phone menu. No speech recognition, no language model, no per-call cost.
Answers, says who is picking up, and puts the caller straight through to a person.
General-purpose booking — checks availability, books, confirms.
Outbound confirmations and rescheduling for upcoming appointments.
Service pricing, bookings, and stylist requests.
Reservations, party sizes, dietary notes, and opening hours.
HVAC, plumbing and electrical — qualifies the job and books a technician.
Tenant calls — maintenance requests, rent questions, emergencies.
Takes pickup and delivery orders with customisations and totals.
Internal IT — password resets, VPN, access requests, software faults.
Answers staff questions on leave, benefits and payroll.
Walks a new starter through day one and what they need to do.
Answers process and policy questions from internal documentation.
Outbound follow-up for ratings and open-ended feedback.
Qualitative discovery interviews — open questions, never leading.
Conversation practice that adapts to level and corrects gently.
Plays a realistic counterpart for practice, then scores the attempt.
Conducts a spoken assessment, scores it, and explains the result.
Every one is a starting point rather than a cage — the prompt, the voice, the tools and the languages are yours to change the moment it exists. Tools are named, not assumed: a template that wants book_appointment is filtered against what your account has actually registered, so it never creates an agent with a broken hand-off in it.
A caller who changes language mid-sentence is not an edge case here.
Every language an agent speaks is its own entry, with its own prompt, its own voice, its own synthesizer and recognizer and its own greeting. There is no separate field for "the" language anywhere on the agent — the first entry is simply the one calls open in. Switch detection on, and the agent follows a caller from one language to another partway through a call, voice and prompt and all.
// Calls open in the first entry, and its prompt is the agent's. { "languages": [ { "code": "en-IN", "system_prompt": "You are {{company}}'s collections agent.", "greeting": "Hello, this is {{company}} about your account." }, { "code": "hi-IN", "voice_id": "hindi-voice", "greeting": "नमस्ते, मैं {{company}} से बोल रहा हूँ।" }, { "code": "ta-IN", "voice_id": "tamil-voice" } ], // "off" is the default. "follow" moves language mid-call. "language_detection": "follow" }
A voice is required on every entry after the first, and a prompt only on the first. The two missing halves fail differently: a missing prompt can be derived from the first, a missing voice cannot be derived from anything. Voices & languages
Answering a real number, this afternoon.
The portal and the API are the same three steps against the same objects — the portal is a client of the public API, not a privileged path into it. Whatever you build by clicking can be read back, diffed and recreated by a script, which is the only version of "no-code and code" that survives contact with a second environment.
Pick one of the thirty-eight and you have a working agent: prompt, greeting, filler line, temperature and the tools it wants. Add the languages it should speak and a voice for each.
Talk to it in the browser before it ever touches a phone line — the Build page dials it over the same runtime a real call uses.
Bring your own carrier over SIP, or a number from Twilio, Vobiz or Plivo. Numbers are yours and stay yours; the platform is the thing behind them, not the thing that owns them.
Outbound is the same agent with a list in front of it: upload it, see what is wrong with the list before a single number is dialled, then let the dialer pace it.
Stereo recording with caller and agent on separate channels, full transcript, per-stage latency, CSAT, and cost per call broken down by vendor — so a bad call is a thing you can open rather than a thing you are told about.
Every call fires a signed webhook when it ends, so none of this has to be somewhere you go and look.
Or skip the portal entirely — the same three steps are four API calls, in curl, TypeScript, Python, Go, PHP or Ruby. See the API
Voice AI lives or dies on the gap between turns.
You cannot buy your way under 800 milliseconds by waiting for each stage to finish and then starting the next — the arithmetic does not close. The stages have to overlap, and that is an architecture decision, not a tuning one.
- Wait for the caller to stop. A fixed silence timeout, usually 700ms, because nothing is watching for the end of a sentence.
- Wait for the transcript. The recognizer finalises, then hands over.
- Wait for the whole reply. The model finishes writing before a synthesizer is asked for anything.
- Wait for the audio. Synthesis runs to the end of the sentence, then playback starts.
- Turn detection fuses three signals. Silence, punctuation and an end-of-utterance score, instead of a fixed timeout — the cheapest 200 milliseconds on the board.
- Generation starts on the partial. The model is already writing while the recognizer confirms the last few words.
- Synthesis starts before the model finishes. A sentence aggregator releases whole clauses to text-to-speech as they form.
- The state machine is lock-free. A small compare-and-swap machine — IDLE → LISTENING → THINKING → SPEAKING — so the goroutine carrying live media never blocks on a mutex to learn what the call is doing.
Falling silent is three things at once.
Barge-in is the feature most platforms get wrong, and they get it wrong in the same place. Cancelling the generation is the obvious part. Closing the synthesis stream is the part people remember second. The one that is missed is discarding audio that is already buffered but not yet played — skip it and the agent keeps talking over the caller for a second and a half after it was interrupted, which is the exact moment a caller decides they are talking to a machine.
How a turn is actually runNot every phone line needs a language model.
A business buying a phone system is not only buying the clever part of one. Three modes, chosen per agent — because routing "press 1 to confirm" through a model buys nothing but latency, spend and variation.
The full agent
Listens, thinks, answers, and can act — knowledge, tools, workflows, transfers. Any keypad entries the agent defines are still answered from the menu without troubling the model.
A menu and nothing else
No recognizer, no model, no network call of any kind inside a turn. The menu answers in milliseconds, costs nothing per call, and keeps working on the day a vendor is down or out of quota.
Digits with no entry still fall through to the model, so an agent can take "press 1 for X" deterministically and handle anything else it is told.
A plain telephone line
Answers, reads its greeting, and puts the caller through to a number. Nothing thinks. For the overflow line, the closed-for-the-holidays number, the one on the back of the card that has always rung a desk.
With nowhere to hand off to it is an announcement line — which is the only honest thing a forwarding line with no destination can do, and a use of its own.
Everything a real call needs, and nothing it does not.
A live conversation is stateful and streaming; agent configuration and billing are neither. The two planes are split at the architecture, which is why one pins to a session and the other scales horizontally without either pretending to be the other.
Agent runtime
One session object orchestrates a single live call: the streaming pipeline, barge-in, DTMF, transfers, and tool calls executed out of band so a slow lookup never becomes dead air.
Knowledge & retrieval
Grounding runs on sphoro.kb, a separate product this platform is a customer of — integrated over its HTTP API, with its own tenant and key per account, so a bug here cannot reach another tenant's documents.
It is allowed 250ms inside a turn and fails open: a knowledge base that is slow costs a caller a less-grounded reply, never silence.
Function calling
Look up, authorize, parse, validate against JSON Schema, sandbox, run. Every problem in a malformed call is reported at once, and a failure comes back to the model as text it can act on rather than an exception that ends the turn.
Workflows
Book the appointment, update the CRM, send the email, fire the webhook — declarative steps with conditions, retries and stable idempotency keys. Any workflow can be exposed to the model as a single validated function.
Campaigns & dialer
Upload a list, preview what is wrong with it before a single number is dialled, then let the dialer pace it: calls per second the carrier tolerates, a bounded backlog, retry-versus-abandon, and per-tenant fairness.
The list lives in Postgres, never in memory — half a million rows cost the same as five hundred, and a restart resumes rather than repeats.
Voice lines, rendered once
The greeting, the filler, the menu replies and the no-match re-prompt are byte-identical across ten thousand calls. They are rendered once, cached and replayed — so the greeting has no vendor round trip in front of it.
Or upload your own recording: a real voice actor takes precedence over anything synthesized.
Recording & transcripts
A stereo WAV — caller left, agent right — because the answer to "what actually happened" nearly always hangs on who spoke over whom. Caller audio is padded to wall clock; agent bursts are placed where they were played, not where they arrived.
Analytics & CSAT
Per-stage latency percentiles, token usage, caller satisfaction, and cost per call broken down by component — on a non-blocking pipeline that never stalls the media path.
Compliance, before the dial
A do-not-call suppression list, consent records per number, and a pre-flight check you can call before placing a call — so the answer arrives before the dial rather than in a complaint afterwards.
Sixty-nine vendors, three chains, and nothing that assumes any of them.
The runtime depends on interfaces, never on a vendor. Every stage is a chain even with one member, so adding a provider is a configuration change rather than a code change — and a vendor having a bad afternoon degrades to the next one instead of dropping the call.
# Order is priority, and it is explicit. A vendor whose key # is present is a vendor that is wired in — there is no # second enable flag to forget. STT_PROVIDERS=deepgram,assemblyai,speechmatics LLM_PROVIDERS=anthropic,openai,groq TTS_PROVIDERS=cartesia,deepgram-aura,elevenlabs # A configured vendor missing from the order is appended # rather than dropped: a key that is set and then ignored # is worse than an unexpected ordering. # One secret by hand. Every vendor key moves to the portal # behind it. SPHORO_SECRET_KEY="…"
# Every five minutes, per vendor. Two consecutive failures # withdraw it; a permanent error withdraws it immediately. 10:04:12 probe tts/cartesia ok 181ms 10:04:12 probe tts/elevenlabs fail 402 voice_not_in_plan 10:04:12 probe llm/anthropic ok 240ms 10:04:13 probe stt/deepgram ok 96ms 10:09:12 probe tts/elevenlabs fail 402 voice_not_in_plan 10:09:12 withdraw tts/elevenlabs # 2 consecutive 10:09:12 chain tts → cartesia, deepgram-aura # It comes back on its own. A withdrawn vendor keeps being # probed, and one success returns it to its place.
# An agent can name its own synthesizer, voice and model. # The chain still stands behind it as the fallback. PATCH /v1/agents/ag_2rk9 { "tts_provider": "cartesia", "voice_id": "a0e99841-…", "llm_provider": "anthropic", "model": "claude-sonnet-4-5" } # A name that matches nothing configured is ignored, not # refused: dropping a vendor should never silence every # agent that was pointed at it. # Changing the voice purges that agent's cached lines, so # the greeting is not the last voice it had.
Your numbers, and one stack behind all of them.
Six carriers speak to the same telephony core; only the webhook signature and the media framing differ. We label each one by what it has actually done, not by what the code supports — a carrier badge is a promise, and promising one nobody has dialled through is a support ticket with a sales pitch on it.
# Point the number at the platform. Every carrier gets the # same three routes; only the signature differs. voice url → https://voice.sphoro.com/v1/telephony/twilio/incoming status url → https://voice.sphoro.com/v1/telephony/twilio/status media → wss://voice.sphoro.com/v1/telephony/twilio/stream # India, same shape: answer url → https://voice.sphoro.com/v1/telephony/vobiz/incoming hangup url → https://voice.sphoro.com/v1/telephony/vobiz/status
curl https://voice.sphoro.com/v1/calls \ -H "Authorization: Bearer $VOICEAI_API_KEY" \ -H 'Content-Type: application/json' \ -H 'Idempotency-Key: 8f21c4b0-…' \ -d '{"agent_id":"ag_2rk9", "to":"+919812341207", "carrier":"vobiz", "variables":{"name":"Asha","amount":"₹4,200"}}' # The record is created first, then dialled, so the callback # URLs can name it. An unfilled {{variable}} is an error # before anybody's phone rings — never an empty string read # aloud to a customer.
An API you can hold the whole shape of in your head.
REST for configuration, Server-Sent Events for watching a call, a WebSocket for driving one, and signed webhooks for everything that happens while you are not looking. The OpenAPI document is served by the API itself, so it cannot drift from the deployment you are talking to.
curl https://voice.sphoro.com/v1/agents \ -H "Authorization: Bearer $VOICEAI_API_KEY" \ -H 'Content-Type: application/json' \ -d '{"name":"Reception", "mode":"conversation", "system_prompt":"You are a friendly receptionist."}' # Watch it work. SSE with a ring buffer behind Last-Event-ID, # so a dropped connection replays the turns it missed. curl -N https://voice.sphoro.com/v1/calls/call_8f21c4b0/events \ -H "Authorization: Bearer $VOICEAI_API_KEY"
import voiceai "github.com/sphoro/sphoro.voice/sdk/go" client := voiceai.New( voiceai.WithAPIKey(os.Getenv("VOICEAI_API_KEY")), voiceai.WithBaseURL("https://voice.sphoro.com"), ) agent, err := client.Agents.Create(ctx, voiceai.AgentInput{ Name: voiceai.String("Reception"), SystemPrompt: voiceai.String("You are a friendly receptionist."), Temperature: voiceai.Float(0.4), })
from voiceai import VoiceAI client = VoiceAI(api_key=os.environ["VOICEAI_API_KEY"]) agent = client.agents.create( name="Reception", system_prompt="You are a friendly receptionist.", temperature=0.4, ) # Auto-pagination — cursors are the transport's problem. for agent in client.agents.iter(): print(agent["name"])
import VoiceAI from "@voiceai/sdk"; const client = new VoiceAI({ apiKey: process.env.VOICEAI_API_KEY }); const agent = await client.agents.create({ name: "Reception", systemPrompt: "You are a friendly receptionist.", temperature: 0.4, }); // Realtime — token deltas as the agent forms its reply. const connection = client.calls.connect(callId); await connection.ready(); connection.on("response.text.delta", m => process.stdout.write(m.text));
import dev.voiceai.VoiceAI; VoiceAI client = VoiceAI.builder() .apiKey(System.getenv("VOICEAI_API_KEY")) .build(); Map<String, Object> agent = client.agents().create(Map.of( "name", "Reception", "system_prompt", "You are a friendly receptionist."));
Every URL in a voice platform comes from a customer or a model.
The crawler, the webhooks, the HTTP tools an agent can invoke — none of those addresses is yours. That is the threat model the outbound path is written against.
Egress that fails closed
Private, loopback, link-local, CGNAT and cloud-metadata addresses are rejected at connect time, redirects are re-validated, bodies are capped and non-HTTP schemes refused — which is what makes it immune to DNS rebinding rather than merely careful about it.
Keys that cannot be recovered
API keys are 256-bit random secrets stored only as SHA-256 hashes and compared in constant time. A database leak yields hashes, not credentials. Revocation is immediate.
Tenancy that is a partition
A namespace is a hard boundary, not a filter predicate — it fails closed without a tenant and cross-checks the authenticated identity. A dedicated test asserts one tenant's credentials can never resolve to another's.
Webhooks you can trust
HMAC-SHA256 over timestamp.body, so a captured request stops verifying once it ages out of a five-minute window. Multiple signatures during a rotation mean a secret can change without dropping a delivery.
Tools that cannot run wild
Deadlines, panic containment, per-tenant rate limits and concurrency caps, truncated output. The database tool takes a query name and parameters, never SQL — a "run this SQL" tool is an injection vulnerability with extra steps.
Permissions, not role strings
Nothing asks "is this user an admin"; it asks "may this user revoke a key". Every rule that stops somebody promoting themselves lives in one place, because a privilege-escalation bug is a single missing check somewhere. One-time codes on sign-in, and a durable audit log behind it.
Limits you can see coming
Token-bucket rate limits with X-RateLimit-* on every response and Retry-After on a 429 — so a client can slow down before it is throttled rather than after.
Consent, before the dial
The TCPA sets statutory damages per call with no cap; TRAI layers registration and a national registry on top. Neither is a policy code can interpret — what it can do is make suppression, consent and time-of-day checks impossible to skip.
Nothing fetched from a stranger
The server has no third-party dependency, and neither does any SDK. This page loads no font, no script and no image from another host — which is why it renders offline and has nothing to disclose about who watched you read it.
Prepaid credit, and one number you can answer.
A customer should be able to ask "how much have I got left" and get one figure back, in one currency, that ties to a ledger they can read line by line. So the model is prepaid tokens against a rate card, not a subscription with estimated overage that cannot answer the question until the month closes. A better plan spends fewer tokens per minute — growing with the platform is never punished.
Prove it works, with no card.
≈ 60 minutes · $0.15/min
- Every provider and every language
- Knowledge bases, tools, and workflows
- 1 agent · 2 concurrent calls
A first production line.
≈ 500 minutes · $0.12/min
- Real numbers on Twilio, or Vobiz for India
- Call recordings and transcripts
- Webhooks with signed delivery
- 3 agents · 10 concurrent calls
Multiple teams, real volume.
≈ 2,500 minutes · $0.09/min
- Everything in Starter
- Provider failover chains across vendors
- Analytics history and CSAT
- Role-based access and a full audit log
- 15 agents · 50 concurrent calls
High concurrency, lowest rate.
≈ 12,000 minutes · $0.06/min
- Everything in Growth
- Bring your own provider keys
- S3-compatible recording storage
- 99.9% uptime commitment
- Unlimited agents · 200 concurrent calls
Your infrastructure, your terms.
No token charge on conversation
- Everything in Scale
- Self-hosted or private cloud
- Data residency in the US or India
- SSO, custom contracts, a named engineer
Top-ups are sold in packs of 1,000 tokens — $10 — and both figures are chosen rather than converted, so neither moves with an exchange rate. Every plan meters conversation minutes; model tokens and synthesis characters are counted but not charged. Moving between plans is done with us or by redeeming a plan code in the portal, so nobody changes tier by clicking the wrong button — mail info@sphoro.com and it takes a minute.
Do I bring my own carrier and model keys?+
You can, and on Scale and above that is the intended shape — you keep the commercial relationship with your carrier and your model providers, and Sphoro Voice is the runtime between them. On the lower tiers ours are used and metered as conversation minutes. Nothing about the platform assumes a particular vendor, because the runtime depends on interfaces rather than on any of them.
What happens when a provider goes down mid-call?+
Each of speech-to-text, the model, and text-to-speech is a chain rather than a single provider. A health probe asks every vendor every five minutes whether it still works, and two consecutive failures withdraw it before the next caller reaches it. If one fails during a turn, the chain resumes from where it left off rather than starting over — including the case where a vendor accepts the session and only then refuses the voice.
Can the agent actually do things, or only talk about them?+
Do things. Function calling validates the model's arguments against a JSON Schema and runs them in a sandbox with deadlines and per-tenant limits; the workflow engine composes those into multi-step automations with retries and idempotency keys; and a call can be handed to a human mid-conversation. A failure comes back to the model as text it can act on, so a mistyped booking becomes a follow-up question rather than a dropped turn.
Can I run outbound campaigns?+
Yes. Upload a list, see everything wrong with it before a single number is dialled, then let the dialer pace it against what your carrier tolerates — calls per second, a bounded backlog, retry-versus-abandon, and a refusal to outrun answering capacity, because a call placed with nowhere to answer it spends money to annoy a customer. Suppression and consent are checked before each dial, not after.
Where does it run?+
The data plane is geo-pinned — a live call is stateful and sticky, so it stays close to the caller. The control plane is stateless and scales horizontally anywhere. Current focus is India and the US; Enterprise adds data residency in either. Talk to us about other regions.
How do I evaluate it without a phone number?+
The whole platform runs locally with no network, GPU, database or cloud account — mock speech and language providers ship with it, and a call simulator speaks the carrier's side of the media-stream protocol so nothing on the server is stubbed. You can hear a barge-in work before you sign anything.
Tell us what the call is supposed to accomplish.
Start on the trial and hear a real turn — including the interruption — inside ten minutes. Or book thirty minutes and we will walk one end to end and be straight with you about what is ready and what is not.
No credit card · info@sphoro.com