Skip to content
Discord

Call Lifecycle & Webhooks

Voice Agents uses webhooks to notify your application about the state of every call in real-time. Whether a call connects, fails, or triggers a specific action (like creating an order), your configured callback URL receives an event payload.

Every call progresses through a specific lifecycle. At each stage, an event is fired.

stateDiagram-v2
    [*] --> Initiate: Call Placed
    Initiate --> InProgress: Connected
    Initiate --> Failed: Failed/Busy/No Answer
    InProgress --> Ended: Disconnected
    Ended --> Completed: Processing Done
    Completed --> EndOfCall: Analysis Ready
    EndOfCall --> LifecycleEnded: All Done
    Failed --> LifecycleEnded: All Done
    LifecycleEnded --> [*]

These events track the normal progression of a successful call.

EventDescription
call.initiateThe call has been queued and is being dialed.
call.in-progressThe recipient picked up; the AI conversation has started.
call.endedThe phone connection has dropped.
call.completedCall data (recording, transcript, duration) has been processed.
call.timeoutThe call exceeded the maximum allowed duration.
end-of-callAI analysis is complete — summary, success evaluation, and structured data are available.
call.lifecycle-endedAll processing is finished. This is the final event for this call.

If a call cannot be established, one of these events will fire. The system may automatically retry based on your campaign settings.

EventDescription
call.failedThe call could not be connected (general failure).
call.busyThe recipient’s line was busy.
call.no-answerThe recipient did not pick up.
call.validation-failedPre-call validation failed (e.g., invalid number).
call.skipThe call was skipped (e.g., DND number).
EventDescription
call.rescheduledA callback has been scheduled for a later time (lifecycle continues to the next attempt).
call.abortedThe call was manually cancelled via the abort API.

Every webhook event shares a common envelope structure.

{
  "metadata": {
    "customer_id": "12345",
    "order_ref": "ORD-001"
  },
  "event": {
    "type": "call.completed",
    "data": {
      "call": {
        "id": "c_550e8400-e29b",
        "status": "completed",
        "startedAt": "2023-10-27T10:00:00Z",
        "endedAt": "2023-10-27T10:02:30Z",
        "durationSeconds": 150,
        "recordingUrl": "https://api.voice-agents.com/recordings/...",
        "detailUrl": "https://api.voice-agents.com/calls/..."
      }
    }
  }
}
  • metadata: The custom JSON object you passed when initiating the call. This is passed back in every event, allowing you to link calls to your internal records (e.g., userId, orderId).
  • event.type: The specific event name (e.g., call.in-progress, end-of-call).
  • event.data: The payload specific to the event.

Some events contain additional data in event.data.

Contains the AI analysis, summary, and credit usage.

{
  "analysis": {
    "success": true,
    "summary": "Customer confirmed the appointment for Tuesday.",
    "insights": {
        "sentiment": "positive",
        "intent": "booking_confirmed"
    }
  },
  "credits": {
    "used": 2.5,
    "available": 105.0
  }
}

Contains a report of all attempts.

{
  "report": {
    "reAttemptCount": 1,
    "rescheduledCount": 0,
    "finalStatus": "completed"
  }
}

Actions are special events triggered by the AI during the conversation when a specific task needs to be performed on your end, such as creating an order or sending a message.

Fires when the AI determines the customer wants to place an order and has provided all necessary details.

{
  "event": {
    "type": "action",
    "data": {
      "action": "create_order",
      "payload": {
        "phone": "+15550109988",
        "lineItems": [{ "variantId": "123", "quantity": 1 }],
        "shippingAddress": {
          "firstName": "Jane",
          "lastName": "Doe",
          "address1": "123 Main St",
          "city": "New York",
          "zip": "10001",
          "country": "US"
        },
        "paymentMode": "cod",
        "cartTotal": 150.00
      }
    }
  }
}

Fires when the AI cannot complete a task (like creating an order) due to missing info, and triggers a fallback message via WhatsApp.

ReasonMeaning
missing_addressCustomer’s shipping address is incomplete.
missing_first_nameCustomer’s name could not be determined.
invalid_cart_dataCart data is malformed or missing.
{
  "event": {
    "type": "action",
    "data": {
      "action": "send_whatsapp",
      "reason": "missing_address"
    }
  }
}

Here is an example of how to handle these events in a Node.js Express application.

app.post('/webhooks/voice-agent', (req, res) => {
  const { event, metadata } = req.body;

  console.log(`Received event: ${event.type} for Customer: ${metadata.customer_id}`);

  switch (event.type) {
    case 'call.in-progress':
      // Call connected, maybe update UI status
      break;

    case 'action':
      if (event.data.action === 'create_order') {
        // Handle order creation logic
        createOrder(event.data.payload);
      } else if (event.data.action === 'send_whatsapp') {
        // Handle WhatsApp fallback logic
        sendWhatsAppFallback(event.data.reason);
      }
      break;

    case 'end-of-call':
      // Save call summary and analysis
      saveCallAnalysis(event.data.call.id, event.data.analysis);
      break;

    case 'call.rescheduled':
      // Update next attempt time in your DB
      console.log(`Call rescheduled for later`);
      break;

    case 'call.failed':
    case 'call.busy':
    case 'call.no-answer':
      // Log failure reason
      console.log(`Call failed: ${event.type}`);
      break;
      
    default:
      console.log('Unhandled event:', event.type);
  }

  // Always acknowledge the webhook
  res.status(200).send('OK');
});

To ensure that the webhooks you receive are genuinely from Voice Agents, you should verify the signature included in the headers.

See Webhook Signature Verification for implementation details.