Webhook API

API reference for passthrough mode webhooks

Overview

In passthrough mode, chans sends transcribed speech to your webhook and expects a text response.

Request Format

POST /your-webhook-url

chans sends a POST request with the following JSON body:

{
"type": "transcription_complete",
"session_id": "room-abc123",
"timestamp": "2024-01-15T10:30:00.000000",
"data": {
"transcript": "What's my order status?",
"user_id": "end-user-123",
"context": null
}
}

Fields

FieldTypeDescription
typestringEvent type (see Event Types below)
session_idstringUnique session/room identifier
timestampstringISO 8601 timestamp
data.transcriptstringTranscribed user speech
data.user_idstring | nullEnd user identifier (from SDK connection)
data.contextstring | nullRAG context if enabled on the agent

Response Format

Your webhook must respond with JSON:

{
"response": "Your order #1234 is out for delivery!"
}

Response Fields

FieldTypeDescription
responsestringText to be spoken back to the user

Timeout

Your webhook has 30 seconds to respond by default. If your webhook times out, the user hears nothing for that turn and the agent continues listening.

Authentication

If you configure an API key in your agent settings, chans includes it in the request:

Authorization: Bearer your-api-key

Error Handling

If your webhook returns a non-2xx status code:

  1. The error is logged
  2. The user hears no response for that turn
  3. The agent continues listening for the next utterance

Example Implementation

Node.js / Express

app.post('/webhook', async (req, res) => {
const { type, session_id, data } = req.body
const { transcript, user_id } = data
// Call your LLM
const response = await yourLLM.chat(transcript, {
userId: user_id,
sessionId: session_id
})
res.json({ response: response.text })
})

Python / FastAPI

@app.post("/webhook")
async def webhook(payload: dict):
transcript = payload["data"]["transcript"]
user_id = payload["data"].get("user_id")
session_id = payload["session_id"]
# Call your LLM
response = await your_llm.chat(
transcript, user_id=user_id, session_id=session_id
)
return {"response": response}

Event Types

The main passthrough call uses transcription_complete (synchronous -- expects a response). chans also supports async events sent to a separate events URL:

Event TypeSync/AsyncDescription
transcription_completeSyncUser speech transcribed. Expects {"response": "..."}
context_retrievedAsyncRAG context was retrieved for the query
llm_responseAsyncAgent response generated
audio_readyAsyncTTS audio generated
session_startAsyncVoice session started
session_endAsyncVoice session ended

Async events are fire-and-forget notifications sent to your configured events URL. They include retry with exponential backoff (up to 3 retries). Configure the events URL separately from your main webhook URL in agent settings.