Skip to main content

Official Python SDK for the VoiceML REST API (Twilio-compatible voice + AMD service from VoiceTel)

Project description

📞 VoiceML Python SDK

The official Python client for the VoiceML REST API — Twilio-compatible outbound voice and answering-machine-detection from VoiceTel, with type-safe, async-ready Python.

Version Python License Tests Typed

📚 Table of Contents

✨ Features

🛡️ Strongly Typed End-to-End

  • Pydantic v2 models for every one of the 81 API operations — request bodies validated before they leave your machine, responses validated when they arrive.
  • Autocomplete everywhere. Your IDE knows the shape of every field — Call.sid, Recording.duration, Queue.current_size are all typed.
  • Twilio-compatible wire shapesaccount_sid, from_number, to_number, status callbacks, pagination envelopes — match what Twilio's Programmable Voice API documents.

⚡ Sync + Async, Same Surface

  • Client for blocking calls, AsyncClient for await-based async — identical method names, identical return types.
  • Built on httpx — HTTP/2 ready, connection pooling, custom transports if you need them.
  • TLS session cache + persistent connections out of the box.

🔁 Production-Grade Transport

  • Automatic retry with exponential backoff on 429 / 5xx — honors Retry-After headers.
  • Configurable timeouts per client or per call.
  • HTTP Basic auth with AccountSid:ApiKey — exactly what the Twilio SDK uses, so existing credentials work unchanged.
  • Structured exception hierarchyRateLimitError, AuthenticationError, NotFoundError, etc. all subclasses of ApiError you can catch broadly or narrowly.

📞 Complete API Coverage

  • Calls — originate, fetch, terminate, update + per-call recordings, streams, siprec, transcriptions, notifications, events, and the /Calls/{sid}/Payments lifecycle (Pay TwiML companion).
  • Conferences — list, fetch, end conferences, plus participants (mute / hold / kick) and conference-scoped recordings.
  • Queues — create, list, update, delete, peek, dequeue (front or specific member).
  • Applications — CRUD on stored TwiML + callback bundles.
  • Recordings — account-wide list, metadata fetch, audio fetch (follows S3 redirect), delete.
  • Messages — create, fetch, list (To/From/DateSent filters + pagination), update (Body redaction; Status=canceled), delete.
  • IncomingPhoneNumbers — list, fetch, update.
  • Notifications — fetch, list.
  • Diagnostics/health deep probe, OpenAPI spec.

🧪 Tested

  • 57 unit tests with mocked HTTP layer (respx) and real Pydantic validation on every fixture — spec drift gets caught at parse time.
  • Integration test suite that runs against a callBroadcast / VoiceML instance — gated by env vars, safe for CI.

📦 Clean Distribution

  • Zero codegen footprint — every byte hand-written.
  • Built with hatchling; ships as wheel + sdist.
  • py.typed marker — downstream type checkers see your imports natively.

🚀 Installation

pip install voiceml

Requires Python 3.10 or later. Tested against 3.10, 3.11, 3.12, and 3.13.

🏁 Quickstart

from voiceml import Client
from voiceml.models import CreateCallRequest

with Client(account_sid="AC…", api_key="…") as c:
    call = c.calls.create(
        CreateCallRequest(
            To="+18005551234",
            From="+18005550000",
            Url="https://example.com/twiml",
            MachineDetection="DetectMessageEnd",
        )
    )
    print(call.sid, call.status)

    for q in c.queues.list().queues:
        print(q.friendly_name, q.current_size)

🔑 Authentication

Every endpoint uses HTTP Basic with your AccountSid as the username and your per-tenant API key as the password — identical to Twilio's auth shape, so credentials issued for Twilio code work here unchanged.

from voiceml import Client

with Client(account_sid="AC…", api_key="…") as c:
    me = c.diagnostics.health()  # uses your AccountSid + key on every call

Don't have credentials yet? See voicetel.com/docs/api/v0.6/voiceml/ for issuance and rotation.

🗺️ Resource Reference

Resource Sync + Async Covers
client.calls originate, fetch, list, terminate, update + per-call recordings, streams, siprec, transcriptions, notifications, events, payments
client.conferences list, fetch, end participants (mute / hold / kick), conference-scoped recordings
client.queues create, list, update, delete peek, dequeue (front or specific member)
client.applications CRUD on TwiML + callback bundles
client.recordings account-wide list, metadata, audio fetch, delete follows S3 redirect for audio
client.messages create, fetch, list, update, delete To/From/DateSent filters; Body redaction; Status=canceled
client.incoming_phone_numbers list, fetch, update
client.notifications fetch, list
client.diagnostics /health, OpenAPI spec

Every method that takes a request body accepts a typed Pydantic model imported from voiceml.models:

from voiceml import Client
from voiceml.models import CreateCallRequest, StartPaymentRequest

with Client(account_sid="AC…", api_key="…") as c:
    call = c.calls.create(CreateCallRequest(
        To="+18005551234",
        From="+18005550000",
        Url="https://example.com/twiml",
    ))
    # On a live call, open a Pay session:
    session = c.calls.start_payment(call.sid, StartPaymentRequest(
        IdempotencyKey="order-482917",
        StatusCallback="https://example.com/pay-status",
    ))
    print(session.sid, session.status)

