Skip to main content

What are Post-Call Webhooks?

Post-call webhooks are HTTP notifications that Bland AI automatically sends to your server after a phone call completes. Think of them as real-time alerts that deliver call data directly to your application, enabling you to:
  • Process call outcomes immediately - Trigger follow-up actions based on call results
  • Integrate with your CRM or database - Automatically update customer records with call transcripts and extracted data
  • Build custom analytics - Track call performance and agent effectiveness
  • Create automated workflows - Send emails, create tickets, or update dashboards based on call data
  • Access rich call data - Get complete transcripts, extracted variables, call duration, and more
Webhooks make it easy to integrate with Bland, so your system can react to call completions right away, no need to keep polling our API.

About This Tutorial

This tutorial will help you set up and test your Bland AI webhooks for both inbound and outbound phone calls.

Step 1: Create your test webhook

For testing purposes, we’ll use Webhook.site to create a temporary webhook endpoint. Webhook.site generates instant webhook URLs with no setup required and captures all incoming requests so you can see webhook deliveries in real-time. When you visit Webhook.site, it automatically provides you a unique webhook URL that will capture any HTTP requests sent to it. This is perfect for testing before you implement your own webhook endpoint. Copy your unique webhook URL - you’ll need it in the next step.

Step 2: Configure webhook for inbound calls

  1. Open your Bland AI developer portal
  2. Go to the Inbound Phone Numbers page from the sidebar

Configure Your Webhook

  1. Find your phone number in the list of inbound numbers
  2. Click to expand the Advanced section of your inbound number details
  3. Locate the webhook field - this is where you’ll configure your post-call webhook
  4. Paste your webhook URL - Use the Webhook.site URL from Step 1
  5. Click “Test Webhook” - This sends a test payload to verify your webhook is working
Need live events during the call? This webhook parameter sends data after the call completes. If you want to receive webhook events during the call (like when the call starts, transfers, or ends), check out the webhook_events parameter in our Send Call API documentation.

Step 3: Verify webhook test

Navigate back to your Webhook.site page and check if the test webhook fired correctly. You’ll know it worked because a new HTTP request will appear in the list. If the test fails:
  • Double-check that you provided the correct URL
  • Make sure there are no extra spaces or characters
If issues persist, reach out in our Discord community or ask for technical support from hello@bland.ai.

Step 4: Test with a live phone call

Now test with an actual phone call:
  1. Call your inbound phone number and have a conversation with your AI agent
  2. End the call completely
  3. Return to Webhook.site and you should see a new webhook delivery with the complete call data
  4. Inspect the payload to see the full transcript, call duration, and other call metadata
If you see the webhook payload appear after your call, your inbound webhook is working perfectly!

Step 5: Configure webhooks for outbound calls

Outbound calls handle webhooks differently than inbound calls. You have two options for configuring webhooks: When making API calls to create outbound calls, include the webhook parameter in your request:
{
  "phone_number": "+1234567890",
  "task": "Your call task here",
  "webhook": "webhook.site/#!/your-unique-id",
  "voice": "maya"
}
See the Send Phone Call API documentation for complete request details.

Option 2: Dashboard configuration

You can also configure a webhook when creating outbound calls in the dashboard:
  1. Navigate to the Send Call page in your developer portal
  2. Click to expand the Advanced section (similar to inbound numbers)
  3. Add your webhook URL to the webhook field
  4. Send your call
This webhook will receive the post-call data when that specific call completes.

Testing your outbound webhook

  1. Create a test call using the API with your webhook URL
  2. Wait for the call to complete
  3. Check Webhook.site for the incoming webhook payload
  4. Verify the payload contains your outbound call data
If you encounter any issues, reach out in our Discord community for support.

Webhook Payload Examples

Understanding the structure of webhook payloads helps you build better integrations. Here are examples of the actual data your webhook endpoint will receive:

Standard Post-Call Webhook

