Skip to Content
🚀 Voxtra v0.3.1 is live. Read the docs
VoxtraReferenceBackendWebhook

BackendWebhook

from voxtra import BackendWebhook from voxtra.config import WebhookConfig

Async HTTP emitter for VoxtraEvents. Fire-and-forget delivery with HMAC signing, retries, and per-event-type filtering.

WebhookConfig

class WebhookConfig(BaseModel): url: str = "" signing_secret: str = "" events: list[str] = [] timeout_seconds: float = 10.0 max_retries: int = 3 retry_backoff: float = 1.0
FieldDefaultNotes
url""Empty string disables emission.
signing_secret""When set, every request includes X-Voxtra-Signature.
events[]Allowlist of event-type strings. Empty list = all events.
timeout_seconds10.0Per-request HTTP timeout.
max_retries3Retries on 5xx / transport errors.
retry_backoff1.0Initial backoff in seconds; doubles each attempt.

Constructor

BackendWebhook( config: WebhookConfig, *, http_client: httpx.AsyncClient | None = None, )

When http_client is None, the emitter creates and owns an httpx.AsyncClient (closed on aclose() / app.stop()). Pass an external client to share it across emitters or other code — Voxtra will not close clients it doesn’t own.

Methods

await webhook.emit(event: VoxtraEvent) → bool

Deliver a single event. Returns True on a 2xx response (within the retry budget), False otherwise. Failures are swallowed and logged at WARNING — emit never raises.

await webhook.emit(some_event)

You typically don’t call this yourself — VoxtraApp calls it automatically when a webhook= is configured.

await webhook.aclose()

Close the underlying HTTP client (only if owned).

Behaviour

Signature

When signing_secret is set, the request includes:

X-Voxtra-Signature: <hmac_sha256(secret, body)>

The hex digest is computed over the raw request body (the canonical JSON, with "," and ":" separators — no whitespace).

Headers

Every request includes:

HeaderValue
Content-Typeapplication/json
User-Agentvoxtra-webhook/1
X-Voxtra-EventThe event.type string
X-Voxtra-Event-IdThe event.id (use as idempotency key)
X-Voxtra-Session-IdThe event.session_id
X-Voxtra-SignatureHMAC-SHA256 (when secret set)

Retry policy

OutcomeBehaviour
2xxDone.
4xxDrop, log at WARNING — no retry.
5xxRetry up to max_retries times.
Transport errorRetry up to max_retries times.
Retry budget exhaustedDrop, log at WARNING.

Backoff is exponential — retry_backoff, then 2×, then 4×, etc.

Filtering

events=[] (default) emits every event. To restrict:

WebhookConfig( url="...", events=[ "call.started", "call.ended", "user.transcript", # finals only — partials have a different type ], )

The string values are the EventType enum values (e.g. call.started, not CALL_STARTED).

Wiring into VoxtraApp

Constructor parameter

from voxtra import VoxtraApp, BackendWebhook from voxtra.config import WebhookConfig webhook = BackendWebhook(WebhookConfig(url="https://api.example.com/webhooks/voxtra")) app = VoxtraApp(..., webhook=webhook)

Auto-built from config

VoxtraApp.from_config(VoxtraConfig) (and from_yaml) auto-build a BackendWebhook when config.backend.webhook.url is set:

voxtra.yaml
app_name: voxtra-acme telephony: provider: asterisk asterisk: base_url: http://pbx:8088 username: voxtra-acme password: ${ARI_PW} backend: webhook: url: https://api.example.com/webhooks/voxtra signing_secret: ${WEBHOOK_SECRET} events: - call.started - call.ended
app = VoxtraApp.from_yaml("voxtra.yaml") # app._webhook is a BackendWebhook configured from the YAML

Receiver examples

See the Webhooks guide for FastAPI, Express, and Go receiver examples with signature verification.

Last updated on