🚨 Error Handling

All HTTP errors raise subclasses of voiceml.ApiError. Catch broadly or narrowly:

Status Exception
400 BadRequestError
401 AuthenticationError
403 PermissionDeniedError
404 NotFoundError
409 ConflictError
410 GoneError
429 RateLimitError
501 NotImplementedAPIError
5xx ServerError
other ApiError
from voiceml import Client, NotFoundError, RateLimitError

with Client(account_sid="AC…", api_key="…") as c:
    try:
        call = c.calls.get("CA0000000000000000000000000000aaaa")
    except NotFoundError:
        print("That call isn't on your account.")
    except RateLimitError as e:
        print(f"Slow down — retry in {e.body.get('retry_after', '?')}s")

The Twilio-compatible error body (code, message, more_info, status) is parsed into error.code / error.message with the raw payload on error.body.

⚡ Async Support

Identical surface to Client, with await-based methods:

import asyncio
from voiceml import AsyncClient

async def main() -> None:
    async with AsyncClient(account_sid="AC…", api_key="…") as c:
        calls = await c.calls.list(status="in-progress")
        for call in calls.calls:
            print(call.sid, call.duration)

asyncio.run(main())

📄 Pagination

List operations return a …List model with a Twilio-compatible pagination envelope (page, page_size, total, next_page_uri, previous_page_uri, …). For /Calls and /Messages, use the iter() helper to walk all pages transparently:

for call in c.calls.iter(status="completed", page_size=200):
    process(call)

for msg in c.messages.iter(from_number="+18005550000", page_size=200):
    archive(msg)

For other resources, page manually with client.<resource>.list(page=n).

🔁 Migration from twilio-python

The account_sid + api_key pair Twilio's SDK validates in its constructor works unchanged here:

# Before — Twilio
from twilio.rest import Client as TwilioClient
client = TwilioClient("AC…", "<token>", region=None)

# After — VoiceML (Twilio-compatible)
from voiceml import Client
client = Client(account_sid="AC…", api_key="<api-key>")

Method names follow the resource map above (client.calls.create(...), client.queues.list(), …) rather than Twilio's client.api.v2010.accounts(sid).calls.create(...) chain — flatter, fewer keystrokes, same wire format on the way out.

⏱️ Rate Limits

VoiceML applies per-tenant rate limits at the edge. The SDK automatically retries 429 responses with Retry-After honored, up to max_retries (default 2). To bump it:

Client(account_sid="AC…", api_key="…", max_retries=4, timeout=60.0)

🛠️ Development

git clone https://github.com/voicetel/voiceml-python-sdk
cd voiceml-python-sdk
python -m venv .venv && source .venv/bin/activate
pip install -e ".[dev]"

# Unit tests (fast, no network)
pytest tests/unit

# Lint + type-check
ruff check src tests
mypy src

# Integration tests (live, read-only against a configured VoiceML instance)
cp .env.example .env  # fill in VOICEML_ACCOUNT_SID / VOICEML_API_KEY / VOICEML_BASE_URL
pytest tests/integration

# Build wheel + sdist
python -m build
twine check dist/*

📖 API Documentation

🙌 Contributors

Contributions welcome. Open an issue describing the change you want to make, or send a pull request against main.

💖 Sponsors

Sponsor Contribution
VoiceTel Communications Primary development and production hosting

📄 License

MIT with the Commons Clause restriction. See LICENSE and voicetel.com/legal/.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

voiceml-0.7.1.tar.gz (31.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

voiceml-0.7.1-py3-none-any.whl (45.6 kB view details)

Uploaded Python 3

File details

Details for the file voiceml-0.7.1.tar.gz.

File metadata

  • Download URL: voiceml-0.7.1.tar.gz
  • Upload date:
  • Size: 31.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for voiceml-0.7.1.tar.gz
Algorithm Hash digest
SHA256 63d09040669e708d284965b2873208360bf8c0f010d1596738b21e01430298a2
MD5 73b82dd35f045396ee91e827cf2acba8
BLAKE2b-256 9c0add632caae10f121c5c2748e8b3b21ce06f3d1347efad280a3d8c692fe13f

See more details on using hashes here.

Provenance

The following attestation bundles were made for voiceml-0.7.1.tar.gz:

Publisher: publish.yml on voicetel/voiceml-python-sdk

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file voiceml-0.7.1-py3-none-any.whl.

File metadata

  • Download URL: voiceml-0.7.1-py3-none-any.whl
  • Upload date:
  • Size: 45.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for voiceml-0.7.1-py3-none-any.whl
Algorithm Hash digest
SHA256 ae65ece1d286b1d5d8c6487d755cedc1f4dfd1c1fde3fe4331b16529e9d4fe5e
MD5 8599d273606eaabe2e74015bd3cd0843
BLAKE2b-256 010a8b19769badc789d31ca2698de54aba6bd06d7dd9e97a5d5eccda055dac2e

See more details on using hashes here.

Provenance

The following attestation bundles were made for voiceml-0.7.1-py3-none-any.whl:

Publisher: publish.yml on voicetel/voiceml-python-sdk

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page