This is the immediate webhook sent right after a call completes:
{
  "call_id": "12345678-1234-1234-1234-123456789012",
  "c_id": "12345678-1234-1234-1234-123456789012",
  "call_length": 0.183333333333333,
  "batch_id": null,
  "to": "+15551234567",
  "from": "+15559876543",
  "completed": true,
  "created_at": "2025-09-12T20:39:03.168+00:00",
  "inbound": false,
  "queue_status": "complete",
  "max_duration": 12,
  "error_message": null,
  "variables": {
    "now": "Friday, September 12, 2025 1:39 PM",
    "now_utc": "Friday, September 12, 2025 8:39 PM",
    "short_from": "5559876543",
    "short_to": "5551234567",
    "from": "+15559876543",
    "to": "+15551234567",
    "call_id": "12345678-1234-1234-1234-123456789012",
    "phone_number": "+15551234567",
    "country": "US",
    "state": "CA",
    "language": "English",
    "timestamp": "2025-09-12T13:39:11-07:00",
    "timezone": "America/Los_Angeles"
  },
  "answered_by": "human",
  "record": true,
  "recording_url": "https://api.twilio.com/2010-04-01/Accounts/ACexample123/Recordings/REexample456",
  "metadata": {},
  "summary": "The call was a brief test call from Bland, during which the assistant confirmed the connection and exchanged polite pleasantries with the user before ending the call.",
  "price": 0.017,
  "started_at": "2025-09-12T20:39:03.168Z",
  "local_dialing": false,
  "call_ended_by": "ASSISTANT",
  "pathway_logs": null,
  "analysis_schema": null,
  "analysis": null,
  "transferred_to": null,
  "pathway_tags": [],
  "recording_expiration": null,
  "status": "completed",
  "pathway_id": null,
  "is_proxy_agent_call": false,
  "citation_schema_ids": [],
  "warm_transfer_calls": null,
  "concatenated_transcript": "user: Hello?  \n assistant: This is a test call from Bland. \n user: Cool. Thank you very much. \n assistant: You're welcome, have a great day, goodbye. \n agent-action: Ended call \n ",
  "transcripts": [
    {
      "id": 123456789,
      "user": "user",
      "text": "Hello? ",
      "created_at": "2025-09-12T20:39:13.173+00:00"
    },
    {
      "id": 123456790,
      "user": "assistant",
      "text": "This is a test call from Bland.",
      "created_at": "2025-09-12T20:39:13.566+00:00"
    },
    {
      "id": 123456791,
      "user": "user",
      "text": "Cool. Thank you very much.",
      "created_at": "2025-09-12T20:39:17.748+00:00"
    },
    {
      "id": 123456792,
      "user": "assistant",
      "text": "You're welcome, have a great day, goodbye.",
      "created_at": "2025-09-12T20:39:19.186+00:00"
    },
    {
      "id": 123456793,
      "user": "agent-action",
      "text": "Ended call",
      "created_at": "2025-09-12T20:39:20.53+00:00"
    }
  ],
  "corrected_duration": "11",
  "end_at": "2025-09-12T20:39:21.000Z",
  "disposition_tag": "COMPLETED_ACTION"
}

Delayed Webhook with Citations and Corrected Transcript

