Skip to main content
Webhooks allow RevRing to communicate with your systems before and after phone calls, enabling deep integration with your CRM, databases, and business logic.

Webhook Types

RevRing supports two types of webhooks:
  • Pre-Call Webhooks: Called before an inbound call is answered, allowing you to personalize the agent’s behavior
  • Post-Call Webhooks: Called after any call ends, providing complete call details including transcript and recording

Pre-Call Webhooks

Pre-call webhooks enable dynamic customization of agent behavior based on caller information. Before answering an inbound call, RevRing sends caller details to your webhook and uses the response to personalize the conversation.

When to Use

  • Look up caller information in your CRM
  • Customize greetings based on customer status or history
  • Route calls differently based on caller context
  • Apply business hours logic or special handling
  • Personalize the agent’s knowledge with customer-specific data

Configuration

  1. Navigate to your agent’s Advanced tab
  2. Set the Pre-call Webhook URL:
  3. Click Save
Pre-call webhooks only apply to inbound calls. Outbound calls receive variables directly via the API when the call is sent.

Request Format

When an inbound call arrives, RevRing sends a POST request to your webhook:
Field Descriptions:
  • event: Always "pre_call" for pre-call webhooks
  • agentId: The agent that will handle the call
  • fromNumber: Caller’s phone number (E.164 format)
  • toNumber: The number that was dialed
  • dialedAgentId: The agent ID when the call was routed directly to an agent (null if routed via phone number)
  • callback: Present only when the caller is returning a call your account placed in the callback window: { "callId", "calledAt", "outcome" } (the outbound call, when it was placed, and answered, voicemail, no_answer, busy or declined). See Callbacks

Response Format

Your webhook must respond within 5 seconds (aim for well under one: the caller is waiting in silence) with a JSON object containing variables:
These variables will be available in the agent’s prompt and first message using {{variable_name}} syntax.
Variables you return can override system variables like {{current_time}} and {{timezone}} if needed. However, system variables ({{direction}}, {{user_number}}, {{agent_number}}, {{current_time}}, {{timezone}}, {{language}}) are automatically provided and don’t need to be set via webhook.

Route, personalize or reject the call

The response can also decide how the call runs. Every field is optional:
If the agent or environment you name does not exist, the call runs on the dialed agent as usual, so a mistake in your webhook never drops a caller.
Moving from another platform? A Retell inbound webhook answer ({ "call_inbound": { "override_agent_id", "dynamic_variables" } }) and an ElevenLabs conversation initiation answer (dynamic_variables, conversation_config_override.agent.first_message and .prompt.prompt) work as they are. A Retell agent id resolves to the agent you imported from it.

Using Variables in Agent Configuration

Reference webhook variables in your First Message:
And in your Prompt:

Error Handling

If your webhook fails, times out, or returns invalid JSON:
  • RevRing will proceed with the call using default variables (if configured)
  • The call will not be rejected - the agent will answer without personalization
  • Check the call’s preCallWebhookStatus field to see webhook delivery status
Webhook Status Values:
  • sent: Webhook responded successfully
  • failed: Webhook returned an error or timed out
  • skipped: No webhook URL configured
  • null: Call has not yet reached the webhook stage

Example Implementation

Node.js / Express:
Python / Flask:

Post-Call Webhooks

Post-call webhooks deliver complete call details immediately after a call ends, including the transcript, recording URL, summary, and metadata.

When to Use

  • Update your CRM with call outcomes
  • Log call details for compliance or auditing
  • Trigger follow-up workflows (emails, tasks, tickets)
  • Track agent performance metrics
  • Store transcripts and recordings in your system
  • Implement custom analytics or reporting

Configuration

  1. Navigate to your agent’s Advanced tab
  2. Set the Post-call Webhook URL:
  3. Click Save
Post-call webhooks fire for both inbound and outbound calls.

Request Format

