Skip to main content
Verbeo sends webhook events to your HTTPS endpoint as calls progress. You configure one URL per agent and Verbeo delivers all lifecycle events there automatically. This lets your systems react in real time — open a CRM record when a call starts, log duration when it ends, and push extracted insights to your database when analysis completes.

Event types

All four events carry the same call_id for a given call. Use it as your primary key to correlate events across your systems.
These events tell you what happened after the fact. To influence a call before it connects — supplying dynamic variables for the agent’s prompt, or choosing which agent answers — use the inbound call webhook, which is configured per phone number rather than per agent.

Set your webhook URL

In the Agent Editor, open Settings and fill in the Webhook URL field with your HTTPS endpoint. You can also set it via the API with Update assistant, which changes the webhook and leaves the rest of the assistant as it is:
Verbeo only delivers to HTTPS endpoints. Plain HTTP URLs are rejected. Your endpoint must present a valid TLS certificate and respond with a 2xx status promptly — Verbeo’s delivery request times out after about 12 seconds — or the event is retried.
The URL must be publicly reachable. Verbeo refuses webhook URLs that point at a private, local or cloud metadata address — for example localhost, 127.0.0.1, 10.x.x.x, 192.168.x.x or 169.254.169.254 — and sends no events to them. To receive events on a server running on your own machine, expose it through a public tunnel. Use the final address as your webhook URL: Verbeo follows a 307 or 308 redirect once, and no other redirects (see Retries).

Event payloads

All lifecycle events (call_started, call_ended, call_analyzed) share the same top-level envelope:
Dispatch in your handler using the top-level event field. For a field-by-field reference of every event, see the Webhook events reference.

call_started

Fires within 1–2 seconds of the call being answered. Contains caller/callee numbers, call type, and any dynamic variables you passed when initiating the call.

call_ended

Fires within 1–2 seconds of disconnect. Includes duration in seconds, cost in cents, and the disconnection reason. The transcript and extracted data are not yet available at this point.
Disconnection reasons: disconnection_reason is an open string — Verbeo may return additional or more specific values over time, so treat any value you don’t recognize gracefully rather than assuming a fixed set.

call_analyzed

Fires once, when the summary and post-call analysis are ready — usually within seconds of the call ending. If generating them fails, Verbeo keeps retrying and the event can take up to 3 hours; it is still sent only once, and in that rare case summary or analysis_data can be null. This is the primary event for downstream integrations. It carries the full transcript, AI-generated summary, your extracted analysis_data fields, a log of every tool executed, and a recording URL.
The transcript array interleaves user, agent, and tool turns in chronological order. A tool turn carries tool_name, query, status_code, result, error, and documents. The transcript_clean array is the same conversation with the tool turns removed — use it when you want only the human-readable dialogue. The tools array is a separate, flat log of every tool the agent executed, where tool_type is an open value such as custom, native, or knowledge_base.
The recording_url is a pre-signed, time-limited link. Download and store the audio in your own system if you need it beyond the signature window.

tool_invoked

Fires during the call, every time the agent invokes one of your custom tools. This event is sent directly to the tool’s configured endpoint URL — not to the agent’s webhookUrl.
Your handler must respond within 10 seconds with JSON. See the Custom tools guide for the full response format.

Handle webhooks reliably

Respond with 2xx immediately

Return a 200 OK as fast as possible — Verbeo’s delivery request times out after about 12 seconds. If your processing takes longer, queue the payload and acknowledge immediately:
Respond from the webhook URL itself. Verbeo follows a 307 or 308 redirect once; any other 3xx, or a second redirect, counts as a failed delivery. Configure the final URL rather than relying on a redirect.

Retries

Any response other than 2xx — or no response within 12 seconds — is retried, up to 12 automatic attempts per event (a resend from the dashboard starts a fresh series):
  • The wait between attempts doubles from 2 minutes up to a cap of 6 hours, so the last attempt comes about 26 hours after the first.
  • If a 429 or 503 response carries a Retry-After header, Verbeo waits that long instead (between 1 minute and 6 hours).
  • A 307 or 308 redirect is followed once, re-sending the same request to its Location. Other 3xx responses, and a second redirect, are not followed and count as failures.
See Retries for the exact schedule.

Make your handler idempotent