When you enable citation extraction, you can choose to delay the post-call webhook until citations are processed. This combined webhook includes all call data plus citation information and corrected transcripts:
{
  "to": "+447931841239",
  "c_id": "8a9620f6-d634-4b92-8d75-93280a894a71",
  "from": "+14159438185",
  "price": 0.029,
  "end_at": "2025-09-19T18:22:31.000Z",
  "record": true,
  "status": "completed",
  "call_id": "8a9620f6-d634-4b92-8d75-93280a894a71",
  "inbound": false,
  "summary": "The call was a brief confirmation from Jean at Nutriva Health to a client named James, verifying his attendance at an upcoming appointment scheduled for the next day at 10:00 AM. James confirmed his ability to attend, and the call was promptly ended.",
  "analysis": null,
  "batch_id": null,
  "metadata": {},
  "completed": true,
  "variables": {
    "to": "+447931841239",
    "now": "Friday, September 19, 2025 11:22 AM",
    "from": "+14159438185",
    "call_id": "8a9620f6-d634-4b92-8d75-93280a894a71",
    "country": "GB",
    "now_utc": "Friday, September 19, 2025 6:22 PM",
    "language": "English",
    "short_to": "7931841239",
    "timezone": "America/Los_Angeles",
    "timestamp": "2025-09-19T11:22:13-07:00",
    "short_from": "4159438185",
    "phone_number": "+447931841239"
  },
  "created_at": "2025-09-19T18:22:06.984+00:00",
  "pathway_id": null,
  "started_at": "2025-09-19T18:22:06.984Z",
  "answered_by": "human",
  "call_length": 0.316666666666667,
  "transcripts": [
    {
      "id": 174,
      "text": "Hey, this is Jean from Nutriva Health. Could you confirm your name for me?",
      "user": "assistant",
      "created_at": "2025-09-19T18:22:15.893+00:00"
    },
    {
      "id": 175,
      "text": "Yeah. My name is James.",
      "user": "user",
      "created_at": "2025-09-19T18:22:20.579+00:00"
    },
    {
      "id": 176,
      "text": "Hey James, great to meet you! I just wanted to confirm that you’ll be able to attend your upcoming appointment tomorrow at ten A M?",
      "user": "assistant",
      "created_at": "2025-09-19T18:22:22.375+00:00"
    },
    {
      "id": 177,
      "text": "Yeah. I will be able to. Goodbye.",
      "user": "user",
      "created_at": "2025-09-19T18:22:31.061+00:00"
    }
  ],
  "max_duration": 12,
  "pathway_logs": null,
  "pathway_tags": [],
  "queue_status": "complete",
  "call_ended_by": "USER",
  "error_message": null,
  "local_dialing": false,
  "recording_url": "https://akalocaldev.internal.bland.ai/v1/recordings/8a9620f6-d634-4b92-8d75-93280a894a71:24847607-ce61-4488-be8f-8e63d548b13e",
  "transferred_at": null,
  "transferred_to": null,
  "analysis_schema": null,
  "disposition_tag": "COMPLETED_ACTION",
  "corrected_duration": "19",
  "citation_schema_ids": [
    "b0477cba-1c97-4105-8ac9-46cb8eae5cf1"
  ],
  "is_proxy_agent_call": false,
  "warm_transfer_calls": null,
  "recording_expiration": "2025-10-19T18:22:36.641+00:00",
  "pre_transfer_duration": null,
  "post_transfer_duration": null,
  "concatenated_transcript": "assistant: Hey, this is Jean from Nutriva Health. Could you confirm your name for me? \n user: Yeah. My name is James. \n assistant: Hey James, great to meet you! I just wanted to confirm that you’ll be able to attend your upcoming appointment tomorrow at ten A M? \n user: Yeah. I will be able to. Goodbye. \n ",
  "citations": [
    {
      "call_id": "8a9620f6-d634-4b92-8d75-93280a894a71",
      "variable_name": "firstName",
      "variable_type": "string",
      "value": "James",
      "cited_utterances": [
        {
          "id": "8a9620f6-d634-4b92-8d75-93280a894a71_1",
          "idx": 1,
          "start_time": 5.056,
          "end_time": 6.176,
          "confidence": 0.115,
          "channel": 1,
          "transcript": "- Yeah, my name is James.",
          "speaker_id": "SPEAKER_1_0",
          "speaker_name": "James (Customer)",
          "speaker_description": "The customer being called to confirm his appointment.",
          "topics": [
            "identity_confirmation"
          ],
          "topics_meta": "{\"identity_confirmation\":\"The customer confirms his name is James.\"}",
          "utterance_type": "answer"
        },
        {
          "id": "8a9620f6-d634-4b92-8d75-93280a894a71_2",
          "idx": 2,
          "start_time": 8.704,
          "end_time": 14.848,
          "confidence": 0.7174999999999999,
          "channel": 0,
          "transcript": "Hey, James. Great to meet you. I just wanted to confirm that you'll be able to attend your upcoming appointment tomorrow at 10 a.m.",
          "speaker_id": "SPEAKER_0_0",
          "speaker_name": "Jean (Agent)",
          "speaker_description": "An agent from Nutriva Health calling to confirm an appointment.",
          "topics": [
            "greeting",
            "appointment_confirmation"
          ],
          "topics_meta": "{\"appointment_confirmation\":\"The agent asks the customer to confirm his attendance for an appointment at a specific date and time.\",\"greeting\":\"The agent greets the customer by name.\"}",
          "utterance_type": "question"
        }
      ],
      "schema_id": "b0477cba-1c97-4105-8ac9-46cb8eae5cf1"
    }
  ],
  "corrected_transcript": [
    {
      "start": 0.384,
      "end": 4.096,
      "speaker": 2,
      "speaker_label": "assistant",
      "text": "Hey, this is Jean from Nutriva Health. Could you confirm your name for me?",
      "confidence": 0.713
    },
    {
      "start": 5.056,
      "end": 6.176,
      "speaker": 1,
      "speaker_label": "user",
      "text": "Yeah, my name is James.",
      "confidence": 0.115
    },
    {
      "start": 8.704,
      "end": 14.848,
      "speaker": 2,
      "speaker_label": "assistant",
      "text": "Hey James, great to meet you! I just wanted to confirm that you'll be able to attend your upcoming appointment tomorrow at ten A M?",
      "confidence": 0.717
    },
    {
      "start": 16.224,
      "end": 18.464,
      "speaker": 1,
      "speaker_label": "user",
      "text": "Yeah. I will be able to. Goodbye.",
      "confidence": 0.432
    }
  ]
}

