What is an After‑Call Webhook, and how do I configure it?

What is an After‑Call Webhook, and how do I configure it?

An After‑Call Webhook sends call details from your account to your server right after a call ends. It lets you automate CRM updates, analytics, quality checks, and alerts without polling.


Table of contents

  • When and why to use it
  • Prerequisites
  • Quick start — configure in the web app
  • Verify delivery
  • Sample JSON payload
  • Field reference
  • Security & authentication
  • Error handling, retries, and limits
  • Alternative setup — API
  • Expected results
  • Troubleshooting
  • FAQs


When and why to use it

Use an after‑call webhook when you need timely events for downstream systems.

Common use cases:

  • Create or update CRM activities with call outcomes.
  • Attach the recording URL to a support ticket.
  • Trigger QA workflows when a call is missed or short.
  • Push metrics to BI tools within seconds after call end.


Prerequisites

  • Role/permission: Admin or Owner to manage integrations.
  • Endpoint: A publicly reachable HTTPS URL that accepts POST with JSON.
  • Authentication: Basic Auth or a custom bearer/secret header.
  • Firewall/IP allowlist: Allow inbound traffic from our egress IPs.
  • TLS: Valid certificate chain. No self‑signed certs.
  • Test tool: cURL or Postman to validate quickly.

Tip: Use a separate test endpoint first. Promote to production after validation.


Quick start — configure in the web app

  1. Go to Settings → Integrations → Webhooks → After‑Call.
  2. Click Add Webhook.
  3. Set Destination URL (HTTPS).
  4. Choose Auth type:
    • Basic Auth: enter username and password.
    • Custom Header: enter header key (for example, X-Webhook-Token) and secret value.
  5. Select Payload format = JSON.
  6. (Optional) Choose which call events to send: Answered, Missed/Abandoned, Voicemail.
  7. Click Save, then Send Test.

What you should see: Your endpoint returns HTTP 200 OK within 5 seconds. The app marks the webhook test as Delivered.

Alt text: After‑Call Webhook form with URL, Auth type, and Send Test button.Caption: Configure destination URL, auth, and payload format before sending a test.


Verify delivery

Use one of the following methods.

Method A — Logs in your server

  • Log the request method (POST), headers, and body.
  • Confirm you received a JSON payload that matches the sample below.
  • Return HTTP 200 with a short body (or empty).

Method B — cURL mock

curl -X POST "https://example.com/webhooks/after-call" \

-H "Content-Type: application/json" \

-H "X-Webhook-Token: REPLACE_WITH_SECRET" \

-d '{

"event": "call.completed",

"call_id": "cl_8fKQ92",

"direction": "inbound",

"from": "+

1408555123

4",

"to": "+

1408555987

6",

"started_at": "2025-08-21T10:58:13Z",

"ended_at": "2025-08-21T11:02:44Z",

"duration_seconds": 271,

"status": "answered",

"agent": {"id": "ag_102", "name": "Jordan"},

"recording_url": "https://recordings.example/abc123.mp3",

"wrap_up_notes": "Callback scheduled"

}'

Method C — Postman

  • Create a POST request to your endpoint.
  • Add headers and the sample JSON body.
  • Click Send and verify a 200 OK response.

Alt text: Postman request showing POST to webhook URL with JSON body and 200 OK response.Caption: Use Postman to validate your endpoint and headers.


Sample JSON payload

{

"event": "call.completed",

"event_id": "evt_5z7h3c",

"occurred_at": "2025-08-21T11:02:44Z",

"call_id": "cl_8fKQ92",

"parent_call_id": null,

"direction": "inbound",

"from": "+

1408555123

4",

"to": "+

1408555987

6",

"status": "answered",

"reason": null,

"queue": {"id": "q_23", "name": "Support"},

"agent": {"id": "ag_102", "name": "Jordan"},

"started_at": "2025-08-21T10:58:13Z",

"connected_at": "2025-08-21T10:58:33Z",

"ended_at": "2025-08-21T11:02:44Z",

"duration_seconds": 271,

"talk_time_seconds": 251,

"wrap_up_seconds": 20,

"recording_url": "https://recordings.example/abc123.mp3",

"notes": "Callback scheduled",

"custom_fields": {"crm_id": "ACME-4451", "priority": "high"}

}


