Quickstart

First working request in about a minute. Two steps: get a key, then say something.

1. Get your key

Sign up, then make a key in the dashboard: create an account and open API keys. The full key is shown once and only a hash is kept, so there is no way to read it back afterwards — copy it then.

export LATENCY_API_KEY="sk-lat-..."

Or from the API, if you already have a key and want another for a specific integration:

curl -X POST https://api.latency.cam/v1/api-keys \
  -H "Authorization: Bearer $LATENCY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name": "CRM integration"}'

Revoking is immediate, on HTTP and on the websocket, and GET /v1/api-keys reports when each key was last used — which is what makes an unused one safe to revoke.

One header, every endpoint. No rate limits, no quotas, no per-model gating, no concurrency caps.

TLS is liveEverything is HTTPS, 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.raw

format: "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"]'
Always use restrict_to when you canIt is the single biggest accuracy lever on this endpoint. Telugu versus Tamil is reliable. Hindi versus Urdu is not — they are near-identical when spoken. Never build a feature that depends on separating those two by audio alone.

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: "fast",
  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 20ms

Full websocket protocol →

Use 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="fast",
    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.

Or skip the API entirely

Everything above is also a screen. If you are not integrating, the shorter route to a working agent is the dashboard: describe what you want in a sentence and let it write the first version, or start from one of the five templates, then press the call button and talk to it in your browser. Uploading documents, connecting Twilio, running a campaign from a CSV, reading transcripts and watching the numbers are all there too. The API and the dashboard are the same endpoints — there is no capability that is only reachable by writing code.

What to read next