Voice events
Bird emits webhook events as a call starts, is answered, and ends. Use them to update your systems without polling. See Webhooks for subscriptions, signatures, retries, and replay.
A call's path through the event types:
- voice_call.initiated: Bird accepted the call setup request (a SIP INVITE) and started routing the call
- voice_call.answered: the number you called picked up. Only answered calls get this event
- voice_call.ended: the call is over, and the event carries the outcome
voice_call.initiated confirms that a call exists, while voice_call.ended reports its outcome. A call Bird refuses after accepting the INVITE still emits voice_call.ended with status: "failed" and sip_response_code: 503.
The event type is an open enum: Bird may add types over time, so match the ones you handle and ignore the rest rather than treating an unfamiliar type as an error.
The event envelope
Voice events arrive in the same nested envelope as every other Bird event, described in the Webhooks guide: type, timestamp, and a type-specific data object. The event's identity is in the webhook-id HTTP header rather than the body.
| Field | Description |
|---|---|
| type | One of the three types on this page, for example voice_call.ended |
| timestamp | When the event occurred (RFC 3339). Sort by this, never by arrival order |
| data | Event-specific payload, always carrying the same call identity fields |
Every voice event's data contains the same identity fields for correlation. Both numbers use E.164 format: a leading +, country code, and national number.
| Field | Description |
|---|---|
| call_id | The call record's id (vcl_…), the same one shown in the Call log |
| session_id | Shared by every leg of a transferred or multi-party call (vcs_…). Null when no session correlation applies |
| workspace_id | The workspace the call belongs to |
| direction | outbound for calls your equipment placed |
| from | The calling number |
| to | The number that was called |
voice_call.initiated
Bird received the INVITE and began routing.
Exemplo de código
{
"type": "voice_call.initiated",
"timestamp": "2026-06-10T14:30:00Z",
"data": {
"call_id": "vcl_01krdgeqcxet5s7t44vh8rt9mg",
"session_id": "vcs_01krdgeqcxet5s7t44vh8rt9mh",
"workspace_id": "wsp_01krdgeqcxet5s7t44vh8rt9mj",
"direction": "outbound",
"from": "+14155551234",
"to": "+16505559876"
}
}voice_call.answered
The recipient answered, and billable time started. An unanswered call does not emit this event.
The payload is the call identity fields every voice event carries, with timestamp set to the moment of answer.
voice_call.ended
The call is over. This event adds the outcome:
| Field | Description |
|---|---|
| status | How it ended: answered, no_answer, failed, rejected, or unknown (see Statuses) |
| sip_response_code | The call's final SIP code, for example 200 or 486. A call Bird refused carries 503; null when no final code was recorded |
| duration_ms | Total call length in milliseconds, from the moment Bird received the call to hangup |
| billable_ms | Answered time in milliseconds, so a call nobody answered reports zero |
Exemplo de código
{
"type": "voice_call.ended",
"timestamp": "2026-06-10T14:31:05Z",
"data": {
"call_id": "vcl_01krdgeqcxet5s7t44vh8rt9mg",
"session_id": "vcs_01krdgeqcxet5s7t44vh8rt9mh",
"workspace_id": "wsp_01krdgeqcxet5s7t44vh8rt9mj",
"direction": "outbound",
"from": "+14155551234",
"to": "+16505559876",
"status": "answered",
"sip_response_code": 200,
"duration_ms": 65000,
"billable_ms": 60000
}
}The call record holds two details that this event omits: the rejection reason and cost. Open the call in the call log to distinguish a Bird refusal from a carrier failure. Cost appears after rating completes.
Consuming them safely
- Deduplicate on webhook-id. Bird delivers at least once, and a call's initiated event can be published more than once when a signaling retry replays. Same call, same stage, same webhook-id, so keying on it collapses the duplicate.
- Do not rely on order. Deliveries are not ordered, so answered can reach you after ended. Sort by timestamp, and let a later-arriving event with an earlier timestamp lose.
- Treat ended as the only reliable outcome. It is the event that carries status and durations, and it is the one to key your own records off.
- Reconcile against call records. Events provide timely updates, while the call log holds the call record. Export calls as CSV for reconciliation.
Next steps
| Page | What it covers |
|---|---|
| Webhooks & events | Endpoint setup, signature verification, retries, and replay |
| Call log | Every field on a call record, and CSV export |