Camlin Speech API

Speech-to-Text

Recognize Australian English WAV recordings, apply tenant lexicons, and receive JSON transcripts with confidence and word timing.

Endpoints

POST/api/v1/asr/recognize
GET/api/v1/asr/healthz
GET/api/v1/asr/lexicon
GET/api/v1/asr/lexicon/{tenant}
PUT/api/v1/asr/lexicon/{tenant}
DELETE/api/v1/asr/lexicon/{tenant}

Recognize Audio

Send RIFF/WAV bytes in the request body. Mono 16 kHz PCM is preferred; other WAV sample rates are accepted when the service can decode them.

HeaderRequiredDescription
Content-Type: audio/wavRecommendedIdentifies the body as WAV audio.
x-camlin-asr-languageNoLanguage hint. Use en-AU unless directed otherwise.
x-camlin-asr-modelNoRecognition profile. camlin-au is the production default.
x-camlin-tenant-idNoApplies a tenant lexicon for names, agencies, places, and domain vocabulary.
x-camlin-asr-backendNoOperational override. Omit for normal production traffic.
bash
curl -X POST "$CAMLIN_SPEECH_URL/api/v1/asr/recognize"   -H "Content-Type: audio/wav"   -H "x-camlin-asr-language: en-AU"   -H "x-camlin-tenant-id: acme-au"   --data-binary @sample.wav

Response Schema

json
{
  "text": "good morning, thanks for calling Camlin",
  "confidence": 0.93,
  "duration_s": 2.18,
  "backend": "gpu",
  "model": "camlin-au",
  "asr_model": "camlin-au",
  "words": [
    { "word": "good", "start": 0.12, "end": 0.38, "confidence": 0.96 }
  ]
}
FieldTypeDescription
textstringFull transcript. Empty when no speech was recognized.
confidencenumberOverall confidence in the range 0..1 when available.
duration_snumberAudio duration in seconds.
backendstringOperational route used by the service. Do not branch user logic on it.
modelstringRuntime diagnostic identifier.
asr_modelstringRecognition profile requested or selected by default.
wordsarrayOptional word-level timing and confidence entries.

Errors

StatusMeaningTypical Fix
400Empty body, invalid WAV, unknown profile, or invalid override.Re-encode to WAV and use a supported profile.
413Request too large.Split long recordings before submitting.
503Requested route unavailable.Retry with default routing or fall back to queued processing.
500Recognition failed unexpectedly.Retry once, then capture request context for support.

Tenant Lexicons

Lexicons improve recognition of names and vocabulary without changing client code. Create one once, then include x-camlin-tenant-id on recognition calls.

json
{
  "tenant_id": "acme-au",
  "names": ["Sione Tuilagi", "Aanya Reddy", "Hayden Vu"],
  "context_words": ["Centrelink", "NDIS", "BPAY"],
  "pronunciations": { "Tuilagi": "too-ee-LAH-ngee" },
  "boost": 5.0
}
bash
curl -X PUT "$CAMLIN_SPEECH_URL/api/v1/asr/lexicon/acme-au"   -H "Content-Type: application/json"   -d '{"names":["Sione Tuilagi","Aanya Reddy"],"context_words":["NDIS"]}'

Implementation Recipe

javascript
export async function recognizeWav(wavBuffer, { tenantId } = {}) {
  const headers = {
    "content-type": "audio/wav",
    "x-camlin-asr-language": "en-AU",
  };
  if (tenantId) headers["x-camlin-tenant-id"] = tenantId;

  const res = await fetch(`${process.env.CAMLIN_SPEECH_URL}/api/v1/asr/recognize`, {
    method: "POST",
    headers,
    body: wavBuffer,
  });
  if (!res.ok) throw new Error(`recognize failed: HTTP ${res.status}`);
  return res.json();
}

Operational Notes

  • Production callers should omit backend overrides and let the service route to the fastest healthy path with CPU fallback.
  • camlin-au is the customer-facing default recognition profile.
  • Lexicon data can contain customer information; keep exports out of source control and support tickets unless approved.

See also