Webhooks and callbacks
Voice (Retell)
3 endpoints.
/api/v1/voice/retell/eventsRetell Call Events
Retell call-lifecycle webhook: every ended/analyzed call becomes a contact + call record (see ingest.py for the notification posture).
``call_ended`` writes the base record; ``call_analyzed`` upserts the summary and the post-call capture onto the same row (idempotent by provider call id). The capture (design doc P22) prefers the post-call analysis fields (``call_analysis.custom_analysis_data`` — whole-transcript extraction) and falls back to what the mid-call extract tool collected (``collected_dynamic_variables``); both are only present on ``call_analyzed``. Always 200 — Retell retries 5xxs and duplicates are wasted work.
Responses
200Successful Responseapplication/jsonobject400Bad request401Unauthorized403Forbidden404Not found422Validation error500Internal server error503Service unavailable
Error bodies: ErrorResponse. See Errors.
/api/v1/voice/retell/inboundRetell Inbound Webhook
Resolve dialed number → business, inject its context as dynamic variables.
Request bodyrequired
application/jsonInboundWebhookRequest| Field | Type | Description | |||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
eventrequired | string | ||||||||||||||||
call_inbound | InboundCallPayload | null | InboundCallPayload fields
|
Responses
200Successful Responseapplication/jsonInboundWebhookResponse| Field | Type | Description | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
call_inbound | InboundCallResponse | default {}InboundCallResponse fields
|
400Bad request401Unauthorized403Forbidden404Not found422Validation error500Internal server error503Service unavailable
Error bodies: ErrorResponse. See Errors.
/api/v1/voice/retell/toolRetell Tool Webhook
Retell custom-function endpoint: dispatch mid-call tool calls.
Retell POSTs ``{"name": ..., "args": {...}, "call": {...}}`` signed with the same ``x-retell-signature`` scheme as the inbound webhook (same key). Tenant identity comes from ``call.metadata.business_id`` — the value OUR inbound webhook planted, which is why it's trustworthy (design doc §6.4). The response body is a plain JSON string: Retell hands it to the agent's LLM verbatim, so failures are honest instruction strings, never 5xx.
Responses
200Successful Responseapplication/jsonany400Bad request401Unauthorized403Forbidden404Not found422Validation error500Internal server error503Service unavailable
Error bodies: ErrorResponse. See Errors.