Webhooks

Send real-time call data to Zapier, Slack, your CRM, or any URL — automatically after every call.

Overview

Webhooks push call data to your server or a third-party service automatically. CallScaler supports two types:

Post-Call Webhooks fire after a call ends. They send a rich JSON payload with full call details, AI analysis, transcription, and attribution data. This is the recommended way to integrate with CRMs, automation tools, and custom systems.

In-Call Webhooks are a step in a call flow that fires during the call. Use them for advanced real-time routing — your server can control where the call goes next.

Post-Call Webhooks

Post-call webhooks are configured per call flow. When enabled, CallScaler automatically sends an HTTP POST request to your URL after every call through that call flow.

Setup:
1. Open Call Flows and select a call flow.
2. Scroll to Post-Call Webhook in the call flow settings.
3. Toggle it on and enter your destination URL.
4. Choose a firing mode: Immediate or Wait for AI.
5. Save the call flow.

Firing Modes

Immediate (default) — The webhook fires as soon as the call ends. AI fields (ai_score, ai_category, transcription, etc.) will be null because analysis hasn't completed yet. Use this when you need instant notifications and don't need AI data.

Wait for AI — The webhook waits until transcription and AI analysis are complete before firing. This gives you the full payload with AI scores, transcription, summary, and qualification data. There's a 5-minute fallback — if AI processing hasn't completed by then, the webhook fires anyway with whatever data is available.

Use Wait for AI if your integration needs transcription text, AI scores, or qualification status. Use Immediate for instant Slack notifications or time-sensitive alerts.

Payload Reference

The post-call webhook sends a JSON payload with these fields:

  • event — Event type: call.completed, call.missed, call.voicemail, or call.failed
  • call_id — Unique call ID
  • business_id — Your business ID
  • call_flow_id — Call flow ID
  • call_flow_name — Call flow name
  • tracking_number — Your CallScaler tracking number
  • caller_number — The caller's phone number
  • destination_number — Forwarding destination (null if not forwarded)
  • directioninbound or outbound
  • statuscompleted, no-answer, voicemail, busy, or failed
  • duration_seconds — Call duration
  • recording_url — Recording URL (null if not recorded)
  • recording_duration — Recording length in seconds
  • transcription — Full transcription text (null if not available yet)
  • summary — AI summary of the call
  • ai_score — Quality score 0–100
  • ai_categorylead, existing_customer, spam, wrong_number, or voicemail
  • qualified_ai — Whether AI marked this as a qualified lead
  • qualification_reason — Why the call was qualified or not
  • source — Traffic source
  • landing_page_url, referrer_url — Visitor journey
  • utm_source, utm_medium, utm_campaign, utm_term, utm_content — UTM parameters
  • gclid, fbclid, msclkid — Ad platform click IDs
  • value_cents — Assigned call value
  • cost_cents — Call cost
  • robo_score — Robocall likelihood score
  • ai_processed — Whether AI analysis has completed (true/false)
  • created_at — When the call occurred
  • webhook_sent_at — When the webhook was sent
  • delivery_id — Unique delivery ID for tracking
  • attempt — Which delivery attempt this is (1, 2, or 3)

Payload Example

A complete post-call webhook payload:

{
  "event": "call.completed",
  "call_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "business_id": "uuid",
  "call_flow_id": "uuid",
  "call_flow_name": "Google Ads",
  "tracking_number": "+15735551234",
  "caller_number": "+13055559876",
  "destination_number": "+13055554567",
  "direction": "inbound",
  "status": "completed",
  "duration_seconds": 145,
  "recording_url": "https://callscaler.com/api/v1/audio/abc123.mp3",
  "recording_duration": 138,
  "transcription": "Hi, I need a quote for a new AC unit...",
  "summary": "Homeowner requesting HVAC quote for new installation.",
  "ai_score": 85,
  "ai_category": "lead",
  "qualified_ai": true,
  "qualification_reason": "Strong buying intent — requesting pricing",
  "source": "google",
  "landing_page_url": "https://yoursite.com/hvac",
  "referrer_url": "https://google.com",
  "utm_source": "google",
  "utm_medium": "cpc",
  "utm_campaign": "hvac-tampa",
  "utm_term": "ac repair near me",
  "utm_content": null,
  "gclid": "abc123def456",
  "fbclid": null,
  "msclkid": null,
  "value_cents": 5000,
  "cost_cents": 15,
  "robo_score": 0,
  "ai_processed": true,
  "created_at": "2026-03-30T14:30:00Z",
  "webhook_sent_at": "2026-03-30T14:31:15Z",
  "delivery_id": "uuid",
  "attempt": 1
}

Retry Logic

If your endpoint returns an error (HTTP 4xx or 5xx) or doesn't respond within 10 seconds, CallScaler retries the delivery:

1. Attempt 1 — Immediate
2. Attempt 2 — After 30 seconds
3. Attempt 3 — After 2 minutes

After 3 failed attempts, the delivery is marked as failed. You can check delivery status in the Webhook Deliveries API or in the call flow settings in the dashboard.

Your endpoint should return a 200 status code to acknowledge receipt. The response body is ignored.

