Skip to content

fix(0.6.1): direction- and country-aware Twilio telephony billing#97

Open
nicolotognoni wants to merge 1 commit into
feat/observability-otel-attrs-0.6.1from
fix/0.6.1-telephony-pricing-matrix
Open

fix(0.6.1): direction- and country-aware Twilio telephony billing#97
nicolotognoni wants to merge 1 commit into
feat/observability-otel-attrs-0.6.1from
fix/0.6.1-telephony-pricing-matrix

Conversation

@nicolotognoni
Copy link
Copy Markdown
Collaborator

Summary

  • Default twilio telephony billing was a flat $0.0085/min (US inbound local) — under-estimates outbound by 9-40x for international mobile destinations (e.g. US → IT mobile is $0.3473/min, ~40x the default).
  • Adds a per-country, per-direction, per-line-type matrix sourced from Twilio's public pricing pages (verified 2026-05-12), plus a stateless E.164 → ISO-2 parser. No new dependencies (hand-rolled tiny ISO map).
  • Backward compatibility is exact: omitting the new arguments keeps the legacy code path billing at pricing.twilio.price as before.

Implementation

  • New modules:
    • libraries/typescript/src/services/telephony-pricing-matrix.ts
    • libraries/python/getpatter/services/telephony_pricing_matrix.py
  • calculateTelephonyCost / calculate_telephony_cost gain optional direction, destCountry / dest_country, destType / dest_type parameters. Detection of twilio provider + presence of direction + destCountry switches from flat rate to matrix lookup.
  • CallMetricsAccumulator gains setTelephonyContext / set_telephony_context so the carrier handler (Twilio/Telnyx adapter) populates the context once direction and remote E.164 number are known.
  • destType defaults to mobile (conservative — international mobile rates universally exceed landline rates; under-billing on a margin dashboard is worse than over-billing).
  • Operators with negotiated Twilio rates can override the entire matrix via pricing.twilio_outbound_matrix (free-form dict, no SDK fork needed).
  • Files touched: pricing.ts/.py, metrics.ts/.py, index.ts/__init__.py, tests/pricing.test.ts, tests/test_pricing.py, CHANGELOG.md, plus the two new matrix modules.

Pricing matrix (Twilio US-account, USD/min, verified 2026-05-12)

ISO Destination Inbound local Inbound toll-free Outbound landline Outbound mobile
US United States 0.0085 0.022 0.014 0.014
CA Canada (bundled) 0.0085 0.014 0.014
GB United Kingdom 0.0158 0.0305
DE Germany 0.021 0.042
FR France (non-EEA origin) 0.0187 0.1603
IT Italy mobile 0.01 0.0168 0.3473
ES Spain 0.0178 0.0388
NL Netherlands (non-EEA) 0.3675 0.2763
BR Brazil 0.031 0.0663
MX Mexico 0.016 0.0473
IN India 0.0497 0.0405
JP Japan 0.0746 0.185
AU Australia 0.0252 0.075

Sources: https://www.twilio.com/en-us/voice/pricing/us and per-destination pages at https://www.twilio.com/en-us/voice/pricing/<iso2>.

Breaking change?

No. All new parameters are optional with safe defaults; existing callers bill identically to before. Public surface adds a new context object and a new metrics setter — both opt-in. Parity holds across Python and TypeScript: identical matrix, identical country-code map, identical API shape (snake_casecamelCase).

Test plan

  • Python: pytest tests/test_pricing.py -v65 pass (17 new: matrix lookup, parser, override surface, backward-compat fallback)
  • TypeScript: npx vitest run tests/pricing.test.ts57 pass (17 new mirror Python)
  • Full Python suite: pytest tests/ -m "not soak" -q1858 pass, 7 skipped (pre-existing)
  • Full TypeScript suite: npx vitest run1533 pass / 85 files
  • npm run lint — clean (tsc --noEmit)
  • npm run build — clean (tsup esm + cjs + types, 320 KB d.ts)

Docs updates

  • CHANGELOG.md## Unreleased entry under ### Changed with source URL and override syntax.
  • READMEs untouched (no existing dedicated Pricing section).

Default twilio telephony billing was a flat $0.0085/min — the US inbound
local rate. Correct for the 99% case of an agent receiving calls on a US
local number, but under-estimated outbound by 9-40x for international
mobile destinations (US → IT mobile is $0.3473/min, ~40x the default).
On a mixed-traffic dashboard the cost.telephony rollup could swing total
margin reporting by 10x or more.

Add a per-country, per-direction, per-line-type matrix sourced from
Twilio's public pricing pages (verified 2026-05-12), plus a stateless
E.164 → ISO-2 parser (no new deps, tiny hand-rolled country code map).
calculateTelephonyCost / calculate_telephony_cost gain optional
direction, destCountry, destType arguments. CallMetricsAccumulator gains
a setTelephonyContext / set_telephony_context setter the carrier handler
can call once direction and remote number are known.

Backward compatibility is exact: omitting all new arguments keeps the
legacy code path billing at pricing.twilio.price as before.

Sources (all verified 2026-05-12, US-account perspective):
- https://www.twilio.com/en-us/voice/pricing/us
- https://www.twilio.com/en-us/voice/pricing/{it,gb,de,fr,es,nl,br,mx,in,jp,au,ca}

Operators with negotiated Twilio rates can override the entire matrix
via pricing.twilio_outbound_matrix.

Parity: Python ↔ TypeScript matrices, country codes, and API shape are
identical. 65 Python + 57 TS pricing tests cover the matrix, parser,
override surface, and backward-compat fallback. Full suites green
(1858 Py + 1533 TS).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant