apps/telephony holds provider-agnostic HTTP clients and helpers for Vobiz and Plivo. Like apps/providers it is a library, not a container: it is copied into both the api and runtime images. The API uses it to provision applications and phone numbers; the runtime uses it to build answer XML, parse webhooks, and serialize audio frames.
This page covers the package layout and public API. The conceptual model — applications, numbers, inbound versus outbound, what each provider owns — is in Telephony model.
base_url are always injected by the caller. The package never reads ProviderAuth, FerretDB, or environment variables for auth.
Public API
apps.providers.schema:
apps/telephony/__init__.py calls load_providers() at import, so vendor configs are registered as soon as the package is imported. Frame serializers are the exception — they need Pipecat and are loaded separately, on demand.
Dump the catalog from a shell:
Method map
Application and outbound methods return
{status, message, ...} dicts built by the ApiResult dataclass in base.py, where status is "success" or "fail". Recording helpers return ids or bytes, or None. list_recordings_for_call exists on Plivo only.
Outbound call
The caller resolves credentials and builds the answer and hangup URLs; the library only makes the HTTP request:initiate_outbound() builds the typed config, creates the client, and calls initiate_call(). The Vobiz payload carries no hangup fields; Plivo includes hangup_url and hangup_method when they are provided.
Answer XML
The runtime keeps a single/answer route and dispatches on the agent’s provider:
sample_rate defaults to 8000 and selects the contentType. The XML format is identical for Vobiz and Plivo today, but each provider owns its own xml.py so the two can diverge later. Callers use the parent dispatcher only.
Per-provider layout
Every provider underproviders/<name>/ follows the same contract:
registry.py keeps four maps — TELEPHONY_CONFIGS, CLIENT_CREATORS, ANSWER_XML_BUILDERS, and FRAME_SERIALIZER_FACTORIES — and rejects a duplicate registration for a provider id with a ValueError. Provider ids are normalised to lower case, so lookups are case-insensitive.
Do not add provider if/elif chains to the package-root xml.py, calls.py, or serializers.py. Those three modules are thin dispatchers over the registry, and that is all they should be. To add a vendor, follow Adding a telephony provider.
Frame serializers
Serializers require Pipecat, so they live behind a second, lazy discovery pass and are never re-exported fromapps.telephony — the API can use Application and Recording without Pipecat installed. The runtime imports the parent factory:
ValueError. Per-provider classes are importable directly when you need the type:
Webhooks
webhooks.py normalises what the two providers send, so the runtime’s /answer route never branches on vendor field names.
Missing numbers default to
"unknown" rather than raising, and direction defaults to "inbound".
Schemas
schema.py mirrors apps.providers.schema. provider_schemas(Kind.TELEPHONY) returns a readable catalog per provider with secrets, required, and fields; configuration_telephony() wraps it with default_providers, where the telephony default is vobiz. Field extras carried through to the catalog are secret, examples, multiline, docs_url, and integration_model. kind, provider, and name are omitted from fields.
This is what GET /api/v1/configuration/telephony returns.
Out of scope
The package deliberately does not do these things. Its callers do.- Phone attach and detach against FerretDB — that is
apps/api. - MinIO storage and recording submission — that is
apps/runtime. - The FastAPI
/answerroute and the WebSocket endpoint — the runtime owns those and calls the XML helper. - Agent config and credential lookup — the caller injects
auth_id,auth_token, andbase_url.
apps/telephony/README.md in the repository is the package’s own reference, kept in step with this page.Related
- Telephony model — applications, numbers, and call direction
- Telephony agents — connecting a number to an agent
- Adding a telephony provider
- Telephony troubleshooting