Twilio model

Calls daily

Voice volume, outcomes, talk time and spend per day: the summary in Twilio's Voice Insights and Call Logs.

Grain
one row per day (UTC, call start) x account x direction x currency
Built from
  1. 1
    Raw tables
  2. 1
    Staging
  3. 1
    Core
  4. 1
    Analytics
Reads from Twilio
call
Ships as
Weld and dbt SQL, open source on GitHub
core.twilio.calls_daily
1-- core.twilio.calls_daily
2-- Voice volume, outcomes, talk time and spend per day: the summary in Twilio's Voice
3-- Insights and Call Logs.
4--
5-- Grain: one row per day (UTC, call start) x account x direction x currency.
6-- Depends on: staging.twilio.call
7--
8-- Every call leg is a row in staging, and both legs of a forwarded call are billed, so
9-- `call_legs` and `cost` count both. `parent_calls` counts only legs without a parent,
10-- which is the closer match to "conversations". `direction` is `inbound`, `outbound-api`
11-- or `outbound-dial` (the child leg of a <Dial>).
12--
13-- `billable_minutes` rounds each completed leg up to the next minute, which is how Twilio
14-- bills most voice usage. SIP and some international routes are billed per second, so
15-- treat it as an estimate and use `cost` for money.
16-- Answer rate is completed legs over all legs; the per-row rates should be re-derived
17-- from summed counts when you aggregate.
18
19SELECT
20    DATE(started_at)                                            AS date,
21    account_sid,
22    direction,
23    currency,
24
25    COUNT(*)                                                    AS call_legs,
26    COUNTIF(parent_call_sid IS NULL)                            AS parent_calls,
27    COUNTIF(status = 'completed')                               AS completed,
28    COUNTIF(status = 'busy')                                    AS busy,
29    COUNTIF(status = 'no-answer')                               AS no_answer,
30    COUNTIF(status = 'failed')                                  AS failed,
31    COUNTIF(status = 'canceled')                                AS canceled,
32    COUNTIF(answered_by LIKE 'machine%')                        AS answered_by_machine,
33    SAFE_DIVIDE(COUNTIF(status = 'completed'), COUNT(*))        AS answer_rate,
34
35    SUM(duration_seconds)                                       AS talk_seconds,
36    SUM(duration_seconds) / 60                                  AS talk_minutes,
37    SUM(IF(status = 'completed', CEIL(duration_seconds / 60), 0)) AS billable_minutes,
38    SAFE_DIVIDE(SUM(IF(status = 'completed', duration_seconds, 0)),
39                COUNTIF(status = 'completed'))                  AS avg_completed_call_seconds,
40

This model and the 2 it depends on. Deploy them together; refs like {{staging.…}} resolve to the matching folders in Weld, and the dbt view uses source() and ref().

Notes

How it counts. And where it stops.

Every call leg is a row in staging, and both legs of a forwarded call are billed, so `call_legs` and `cost` count both. `parent_calls` counts only legs without a parent, which is the closer match to "conversations". `direction` is `inbound`, `outbound-api` or `outbound-dial` (the child leg of a <Dial>). `billable_minutes` rounds each completed leg up to the next minute, which is how Twilio bills most voice usage. SIP and some international routes are billed per second, so treat it as an estimate and use `cost` for money. Answer rate is completed legs over all legs; the per-row rates should be re-derived from summed counts when you aggregate.

Raw tables it reads

  • raw.twilio.call

Put Twilio in front
of your agents.

Connect Twilio, deploy the models, and ask questions in Claude, Cursor or ChatGPT. Free for 14 days, no credit card.