Skip to main content

Modern, high-performance SIP library for Python — httpx-inspired API, async-native, IVR, RTP, DTMF

Project description

sipx

Python 3.12+ License: MIT

A modern, high-performance SIP library for Python inspired by httpx.

Build voice automation scripts, IVR systems, AI-powered call handlers, and SIP testing tools with a clean, Pythonic API.

Features

  • httpx-inspired APIclient.invite(), client.register(), sync and async
  • FastAPI-style server@server.invite, Annotated DI extractors
  • Response buildersrequest.ok(), request.trying(), request.error(code)
  • Dialog trackingclient.ack() / client.bye() without passing response
  • Declarative events@on('INVITE', status=200) decorators
  • Full SIP support — 14 methods, auto 100 Trying, auto DNS SRV resolution
  • Digest authentication — MD5, SHA-256, auto-retry on 401/407
  • RTP + DTMF — RFC 4733 + SIP INFO + Inband, sync and async
  • SDP with ICE/SRTP — RFC 4566, offer/answer, ICE candidates, DTLS
  • Media pipeline — RTP, tone generators, TTS/STT adapters, IVR builder
  • SIP-I — Real ISUP binary encoding (ITU-T Q.763), Brazilian SIP-I (ANATEL)
  • Multiple transports — UDP, TCP, TLS, WebSocket (sync + async)
  • State management — Transaction FSMs with Timer A/E retransmission
  • Extensible — ABC-based transports, body parsers, custom DI extractors

Quick Start

import sipx

# One-liners
sipx.options("sip:pbx.example.com")
sipx.register("sip:alice@pbx.com", auth=("alice", "secret"))
sipx.send("sip:bob@pbx.com", "Hello!", auth=("alice", "secret"))

# Full call with dialog tracking
from sipx import Client

with Client(local_port=5061) as client:
    client.auth = ("alice", "secret")

    client.register("sip:alice@pbx.com")

    sdp = client.create_sdp(port=8000)
    r = client.invite("sip:bob@pbx.com", body=sdp.to_string())

    if r.status_code == 200:
        client.ack()    # uses tracked dialog
        # call is active...
        client.bye()    # uses tracked dialog

Installation

# With uv (recommended)
uv add sipx

# With pip
pip install sipx

# From source
git clone https://github.com/oornnery/sipx.git
cd sipx
uv sync

Requirements

Python 3.12+

Usage Examples

SIP Server (FastAPI-style decorators + DI)

from typing import Annotated
from sipx import SIPServer, Request, FromHeader, Header

server = SIPServer(local_host="127.0.0.1", local_port=5060)

@server.register
def on_register(request: Request, caller: Annotated[str, FromHeader]):
    print(f"REGISTER from {caller}")
    return request.ok()

@server.message
def on_message(request: Request, caller: Annotated[str, FromHeader]):
    body = request.content.decode() if request.content else ""
    print(f"MESSAGE from {caller}: {body}")
    return request.ok()

server.start()

Async Client

import asyncio
from sipx import AsyncClient

async def main():
    async with AsyncClient(local_port=5061) as client:
        client.auth = ("alice", "secret")

        r = await client.register("sip:alice@pbx.com")
        print(f"REGISTER: {r.status_code}")

        sdp = client.create_sdp(port=8000)
        r = await client.invite("sip:bob@pbx.com", body=sdp.to_string())
        if r and r.status_code == 200:
            await client.ack()
            await asyncio.sleep(5)
            await client.bye()

asyncio.run(main())

FastAPI + SIP Integration

Run a REST API that controls SIP operations:

# Terminal 1: SIP server
uv run python examples/server.py

# Terminal 2: FastAPI
uv run python examples/fastapi_sip.py

# Terminal 3: test via curl
curl -X POST http://localhost:8000/message \
  -H "Content-Type: application/json" \
  -d '{"uri":"sip:test@127.0.0.1:15090","content":"Hello from FastAPI!"}' | jq
{
  "status_code": 200,
  "reason": "OK"
}

Full request/response trace with retransmission timers, DI resolution, and FSM state transitions:

# FastAPI (client side)
INFO     UDP bound to 0.0.0.0:40703
DEBUG    Transaction 592b5fee created: MESSAGE (type=NON_INVITE)
DEBUG    Timer E started (0.5s)          # retransmission armed
DEBUG    Timer F started (32.0s)         # timeout armed
DEBUG    UDP send 335 bytes -> 127.0.0.1:15090
DEBUG    UDP recv 245 bytes <- 127.0.0.1:15090
DEBUG    <<< 200 OK
DEBUG    Transaction 592b5fee: TRYING -> COMPLETED
DEBUG    Timer E cancelled               # retransmission stopped
DEBUG    Timer F cancelled               # timeout stopped

# SIP Server (server side)
DEBUG    UDP recv 335 bytes <- 127.0.0.1:40703
DEBUG    Resolving handler on_message
DEBUG    Extracting caller via FromHeader()
  MESSAGE from <sip:user@0.0.0.0>: Hello from FastAPI!
DEBUG    >>> SENDING 200 OK to 127.0.0.1:40703
DEBUG    UDP send 245 bytes -> 127.0.0.1:40703

Event Handlers

from sipx import Events, on