After a call ends, RevRing sends a POST request with complete call details:
Key Fields:
  • id: Unique call identifier
  • organizationId: Your organization ID
  • agentId: The agent that handled the call
  • agentName: The agent’s display name
  • sipTrunkId: SIP trunk used for the call (null if not applicable)
  • direction: INBOUND or OUTBOUND
  • status: Final call status (COMPLETED, TRANSFERRED, FAILED, CANCELED)
  • fromNumber / toNumber: Caller and recipient numbers (E.164)
  • agentCallerIdName: Caller ID name configured on the agent (null if not set)
  • variables: All template variables used during the call — includes variables from pre-call webhooks, API call variables, and system variables (direction, current_time, timezone, etc.)
  • recordingUrl: URL to download the call recording (null if recording disabled or call not answered)
  • hangupCause: Reason call ended. Common values include USER_ENDED, END_CALL_TOOL, SILENCE_TIMEOUT, MAX_DURATION, VOICEMAIL_DETECTED
  • transcript: Complete conversation with timestamps and tool invocations (both custom tools and system tools like end_call, transfer_to_number)
  • summary: AI-generated summary of the call
  • extraction: Structured fields pulled from the transcript, as configured in the agent’s postCallExtraction (see Post-call data extraction); null when not configured
  • evaluation: Pass/fail/unknown verdicts for the agent’s postCallEvaluation criteria, each with a rationale (see Post-call evaluation); null when not configured
  • campaignId: The campaign that placed the call; null for calls not placed by a campaign
  • metrics: Token usage, audio durations and response latency (see Response latency)
  • durationSeconds: Total call duration (null if never answered)
The example above shows both a custom tool (check_order_status) and a system tool (end_call). When a call is transferred using transfer_to_number, the transcript will contain a similar tool entry with name: "transfer_to_number" and args containing to_number.

Response latency

metrics.latency shows how quickly the agent answered on this call, measured per agent turn and summarized as count, p50_ms, p90_ms and max_ms (milliseconds): Interrupted or discarded replies are not counted, and neither are acknowledgments the caller says while the agent is talking. Calls where the caller never spoke have count: 0. stop_to_audio and stop_to_eot are present on calls from October 10, 2026. Timing on each agent turn Agent turns in a call’s transcript carry a latency object with how long that reply took, in milliseconds. Only measured values are included.
The call page shows each reply’s time next to the turn, and the agent page shows the agent’s typical reply time over its recent calls (GET /v1/analytics/reply-times?agentId=). Tool timing fields Custom tool entries carry how long your webhook took to respond, so you can measure tool latency yourself from the transcript, with no need to ask support: The same timing is shown on each tool card in the call transcript in the dashboard.
For complete field descriptions and additional examples, see the Post-Call Webhook API Reference.

Post-call data extraction

Define the fields you want pulled out of every conversation and the platform fills them in from the transcript after each call. The result lands on the call record as extraction (GET /calls/{id}) and in the post-call webhook, so your systems get typed values instead of parsing the summary. Configure it on the agent with postCallExtraction:
Each field has: How it behaves:
  • Up to 20 fields per agent. Set postCallExtraction to null to turn it off.
  • Values come only from what was said on the call. A field that was not stated, or was unclear, is null, never guessed.
  • Every configured field is present in the result, so your handler can rely on the keys.
  • Extraction runs after the call ends, alongside the summary, and is skipped for calls with no caller speech (unanswered dials, dead lines). Those calls carry extraction: null.
  • The result is included in the same post-call webhook delivery. No extra request to make.
A matching result for the config above:
Keep descriptions specific. “The caller’s budget in dollars” extracts better than “budget”, and enum fields with a short list of values give you clean data for routing and reporting.

Post-call evaluation

Write the outcomes you care about in plain language and every call is judged against them after it ends. Each criterion comes back as pass, fail or unknown with a one-sentence rationale, on the call record as evaluation (GET /calls/{id}) and in the post-call webhook. Use it for success rates, QA sampling and routing follow-ups. Configure it on the agent with postCallEvaluation:
How it behaves:
  • Up to 10 criteria per agent. Set postCallEvaluation to null to turn it off.
  • A criterion that asks the agent to do something is fail when the call reached that point and the agent did not do it: a skipped required action counts against the agent.
  • A criterion about an outcome that depends on the caller (they book, buy, pay or share information) is fail when the call got to that topic and it did not happen, and unknown when the call never got there.
  • unknown also covers calls that ended before the agent could respond, so your success rate reflects what actually happened rather than guesses.
  • Every criterion is present in the result, so your handler can rely on the keys.
  • Runs after the call ends, alongside the summary and extraction, and is skipped for calls with no caller speech. Those calls carry evaluation: null.
  • Included in the same post-call webhook delivery.
A matching result:
Pass rates per criterion over any date range are in the analytics overview (evaluation) and on the dashboard’s Analytics page, so success rates need no spreadsheet.
State each criterion as a single observable outcome. “The caller confirmed an appointment date and time” judges cleanly; “the call went well” does not. Conditional criteria work too: “If the caller asked about pricing, the agent quoted the monthly price”.

Caller sentiment

Every call with caller speech gets a sentiment: how the caller felt over the call as a whole, positive, neutral, negative or unknown (the caller barely spoke or the call ended too soon to tell). It is on the call record (GET /calls/{id}), in the post-call webhook, and in the call-history export. Calls with no caller speech carry sentiment: null. With the Retell compatibility format, it fills call_analysis.user_sentiment (an imported user_sentiment extraction field takes precedence).

