Skip to content

Developers

Webhooks

Connect your software to updates about calls, minutes and workers. The endpoint must use HTTPS. Its signing secret is shown once.

Operations

Each is POST /v1/ops/{name} with JSON and an owner key (Authorization: Bearer <key>). A helper key cannot manage endpoints.

  • webhook.create { "url": "https://your-domain.example/events", "events": ["call.ended"] } (events optional: all when left out). Answer { "id", "url", "events", "secret", "created_at" }. HTTPS on port 443 only, a domain name, no credentials, query or fragment; it must resolve to public addresses. The secret is in this answer only.
  • webhook.list {}. Answer { "endpoints": [{ "id", "url", "events", "created_at" }] }: active endpoints, never a secret.
  • webhook.update { "endpoint_id", "events" } (one or more, no repeats). Answer { "id", "events" }. A newly chosen event is sent from then on, never for the past.
  • webhook.rotate { "endpoint_id" }. Answer { "id", "secret" }: the new secret, once; the old one signs nothing from then on.
  • webhook.revoke { "endpoint_id" }. Answer { "revoked" }.

Refusals come as { error: { code, message }, request_id }: invalid_input (400) for a URL that is not allowed, rejected (409) when the endpoint limit is reached or the URL is already registered, not_found (404) for an endpoint that is not this account's.

Events

Each delivery is a JSON POST with the headers x-telfluent-event-id: evt_<id> and x-telfluent-signature: t=<Unix milliseconds>,v1=<hex HMAC-SHA256>. The HMAC input is the timestamp, a dot, then the exact raw body; the key is the endpoint's secret. Compare in constant time, reject an old timestamp, and deduplicate by event id.

Body: { "id": "evt_<id>", "type": "<event>", "data": { ... } }. An endpoint receives only the events it chose.

  • call.ended: data.call_id.
  • minutes.low: data.remaining_minutes, data.period_start; once a billing period.
  • worker.joined: data.worker_id.

Delivery is at least once and may be out of order. A 2xx answer acknowledges; anything else, a redirect included, is retried with growing waits, a limited number of times over about a day. Each attempt waits at most 10 seconds. No audio, transcript, payment detail or another account's data is ever in an event.