Quickstart
First working request in about a minute. The only thing that usually goes wrong is the GPU being switched off, so we check that first.
0. Check the GPU is on
The GPU is stopped when nobody is using it. This endpoint always answers because it runs on Vercel, not on the GPU box.
curl https://latency.cam/api/status
{
"state": "stopped",
"readyInSeconds": null,
"ratePerHourInr": 107,
"hint": "GPU is off. Turn it on at https://latency.cam and allow about 3 minutes."
}state reads running but readyInSeconds is above zero and requests still fail. Wait for it to reach 0.1. Get your key
Keys live on the GPU box, in a root-owned file. Whoever has SSH access can read the current one:
ssh -i ~/.ssh/voicelab-key.pem ubuntu@<BOX_IP> \ "sudo grep API_KEYS /etc/latency-api.env"
Then set it locally:
export LATENCY_API_KEY="sk-lat-..."
One header, every endpoint. No rate limits, no quotas, no per-model gating, no concurrency caps.
api.latency.cam resolves to an Elastic IP and Caddy holds a real Let's Encrypt certificate, so the key travels encrypted. The websocket is the one exception to the header rule: browsers cannot set headers on a WebSocket, so it takes ?api_key=sk-lat-... in the URL instead.2. Say something
curl -X POST https://api.latency.cam/v1/audio/speech \
-H "Authorization: Bearer $LATENCY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"input": "Namaste, aapka EMI 15250 rupay ka hai, due date 4 tarikh hai.",
"language": "hi",
"format": "mulaw_8000",
"stream": true
}' --output reply.rawformat: "mulaw_8000" gives you telephony-ready audio. We do the downsampling — don't do it yourself.
Note what happened to 15250: because normalize defaults to true, it was spoken as "pandrah hazaar do sau pachas rupay", not as digits. Turn that off and the call immediately sounds like a robot.
3. Listen to a caller
curl -X POST https://api.latency.cam/v1/audio/transcriptions \ -H "Authorization: Bearer $LATENCY_API_KEY" \ -F file=@call.wav \ -F language=te
Omit language and we detect it, which adds roughly 150 ms. If you know the caller's language from your CRM, pass it — that is both faster and more accurate.
4. Work out which language they spoke
curl -X POST https://api.latency.cam/v1/lid \ -H "Authorization: Bearer $LATENCY_API_KEY" \ -F file=@caller.wav \ -F 'restrict_to=["ta","te","kn","ml"]'
5. Run a whole call
One websocket. You do not orchestrate anything — VAD, turn detection, barge-in, the LLM and TTS all run server side.
// The key goes in the URL: browsers cannot set headers on a WebSocket.
const ws = new WebSocket(
`wss://api.latency.cam/ws/stream?api_key=${process.env.LATENCY_API_KEY}`
);
ws.onopen = () => ws.send(JSON.stringify({
type: "configure",
language: "hi",
script: "roman",
audio_format: "mulaw_8000",
llm: "nova-lite",
interrupt_min_words: 3,
system_prompt: "You are a delivery helpdesk. Reply in Hindi, under 12 words."
}));
ws.onmessage = (e) => {
if (e.data instanceof Blob) playToCaller(e.data); // raw audio, no header
else console.log(JSON.parse(e.data)); // events
};
// then push 160-byte frames of 8kHz mulaw, one every 20msUse an existing OpenAI SDK
The LLM endpoint is OpenAI-compatible. Change the base URL and nothing else.
from openai import OpenAI
client = OpenAI(
base_url="https://api.latency.cam/v1",
api_key=os.environ["LATENCY_API_KEY"],
)
r = client.chat.completions.create(
model="nova-lite",
messages=[{"role": "user", "content": "Mera EMI kitna hai?"}],
max_tokens=60, # keep replies short — long ones sound robotic on a call
)Only the chat endpoint is OpenAI-shaped. The audio endpoints take input and language and return raw audio, so use plain HTTP for those.
6. Translate
curl -X POST https://api.latency.cam/v1/translate \
-H "Authorization: Bearer $LATENCY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"text": "Your order will arrive tomorrow between 10 am and 12 pm.",
"source_language": "en",
"target_language": "ta"
}'23 languages. English to any of them and back is direct; Indic to Indic pivots through English and the response tells you so.
What to read next
- Point your AI assistant at the docs — fastest way to get productive
- Model catalog — which model for which language, and which ones you cannot legally ship yet
- Known gaps — what does not work, stated plainly