Field reference

  • event: Always call.completed for this webhook.
  • event_id: Unique per delivery. Use for idempotency.
  • occurred_at: ISO‑8601 UTC timestamp of the event.
  • call_id: Unique call identifier.
  • parent_call_id: Present for transfers or conferences.
  • direction: inbound or outbound.
  • from, to: E.164 numbers.
  • status: answered, missed, abandoned, or voicemail.
  • reason: Populated for missed or abandoned calls.
  • queue/agent: Routing context and agent who handled the call.
  • *_at fields: ISO‑8601 UTC timestamps.
  • *_seconds fields: Integer durations.
  • recording_url: May be null if recording is disabled or restricted.
  • custom_fields: Optional key‑value pairs you map in Settings.


Security & authentication

Recommended options:

A) Custom header (preferred)

  • Configure a header like X-Webhook-Token: <long_random_secret>.
  • Rotate secrets at least quarterly.
  • Verify on your server before processing.

B) Basic Auth

  • We send Authorization: Basic <base64(user:pass)>.
  • Validate credentials and enforce TLS.

Signature verification (optional hardening)

  • Add an HMAC header, for example X-Webhook-Signature.
  • Compute HMAC_SHA256(body, secret) and compare in constant time.

Server examples

PHP

<?php

$raw = file_get_contents('php://input');

$provided = $_SERVER['HTTP_X_WEBHOOK_TOKEN'] ?? '';

$secret = getenv('WEBHOOK_SECRET');

if (!hash_equals($secret, $provided)) { http_response_code(401); exit; }

// Optional HMAC

$hmac = $_SERVER['HTTP_X_WEBHOOK_SIGNATURE'] ?? '';

if ($hmac && !hash_equals(hash_hmac('sha256', $raw, $secret), $hmac)) {

http_response_code(401); exit;

}

http_response_code(200);

echo 'ok';

Node.js (Express)

import express from 'express';

import crypto from 'crypto';

const app = express();

app.use(express.json({ type: '*/*' }));

app.post('/webhooks/after-call', (req, res) => {

const secret = process.env.WEBHOOK_SECRET;

const token = req.header('X-Webhook-Token');

if (token !== secret) return res.status(401).send('unauthorized');

const sig = req.header('X-Webhook-Signature');

if (sig) {

const h = crypto.createHmac('sha256', secret).update(JSON.stringify(req.body)).digest('hex');

if (!crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(h))) {

return res.status(401).send('bad signature');

}

}

return res.status(200).send('ok');

});

app.listen(3000);

Python (Flask)

from flask import Flask, request, jsonify

import hmac, hashlib, os

app = Flask(__name__)

@app.post('/webhooks/after-call')

def after_call():

raw = request.get_data()

secret = os.getenv('WEBHOOK_SECRET','')

token = request.headers.get('X-Webhook-Token','')

if token != secret:

return 'unauthorized', 401

sig = request.headers.get('X-Webhook-Signature')

if sig:

h = hmac.new(secret.encode(), raw, hashlib.sha256).hexdigest()

if not hmac.compare_digest(h, sig):

return 'bad signature', 401

return jsonify({"status":"ok"}), 200

app.run()


Error handling, retries, and limits

  • Timeout: Delivery times out after 5 seconds.
  • Retries: If your endpoint returns non‑2xx or times out, we retry with exponential backoff up to 6 times.
  • Idempotency: Use event_id to deduplicate in case of retries.
  • Rate limiting: Design for bursts of 20 requests/sec during peaks.
  • Payload size: Typical payload is 1–3 KB; recording URLs are links, not blobs.
  • Security: Reject unknown IPs. Use TLS 1.2+ only.

Expected responses

200 OK # Processed

400 Bad Request # Malformed payload

401 Unauthorized # Token or signature failed

403 Forbidden # Auth absent or IP not allowed

410 Gone # Endpoint deprecated; stop sending

429 Too Many Requests # Back off and retry later

500/502/503 # Transient server error; we will retry


Alternative setup — API

Prefer automation? Create or update the webhook via API.