Verbeo retries events if your endpoint returns a non-2xx response or times out — a background reconciler re-drives any event that wasn’t confirmed delivered, and you can resend manually from the dashboard (see Monitor and retry deliveries). The same event can therefore arrive more than once. Deduplicate on (call_id, event):
In production, use a persistent store (Redis, database) rather than an in-memory set. Once Verbeo has recorded a 2xx from your endpoint for an event, it never sends that event again on its own, so a repeat you did not ask for is a retry and safe to skip. The only other repeats come from your team in the dashboard: Retry on a call’s Webhooks tab (see Retry a delivery), and Enhance Transcript, which sends call_analyzed again with the improved transcript. If you want that transcript, update the stored call instead of skipping the repeat.

Events may arrive out of order

Verbeo delivers each call’s events in order — call_started, then call_ended, then call_analyzed — and holds a later event while an earlier one is still being retried, until 30 minutes after the call ended. If your endpoint is down for longer than that, later events are sent anyway and can arrive before earlier ones; the same goes for resends from the dashboard after that point. Each event is self-contained — process them independently rather than relying on order.

Example Express.js webhook handler

Monitor and retry deliveries in the dashboard

Every delivery attempt is recorded — the full request Verbeo sent and the full response your endpoint returned — so you can confirm exactly what Verbeo sent and debug failures without adding any logging on your side. Open Call History, click a call to open its details, and select the Webhooks tab. Attempts are grouped by event, newest first. Each row shows: The outcome is one of: Expand an attempt to see the full exchange:
  • Request — POST and the destination URL, every header Verbeo sent, and the exact JSON body, with a copy button.
  • Response — the status code, headers and body your endpoint returned (up to 16 KB of body), or the error message when there was no response.
Developers, admins and owners see the full request and response; the member role sees metadata only — the event, attempt number, time, outcome, status code, duration, source and the endpoint’s host. Attempt details are kept for 30 days for successful deliveries and 7 days for failed ones. Calls delivered before Verbeo started recording full requests keep the earlier view: one row per delivery attempt, newest first, across all three lifecycle events. In that view, expand a row to see the destination URL, a summary of the payload that was sent, and the response body or error your endpoint returned. Full URLs and payloads are visible to developers, admins and owners; the member role sees metadata only. Verbeo keeps the most recent 50 attempts per call.

Retry a delivery

If your endpoint was down, click Retry, choose which events to resend (All, Started, Ended, or Analyzed), and click Send. Verbeo sends the selected events in lifecycle order and doesn’t stop at a failure: any event that fails, or has to wait for an earlier one, stays queued and is retried automatically. A resend more than 30 minutes after the call ended isn’t held for ordering, so call_analyzed can arrive before a call_ended that is still failing. The tab then polls for a few minutes to surface the new attempts as they land. Manual retry is available to developers, admins and owners. A resend sends exactly the body Verbeo sent before. When Verbeo no longer has that body — more than 30 days after the event was first sent, or for a call from before Verbeo started recording full requests — it rebuilds the event from the call’s current data.
Verbeo also retries failed deliveries automatically in the background, so a transient outage usually resolves itself. Use manual retry when you’ve fixed your endpoint and want the data redelivered right away.

Security recommendations

  • Verify the event field before processing. Unknown events should be ignored, not errored.
  • Use HTTPS with a valid certificate. Plain HTTP endpoints are rejected before any events are sent.
  • Authenticate inbound requests by adding a shared secret to the agent’s webhook URL as a query parameter (e.g. https://api.yourcompany.com/webhooks?secret=abc123) and validating it in your handler.
  • Verbeo does not currently sign webhook payloads. There is no HMAC signature header to verify — rely on the shared-secret query parameter above, and optionally allow-list Verbeo’s egress IP range (contact support@verbeo.ai for the current addresses).
  • Don’t return secrets in webhook responses. Verbeo records each attempt’s full URL, including its query parameters (so a shared secret in the URL too), and your endpoint’s response headers and first 16 KB of response body. It shows them in the dashboard to the developers, admins and owners of your workspace for up to 30 days. Keep tokens and session cookies out of your webhook responses.
  • Do not log full transcripts to services that cannot handle PII. Transcripts may contain names, phone numbers, emails, and other personal data.
  • Store recording_url contents promptly. The pre-signed URLs expire — download recordings to your own storage if you need them for compliance or QA.