#20058: feat(voice-call): add Twilio non-US region support (region/edge config)
channel: voice-call
size: S
Cluster:
TwiML Security and Fixes
Add optional `region` and `edge` fields to the Twilio provider config, enabling EU (IE1/Dublin) and other non-US Twilio regions.
When configured, API requests target `api.{edge}.{region}.twilio.com` instead of the default US1 endpoint. If only `region` is set, the edge is auto-inferred (ie1→dublin, au1→sydney).
Supported processing regions: ie1 (Ireland), au1 (Australia). US1 is the default when region is omitted.
Legacy region codes (br1, de1, jp1, sg1, us2) are intentionally excluded from the default edge map per Twilio's API domain migration guide.
## Summary
- **Problem:** Twilio voice-call provider is hardcoded to the US1 API endpoint (`api.twilio.com`), making it impossible to use EU/AU regions for data processing
- **Why it matters:** EU users need data processed in IE1 (Ireland) for compliance/latency; Twilio's legacy `api.{region}.twilio.com` pattern is deprecated (dies April 28, 2026)
- **What changed:** Added `region` and `edge` config fields to TwilioConfigSchema, dynamic base URL construction in TwilioProvider, plugin JSON schema + uiHints, env var support (TWILIO_REGION, TWILIO_EDGE)
- **What did NOT change:** Default behavior (no region = US1 as before), webhook handling, media streams, TwiML generation, all other providers
## Change Type (select all)
- [ ] Bug fix
- [x] Feature
- [ ] Refactor
- [ ] Docs
- [ ] Security hardening
- [ ] Chore/infra
## Scope (select all touched areas)
- [ ] Gateway / orchestration
- [ ] Skills / tool execution
- [ ] Auth / tokens
- [ ] Memory / storage
- [x] Integrations
- [ ] API / contracts
- [ ] UI / DX
- [ ] CI/CD / infra
## Linked Issue/PR
- Related: https://www.twilio.com/docs/global-infrastructure/api-domain-migration-guide
## User-visible / Behavior Changes
- New optional config fields: `twilio.region` and `twilio.edge` under `plugins.entries.voice-call.config`
- New env vars: `TWILIO_REGION`, `TWILIO_EDGE`
- No change to defaults — omitting region/edge keeps US1 behavior
## Security Impact (required)
- New permissions/capabilities? `No`
- Secrets/tokens handling changed? `No` (auth token field unchanged, but users must use region-specific credentials when targeting non-US regions)
- New/changed network calls? `Yes` — API calls route to `api.{edge}.{region}.twilio.com` when region is configured
- Command/tool execution surface changed? `No`
- Data access scope changed? `No`
- Mitigation: Only activates when user explicitly sets `region` in config. Default behavior unchanged. Uses the non-deprecated FQDN format per Twilio's migration guide.
## Repro + Verification
### Environment
- OS: macOS (arm64)
- Runtime: Node.js v25.6.1
- Provider: Twilio (paid account)
- Integration: voice-call plugin
### Steps
1. Set `twilio.region: "ie1"` and `twilio.edge: "dublin"` in voice-call config
2. Set `twilio.authToken` to an IE1-specific auth token (from Twilio Console → IE1 region)
3. Initiate an outbound call
### Expected
- Call created via `api.dublin.ie1.twilio.com`
- Call connects and audio works normally
### Actual
- Call created successfully, audio worked, conversation mode functional
## Evidence
- [x] Failing test/log before + passing after
- 67/67 tests pass across the full voice-call extension (9 new tests for URL construction)
- Live tested: outbound conversation call through IE1/Dublin endpoint — connected, TTS and STT worked
## Human Verification (required)
- Verified: outbound call via IE1 Dublin endpoint, full conversation mode with streaming TTS/STT
- Edge cases checked: no region (US1 default), region without edge (auto-infer), explicit edge+region, unknown region (falls back to ashburn edge)
- Not verified: AU1 (Sydney) region, inbound calls through non-US region
## Compatibility / Migration
- Backward compatible? `Yes`
- Config/env changes? `Yes` — new optional fields, no required changes
- Migration needed? `No`
## Failure Recovery (if this breaks)
- Remove `region` and `edge` from twilio config → reverts to US1
- Files: `extensions/voice-call/src/providers/twilio.ts` — `buildBaseUrl()` falls back to `api.twilio.com` when no region is set
- Bad symptoms: auth errors (wrong credentials for region), calls not appearing in Twilio console (check region-specific console)
## Risks and Mitigations
- **Risk:** User sets region but uses US1 auth token → auth failure
- **Mitigation:** JSDoc and uiHints clearly state region-specific credentials are required; error message from Twilio is explicit (Error 20003)
<!-- greptile_comment -->
<h3>Greptile Summary</h3>
Adds optional `region` and `edge` configuration fields to the Twilio voice-call provider, enabling API requests to target non-US Twilio regions (IE1/Dublin, AU1/Sydney) using the non-deprecated FQDN format (`api.{edge}.{region}.twilio.com`). Default behavior (US1) is preserved when these fields are omitted.
- Config schema (`TwilioConfigSchema`), plugin JSON schema, uiHints, and env var fallbacks (`TWILIO_REGION`, `TWILIO_EDGE`) all updated consistently
- `TwilioProvider.buildBaseUrl()` static method cleanly handles URL construction with auto-inference of edge from region
- 9 new unit tests cover all URL construction paths (default, explicit, inferred, fallback, override)
- Runtime wiring in `runtime.ts` passes the new fields through correctly
- One minor suggestion: tighten Zod validation on `region`/`edge` strings to prevent malformed URLs from typos containing special characters
<h3>Confidence Score: 4/5</h3>
- This PR is safe to merge — it adds well-tested optional config fields with no impact on default behavior.
- Clean, focused feature addition with good test coverage (9 new tests). Default US1 behavior is unchanged. The only minor concern is the lack of format validation on the new string fields, which could produce confusing errors on typos but is not a security risk in practice since the values come from the user's own config.
- extensions/voice-call/src/config.ts — the `region` and `edge` Zod schemas accept any non-empty string; consider adding a regex constraint.
<sub>Last reviewed commit: 1d1a9f2</sub>
<!-- greptile_other_comments_section -->
<sub>(2/5) Greptile learns from your feedback when you react with thumbs up/down!</sub>
<!-- /greptile_comment -->
Most Similar PRs
#10238: Security: Fix TwiML injection via unescaped locale/language/voice p...
by StreetJammer · 2026-02-06
72.1%
#10231: fix(voice-call): escape locale/language params in TwiML to prevent ...
by coygeek · 2026-02-06
71.6%
#8922: feat(voice-call): Add ElevenLabs WebSocket streaming TTS
by mikiships · 2026-02-04
70.4%
#7965: feat(tts): add Speechify as TTS provider
by chaerla · 2026-02-03
69.1%
#22889: feat(talk): add provider-agnostic talk config contract
by ngutman · 2026-02-21
68.8%
#8297: fix(voice-call): prevent empty TwiML for non-in-progress outbound c...
by vishaltandale00 · 2026-02-03
68.0%
#22186: feat(talk): add baseUrl support for custom TTS servers
by bautrey · 2026-02-20
67.9%
#7704: fix(voice-call): add authentication to WebSocket media stream endpoint
by coygeek · 2026-02-03
67.8%
#4325: fix(voice-call): verify call status with provider before loading st...
by garnetlyx · 2026-01-30
67.6%
#20794: feat(tts): add Fish Audio provider with full docs, tests & gateway ...
by twangodev · 2026-02-19
67.6%