Create webhook

curl -X POST https://api.example.com/v1/webhooks \

-H "Authorization: Bearer <API_KEY>" \

-H "Content-Type: application/json" \

-d '{

"type": "after_call",

"url": "https://example.com/webhooks/after-call",

"auth": {"header": "X-Webhook-Token", "secret": "<SECRET>"},

"events": ["answered","missed","voicemail"],

"format": "json"

}'

Rotate secret

curl -X PATCH https://api.example.com/v1/webhooks/wb_123 \

-H "Authorization: Bearer <API_KEY>" \

-H "Content-Type: application/json" \

-d '{"auth": {"header": "X-Webhook-Token", "secret": "<NEW_SECRET>"}}'


Expected results

After saving and testing:

  • Your server receives a POST with the JSON payload.
  • You return HTTP 200 within the timeout.
  • The webhook status in the app shows Delivered.
  • For live calls, events arrive 0–5 seconds after call end.

To confirm success end‑to‑end:

  1. Place a short test call.
  2. Check your server logs for the event_id.
  3. Verify the CRM or downstream system shows the new record.


Troubleshooting

No deliveries appear

  • Verify the webhook is Enabled.
  • Check DNS and TLS validity of your endpoint.
  • Confirm firewall allowlist and open port 443.

401 Unauthorized

  • Token mismatch or missing header. Compare secrets, rotate if needed.

4xx client errors

  • Validate JSON. Check required fields. Ensure your server accepts POST.

5xx server errors or timeouts

  • Reduce processing time. Acknowledge with 200, then enqueue work.

Recording URL returns 403

  • User lacks permission or link expired. Sign URLs or fetch via API with auth.

Duplicate events

  • Retries may create duplicates. Use event_id for idempotent handling.

[Diagram — Recommended flow]Alt text: Sequence diagram showing Platform → Your Endpoint → Queue/Worker → CRM.Caption: Acknowledge fast, then process asynchronously.


FAQs

What events does this webhook send?It sends call.completed for answered, missed, abandoned, and voicemail outcomes.

Can I filter which calls generate webhooks?Yes. Choose events in the webhook settings. You can also filter by queue or number via rules.

How do I secure recording access?Use expiring URLs or fetch recordings with an authenticated API call.

Do you sign payloads?You can enable HMAC signing and validate with X-Webhook-Signature.

What is the SLA for delivery?We attempt immediate delivery and retry on transient failures. Use logs in the app to review outcomes.


Related articles

  • Create API credentials for integrations — Set up API keys and scopes./docs/api-credentials
  • Webhook best practices and retries — Idempotency and backoff patterns./docs/webhooks-retries-best-practices
  • Accessing and managing call recordings — Permissions and expiring URLs./docs/call-recordings-access


    • Related Articles

    • In-Call Webhook

      Overview Webhooks are HTTP callbacks that receive notification messages for events. MyOperator uses webhooks to notify your application any time a call event happens in your account. For example, if a call has been received by your agent, you will ...
    • After Call Webhook

      Overview Webhooks are HTTP callbacks that receive notification messages for events. MyOperator uses webhooks to notify your application any time a call event happens in your account. For example, if a call has been received by your agent, you will ...
    • What Is an In-Call Webhook?

      ? Table of Contents What Is an In-Call Webhook? What Are the Key Features and Benefits of an In-Call Webhook? How Does an In-Call Webhook Work? What Information Is Transmitted via the Webhook? How Do I Configure an In-Call Webhook in MyOperator? ...
    • How to Add an In-Call Webhook in MyOperator

      ? Table of Contents What is an In-Call Webhook? Prerequisites for Adding an In-Call Webhook Step-by-Step Instructions Tips for Success Troubleshooting Frequently Asked Questions (FAQs) 1. What is an In-Call Webhook? An In-Call Webhook allows ...
    • How to Add an After-Call Webhook in MyOperator?

      ? Table of Contents What is an After-Call Webhook? Prerequisites for Adding an After-Call Webhook Step-by-Step Instructions Best Practices Testing the Webhook in Postman Troubleshooting Frequently Asked Questions (FAQs) 1. What is an After-Call ...