Testing Webhooks

Each call flow with a post-call webhook has a Test button. Click it to send a sample payload to your URL using data from a recent call. This lets you verify your endpoint is receiving and parsing the data correctly without making a real call.

In-Call Webhooks (Advanced)

In-call webhooks are a step in a call flow that fires during the call. Unlike post-call webhooks, these happen in real time while the caller is on the line.

Setup:
1. Open a call flow and click Add Step.
2. Choose Webhook.
3. Enter the destination URL and choose HTTP method (POST, GET, PUT, or PATCH).
4. Save the call flow.

By default, the webhook fires and the call continues immediately (fire-and-forget).

In-Call: Default Payload

In-call webhooks send three fields as application/x-www-form-urlencoded form data by default:

From is the caller's number, To is your tracking number, and CallSid is the unique call ID.

From=+13055551234&To=+13055559876&CallSid=abc-123-def

In-Call: Custom JSON Body

To send JSON instead, add a custom body in More options. Use template variables that get replaced with real call data:

{{caller_number}} — The caller's phone number
{{tracking_number}} — Your tracking number
{{call_sid}} — The unique call ID

When your body starts with {, the Content-Type is automatically set to application/json.

{
  "caller": "{{caller_number}}",
  "tracking_number": "{{tracking_number}}",
  "call_id": "{{call_sid}}"
}

In-Call: Wait for Response

Enable Wait for response to let your server control what happens next in the call. CallScaler waits for your server's JSON response (up to 30 seconds) and takes action based on it:

This is powerful for dynamic routing — your server can look up the caller in your CRM and decide where to route them in real time.

// Forward the call to a specific number
{"action": "forward", "destination": "+13055554567"}

// Play a message to the caller
{"action": "say", "message": "Thanks for calling!"}

// Hang up with a message
{"action": "hangup", "message": "We are currently closed."}

Connect to Zapier

Zapier connects CallScaler to 6,000+ apps without code. This works with both post-call and in-call webhooks.

1. In Zapier, create a new Zap and choose Webhooks by Zapier as the trigger.
2. Select Catch Hook as the trigger event.
3. Zapier gives you a webhook URL (starts with https://hooks.zapier.com/...). Copy it.
4. In CallScaler, paste the URL into either a post-call webhook or an in-call webhook step.
5. Save the call flow and make a test call (or click the Test button for post-call webhooks).
6. Back in Zapier, click Test trigger — it should pick up the call data.
7. Add an action: send an email, create a CRM contact, add a Google Sheets row, post to Slack — whatever you need.

Every call through that call flow automatically triggers your Zap.

Connect to Slack

Get a Slack notification for every call.

Option A — Slack Incoming Webhook (no Zapier needed):
1. In Slack, go to Your Apps → Create New App → From Scratch.
2. Go to Incoming Webhooks → Activate → Add New Webhook to Workspace → pick a channel.
3. Copy the webhook URL (starts with https://hooks.slack.com/...).
4. In CallScaler, use this as your post-call webhook URL. Slack accepts JSON payloads natively — it will post the raw call data to your channel.

For a formatted message, use an in-call webhook step with a custom body:
{"text": "📞 Call from {{caller_number}} to {{tracking_number}}"}

Option B — Via Zapier:
Follow the Zapier steps above and choose Slack → Send Channel Message as the action. This gives you full control over message formatting.

Connect to Make (Integromat)

1. In Make, create a new scenario and add a Webhooks → Custom webhook module.
2. Click Add to create a new webhook. Make gives you a URL — copy it.
3. In CallScaler, paste the URL as a post-call webhook or in-call webhook step.
4. Make a test call (or click Test) so Make can learn the data structure.
5. Add more modules to your scenario (CRM updates, emails, sheets, etc.).
6. Turn the scenario on.

Connect to Google Sheets

For Google Sheets, CallScaler has a built-in Google Sheets addon that's simpler than a webhook. It automatically pushes call data to your sheet with no setup beyond connecting your Google account.

If you prefer using a webhook, you can route calls to a Google Apps Script:

1. In your Google Sheet, go to Extensions → Apps Script.
2. Create a doPost(e) function that parses the incoming data and appends a row.
3. Deploy as a web app (execute as you, anyone can access).
4. Copy the deployment URL and use it as your webhook URL in CallScaler.

We recommend the built-in addon over the manual webhook approach for Sheets.

Troubleshooting

Post-call webhook not firing?
• Make sure it's toggled on in the call flow settings.
• Check the Webhook Deliveries API for error details.
• If using Wait for AI mode, the webhook won't fire until transcription completes (up to 5 minutes).

In-call webhook not firing?
• Make sure the webhook step is in the right position. Steps execute in order — if the call is answered by a previous step (like Forward), it may not reach the webhook.

Getting errors?
• Check that your URL is publicly accessible.
• In-call webhooks have a 5-second default timeout (configurable up to 30 seconds). Post-call webhooks have a 10-second timeout.
• Your endpoint must return a 200 status code.

Wrong data format?
• Post-call webhooks always send JSON with Content-Type: application/json.
• In-call webhooks default to form-encoded data. Use a custom body starting with { to send JSON instead.