class CallEvents(Events):
    @on('INVITE', status=200)
    def on_call_ok(self, request, response, context):
        print("Call accepted!")

    @on('INVITE', status=(180, 183))
    def on_ringing(self, request, response, context):
        print(f"Ringing... ({response.status_code})")

    @on(status=(401, 407))
    def on_auth(self, request, response, context):
        print("Auth challenge received")

Authentication

# Tuple auth (auto-retry on 401/407)
client.auth = ("alice", "secret")

# Or explicit Auth object
client.auth = Auth.Digest("alice", "secret")

# Per-request override
r = client.register("sip:alice@pbx.com")
if r.status_code == 401:
    r = client.retry_with_auth(r, auth=Auth.Digest("alice", "other"))

Supported Methods

Method Description Example
INVITE Establish a call client.invite('sip:bob@ex.com', body=sdp)
ACK Acknowledge INVITE client.ack() (auto dialog)
BYE Terminate a call client.bye() (auto dialog)
CANCEL Cancel pending INVITE client.cancel(response=r)
REGISTER Register location client.register('sip:alice@ex.com')
OPTIONS Query capabilities client.options('sip:ex.com')
MESSAGE Instant message client.message('sip:bob@ex.com', content='Hi')
SUBSCRIBE Subscribe to events client.subscribe('sip:bob@ex.com')
NOTIFY Event notification client.notify('sip:bob@ex.com')
REFER Call transfer client.refer('sip:bob@ex.com', refer_to='sip:carol@ex.com')
INFO Mid-dialog info (DTMF) client.info('sip:bob@ex.com', content=dtmf)
UPDATE Update session client.update('sip:bob@ex.com', sdp_content=sdp)
PRACK Provisional ACK client.prack(response=r)
PUBLISH Publish state client.publish('sip:bob@ex.com')

RFC Compliance

RFC Title Status
3261 SIP: Session Initiation Protocol Complete (auto 100 Trying, retransmission)
2617 HTTP Digest Authentication Complete (MD5, SHA-256)
7616 HTTP Digest (SHA-256) Complete
4566 SDP: Session Description Protocol Complete (ICE, SRTP, DTLS)
3264 Offer/Answer Model with SDP Complete
3550 RTP: Real-time Transport Protocol Complete (sync + async)
4733 DTMF via RTP (telephone-event) Complete
3263 DNS SRV Resolution Complete (auto in Client)
4028 Session Timers Complete

Documentation

Document Description
docs/SDD.md Software Design Document (full spec, diagrams, roadmap)
examples/README.md Examples catalog (22 examples)
docker/asterisk/ Asterisk test environment

Testing with Asterisk

cd docker/asterisk
docker-compose up -d
uv run python examples/asterisk.py

Examples

See examples/README.md for the full list. Highlights:

Example What it shows
quickstart.py One-liner register, options, call, send
call.py REGISTER -> INVITE -> ACK -> BYE
server.py SIPServer with decorators + DI
ivr.py Async IVR with RTP + DTMF
response_builders.py request.ok/trying/error, dialog tracking
asterisk.py Comprehensive integration test

Roadmap

See docs/SDD.md for the full roadmap. Key upcoming work:

  • SRTP — packet encryption (RFC 3711)
  • RTCP — control protocol (RFC 3550 Section 6)
  • Jitter buffer — for smooth RTP playback
  • Coverage >80% — currently 607 tests, ~60%
  • PyPI publishing — package ready, CI pipeline configured

Development

git clone https://github.com/oornnery/sipx.git
cd sipx
uv sync
uv run ruff check sipx
uv run pytest

Inspirations

API design:

  • httpx — Pythonic API, sync/async, extensible

Reference implementations:

Other inspirations:

License

MIT License

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

sipx-0.0.6.tar.gz (172.3 kB view details)

Uploaded Source

Built Distribution

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

sipx-0.0.6-py3-none-any.whl (181.6 kB view details)

Uploaded Python 3

File details

Details for the file sipx-0.0.6.tar.gz.

File metadata

  • Download URL: sipx-0.0.6.tar.gz
  • Upload date:
  • Size: 172.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for sipx-0.0.6.tar.gz
Algorithm Hash digest
SHA256 db900169f027c5563fdc8a0f05798ff894212756a9aeb2cee37222d10bf4da38
MD5 b5a5feea58534a6aed9b854158b8d40d
BLAKE2b-256 87d9a443ada1c7e72eb8823db851fbb9fb399ce6617af498b5b429a430ca57b0

See more details on using hashes here.

Provenance

The following attestation bundles were made for sipx-0.0.6.tar.gz:

Publisher: release.yml on oornnery/sipx

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

File details

Details for the file sipx-0.0.6-py3-none-any.whl.

File metadata

  • Download URL: sipx-0.0.6-py3-none-any.whl
  • Upload date:
  • Size: 181.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for sipx-0.0.6-py3-none-any.whl
Algorithm Hash digest
SHA256 d957a44d39aa0383d7fe7d4c8428751c1644fe29d756febdf9e5367b0733bf60
MD5 e2cefe6de968cc0ad5e98bc9ceb59537
BLAKE2b-256 209501c0a28f03cf5444e1dc9265c9edfa382ed3af25bd47cda54695e72ff430

See more details on using hashes here.

Provenance

The following attestation bundles were made for sipx-0.0.6-py3-none-any.whl:

Publisher: release.yml on oornnery/sipx

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