Key Differences

Standard Post-Call Webhook:
  • Sent immediately after call completion
  • Contains call metadata, transcripts, and basic variables
  • No citations or corrected transcript
Delayed Webhook with Citations:
  • Sent after post-call processing (30-60 seconds later)
  • Includes enhanced corrected_transcript with improved formatting, accuracy, speaker labels, and confidence scores
  • Contains detailed citations array with extracted variables linked to specific utterances
Configuration Note: When you enable citation extraction, you can choose to delay the post-call webhook until citations are processed and include citation data in a single webhook. When disabled, the post-call webhook fires immediately, and citations are sent via a separate webhook.

Error Message Reference

All possible values for the error_message field in post-call webhooks. Note that webhook delivery uses HTTP status codes separately from call outcome errors.

Webhook HTTP Status Codes

Successful Webhook Delivery:
  • 200 - Webhook delivered successfully (regardless of call outcome)
  • 2xx - Any 2xx status indicates successful webhook delivery
Webhook Delivery Failures:
  • 4xx - Client errors (invalid webhook URL, authentication issues)
  • 429 - Rate limiting (webhook endpoint receiving too many requests)
  • 5xx - Server errors (webhook endpoint unavailable or internal errors)
Webhook delivery failures will trigger automatic retries based on the response code.

Call Error Messages

The following error messages appear in the error_message field within successfully delivered webhook payloads:

Successful Calls

  • null - Call completed successfully

Call Connection Failures

HTTP Status: 200 (All call failures result in successful webhook delivery with error details in the payload)
  • "Call failed." - Base failure message
  • "Call failed. The number you dialed is not found." - Invalid/disconnected number (SIP 404)
  • "Call failed. The number you dialed is temporarily unavailable." - Network/carrier issues (SIP 480)
  • "Call failed. The number you dialed is busy. Please try again later." - Line busy (SIP 486)
  • "Call failed. Service Provider Blocked Call due to Spam or Number Reputation. Try a different number." - Carrier blocked (SIP 608)

System Errors

HTTP Status: 200 (System errors result in successful webhook delivery with error details in the payload)
  • "A database error occurred. Please contact support." - Internal database error
  • "Unable to start call. Check the call details error_message for more details." - Call dispatch failure
  • "unknown" - Fallback error message

Important Notes

  • Webhook Delivery vs Call Outcome: HTTP status codes indicate webhook delivery success (200 = delivered), while call errors are embedded in the payload
  • Retry Logic: Failed webhook deliveries (4xx/5xx) trigger automatic retries with exponential backoff
  • SIP Mapping: Call connection failures map from SIP response codes to user-friendly error messages
  • Error Handling: Your webhook endpoint should return 2xx status codes to confirm receipt, regardless of how you process the call data