osmTalk Docs
Settings

Webhooks

Subscribe to call lifecycle events with retry, HMAC signing, and a delivery log.

osmTalk POSTs lifecycle events to your URL so your CRM, dashboards, and automations stay in sync without polling.

Configure

Settings → Webhook has four fields:

  1. Webhook URL — where events are POSTed. Leave blank to disable all webhooks.
  2. HMAC secret — when set, requests include X-OsmTalk-Signature: sha256=… so you can verify the payload came from osmTalk.
  3. Events — which events fire. Default = all events (including ones we add later).
  4. Send Test — fires a webhook.test ping immediately so you can verify your endpoint before going live.

Available events

EventWhen it firesPayload includes
call.startedA call connects (web, phone, or WhatsApp)callId, agentId, channel, startedAt
call.completedA call ends with status=completedcallId, durationSeconds, costTotal, transcript
call.failedA call ends with status=failedcallId, error, failedAt
call.analysis_completedPost-call analysis finishescallId, analysis (sentiment, summary, custom fields)
campaign.lead_completedOutbound campaign lead reaches a terminal statecampaignId, leadId, status, outcome, callId
transfer.initiatedBot transfers the call to a human or another agentcallId, destination, summary
webhook.testYou clicked "Send Test"test payload

Delivery guarantees

  • First attempt is synchronous. If your endpoint responds 2xx within 15s, we mark the delivery successful.
  • Retries on 5xx, 408, 429, or network errors. Backoff is Stripe-style: +1m, +5m, +30m, +2h, +12h. After 6 failed attempts, the event moves to a dead-letter list.
  • 4xx (except 408/429) is a permanent failure. We assume your endpoint is misconfigured and won't retry, so a typo in the URL doesn't burn through your retry budget. Fix the issue and re-send manually.

Signature verification

Every request signed with your secret carries this header:

X-OsmTalk-Signature: sha256=<hex-hmac>

Verify in your handler (Node example):

import { createHmac, timingSafeEqual } from "node:crypto";

function verifyOsmtalkSignature(rawBody: string, header: string, secret: string): boolean {
  const expected = "sha256=" + createHmac("sha256", secret).update(rawBody).digest("hex");
  return timingSafeEqual(Buffer.from(expected), Buffer.from(header));
}

Always verify using the raw request body (before JSON parsing) and use a constant-time comparison.

Delivery log

Every attempt — success or failure — shows up in Settings → Webhook → Recent deliveries:

  • Event name, status code, attempt number, latency, timestamp
  • Last 50 attempts (Redis-backed, 30-day TTL)
  • Failed attempts include the error reason (HTTP 500, timeout, econnrefused)

Use this when:

  • A customer says "I didn't get the webhook" — check whether we tried, and what the response was
  • Tuning retry behavior — see how often a flaky endpoint fails
  • Debugging signature mismatches — the request was sent, you'll see your 401 response in the log

Event subscription filter

By default we send every event. If you only want certain events:

  1. Uncheck the events you don't need
  2. Save

The filter is honored at delivery time — disabled events are dropped before they reach the retry queue, so they don't count against your bandwidth or our retry budget.

Leaving all events checked means you'll automatically receive new event types we add later (e.g., analysis.alert_triggered if we ship it). If you switch to an explicit list, you opt out of that auto-subscribe.

Headers we send

HeaderValue
Content-Typeapplication/json
User-AgentosmTalk-Webhook/1.0
X-OsmTalk-EventThe event name, e.g. call.completed
X-OsmTalk-Delivery-Attempt1 for first try, incremented on retry
X-OsmTalk-SignatureHMAC-SHA256 (only if secret is configured)

Respond 200 OK (any 2xx) to acknowledge. Anything else triggers the retry path.