Re-run analysis on past calls

Changed an agent’s extraction fields or success criteria? Re-run extraction, evaluation and sentiment on past calls with the agent’s current settings, without placing new calls:
In the dashboard, open a call and select Re-run analysis. A field or criterion that was removed from the agent is cleared on the call. Calls still in progress, calls with no caller speech, and calls whose content was deleted under the agent’s data controls are skipped.

Export call history

GET /v1/calls/export returns a CSV of calls, newest first (up to 10,000 per file), filtered by agentId, status, direction, from and to. Columns: call details, sentiment, summary, recordingUrl, one var.* column per call variable, one extraction.* column per extracted field, and one evaluation.* column per success criterion (its result). In the dashboard, use Export CSV on Calls. Cells that would run as a spreadsheet formula are prefixed with an apostrophe.

Call started event

To also hear when a call connects, set the agent’s webhookEvents to ["call.started"]. The post-call webhook URL then receives, once per answered call:
The post-call payload itself has no event field, so a handler can tell the two apart. With the Retell compatibility format the event is Retell’s call_started. Started events are sent once and are not retried.

Transfer events

To hear about transfers as they happen, add any of transfer.started, transfer.bridged and transfer.cancelled to the agent’s webhookEvents (or turn on Also send transfer events in the agent’s Advanced tab). The post-call webhook URL then receives:
With the Retell compatibility format the events are Retell’s transfer_started, transfer_bridged and transfer_cancelled. Transfer events are sent once and are not retried; the post-call webhook still arrives when the call ends.

Compatibility formats

Moving from another voice platform? Set the agent’s postCallWebhookFormat and the post-call webhook is sent in that platform’s payload shape, so the handler you already run keeps working while you switch. Agents created by the importer get this set for you. The values come from the call record: extraction fields become Retell’s custom_analysis_data or ElevenLabs’ data_collection_results, evaluation criteria become call_successful (and ElevenLabs’ evaluation_criteria_results), and an extraction field named user_sentiment fills Retell’s user_sentiment. Fields that only exist on the other platform, such as costs or per-word timings, are not sent. Deliveries are signed with RevRing’s X-RevRing-Signature header, not the other platform’s signature, so replace your signature check (see Verify webhook sources). Retries work as described below.

Response Expectations

Your webhook should:
  • Respond with 200 OK status code
  • Respond within 30 seconds (a few seconds is better: acknowledge first, then process)
  • Handle the webhook asynchronously if processing takes time
RevRing does not require any specific response body. Simply acknowledge receipt:
Retries: a delivery that fails (connection error, timeout, or any non-2xx response) is retried three times, 1 minute, 5 minutes and 30 minutes later. Make your handler idempotent on the call id: a retry carries the same payload, and a slow handler that returned after our 30 second timeout may be retried even though it processed the call. The call record shows the outcome in postCallWebhookStatus (sent, retrying, failed) with postCallWebhookAttempts.

Error Handling

If your webhook fails (non-2xx status), can’t be reached, or times out:
  • The delivery is retried automatically 1, 5 and 30 minutes later (see Retries above); postCallWebhookStatus is retrying meanwhile
  • After the last retry it is marked failed in the call record
  • To backfill anything that ended failed (for example after a long outage on your side), list recent calls with GET /calls and check postCallWebhookStatus
Webhook Status Values:
  • sent: Delivered successfully
  • failed: Webhook returned an error or timed out
  • skipped: No webhook URL configured
  • null: Call has not yet reached the webhook stage

Example Implementation

Node.js / Express:
Python / Flask:

Security Best Practices

Verify Webhook Sources

Signature verification (recommended): Turn on webhook signing for your organization and verify every request. One secret signs every webhook RevRing sends you: pre-call, post-call and message received.
  1. Create a secret (the full value is returned only by this call; store it with your other secrets):
  1. From then on each webhook carries two headers:
  1. Verify on the raw request body, before parsing JSON, and reject timestamps older than a few minutes:
Rotate with the same POST (the new secret is live within a minute; verify against both during the switch), check the state with GET, and turn signing off with DELETE. See the signing secret reference. Request Validation: Implement validation to ensure webhook requests contain expected fields and structure.

Use HTTPS

Always use HTTPS for webhook URLs to ensure data is encrypted in transit:

Validate Payload

Validate incoming webhook data before processing:

Rate Limiting

Implement rate limiting to prevent abuse:

Testing Webhooks

Local Development with ngrok

For local testing, use ngrok to expose your local server:
Use the ngrok HTTPS URL in your webhook configuration:

Testing Tools

Request Inspection: Use webhook.site to inspect webhook payloads without writing code. Manual Testing: Use curl to simulate webhook responses:

Test with Real Calls

  1. Configure your webhook URL in the Advanced tab
  2. For pre-call webhooks: use the test panel to make a browser call and check your server logs
  3. For post-call webhooks: use either the test panel or the Make a Call page
  4. Check call details in Calls to verify webhook status

Monitoring Webhooks

Check Webhook Status

For each call in Calls:
  1. Click on the call to view details
  2. Check Webhook Status in the Overview card:
    • Pre-call webhook status
    • Post-call webhook status
  3. If failed, review your server logs for errors

Common Issues

  • Ensure your webhook responds within 5 seconds (pre-call; the caller is waiting) or 30 seconds (post-call)
  • Move slow operations (database writes, external API calls) to async background processing
  • Return acknowledgment immediately, then process in background
  • Check your server’s response time and optimize slow queries
  • Verify your endpoint is accessible from the internet
  • Check that you’re returning a 200 status code
  • Ensure response is valid JSON (even if empty: {})
  • Review server logs for exceptions or errors
  • Test endpoint with curl or Postman to verify it works
  • Verify your pre-call webhook returns valid JSON with variable keys
  • Check variable names match exactly between webhook and prompt (case-sensitive)
  • Ensure the webhook responds within 5 seconds; after that the call starts without its variables
  • Test webhook independently to confirm it returns expected data
  • Review the call’s variables field in call logs to see what was actually received
  • Confirm the webhook URL is configured in the agent’s Advanced tab
  • Verify the URL is correct and accessible
  • Check your server logs - RevRing may be sending but your server isn’t logging
  • Test with webhook.site to confirm RevRing is sending requests
  • Review firewall rules that might block incoming requests

Best Practices

Performance

  • Respond quickly: Acknowledge webhooks within 1-2 seconds
  • Process asynchronously: Handle heavy processing in background jobs
  • Cache frequently: Cache CRM lookups or database queries when possible
  • Use connection pooling: Reuse database connections across requests
  • Set timeouts: Configure timeouts for external API calls to prevent hanging

Reliability

  • Idempotency: Design webhooks to handle duplicate calls (use id as idempotency key)
  • Error handling: Wrap processing in try/catch and return 200 even if internal processing fails
  • Logging: Log all webhook requests and responses for debugging
  • Monitoring: Set up alerts for webhook failures or high error rates
  • Fallbacks: Provide default values if lookups fail

Security

  • HTTPS only: Never use HTTP for webhook URLs
  • Validate input: Sanitize and validate all incoming data
  • Request validation: Verify requests contain expected structure and fields
  • Rate limiting: Protect against potential abuse
  • Audit logging: Log all webhook activity for security review

Advanced Patterns

Dynamic Agent Customization

Use pre-call webhooks to provide variables that customize agent behavior for each caller: Webhook Response:
Reference in First Message:
Reference in Prompt:

Call Outcome Tracking

Use post-call webhooks to track outcomes and trigger workflows:

Inbound Message Webhook

When an agent’s inbound messaging mode is set to notify, RevRing forwards each incoming text to a webhook URL you choose, and your own system composes and sends the reply. (In auto-reply mode RevRing replies automatically from the agent’s SMS prompt, and no webhook is sent — see Two-way texting.)

When to Use

  • You orchestrate replies yourself (in N8N, Make, your CRM, etc.) and want full control over each reply.
  • You want to log, score, or branch on an inbound text before responding.

Configuration

  1. On the agent’s Messaging tab, set When a text comes in to Notify my webhook and enter your webhook URL.
  2. Assign the receiving number to the agent under Numbers.
  3. Point your provider’s inbound message webhook at RevRing:

Request Format

When an inbound text arrives, RevRing sends a POST request to your webhook URL:
Field Descriptions:
  • event: Always "message_received" for inbound messages.
  • organizationId: Your organization ID.
  • agentId: The agent that owns the number that received the text.
  • conversationId: RevRing’s id for the thread with this contact. Use it with the messages log to read the full conversation.
  • fromNumber: The contact’s number (E.164).
  • toNumber: Your number that received the text (E.164).
  • body: The text content of the incoming message.
  • messageSid: Your provider’s id for the inbound message.

Response Expectations

Respond with 200 OK promptly. RevRing does not require a response body and does not retry. To reply, call the Send Message API.

Example Implementation

Node.js / Express:
Python / Flask:

Next Steps

Tools

Configure system and custom tools

API Reference

View complete webhook API documentation

Inbound Calls

Set up inbound call handling

Outbound Calls

Configure outbound calling