A modern, intuitive SIP (Session Initiation Protocol) library for Python with a clean, declarative API.
- π― Simple & Intuitive - Clean API with declarative event handlers
- π Automatic Authentication - Built-in digest authentication with auto-retry
- π‘ Multiple Transports - UDP, TCP, and TLS support
- π¨ Rich Console Output - Beautiful CLI with colored output
- π State Management - Automatic transaction and dialog tracking
- π Full SIP Support - INVITE, REGISTER, OPTIONS, MESSAGE, BYE, and more
from sipx import Client, Events, Auth, event_handler
class MyEvents(Events):
"""Define your event handlers with decorators."""
@event_handler('INVITE', status=200)
def on_call_accepted(self, request, response, context):
print("Call accepted!")
print(f"SDP: {response.body}")
# Create client and make a call
with Client() as client:
client.events = MyEvents()
client.auth = Auth.Digest('alice', 'secret')
response = client.invite('sip:bob@example.com', 'sip:alice@local')That's it! Authentication, retries, and state management are all handled automatically.
# Install uv if you don't have it
curl -LsSf https://astral.sh/uv/install.sh | sh
# Install sipx
uv pip install sipx
# Or add to your project
uv add sipxpip install sipxfrom sipx import Client, Events, Auth, event_handler, SDPBody
# Define event handlers
class CallEvents(Events):
def on_request(self, request, context):
"""Called before every request is sent."""
print(f"β Sending {request.method}")
return request
def on_response(self, response, context):
"""Called after every response is received."""
print(f"β Received {response.status_code}")
return response
@event_handler('INVITE', status=180)
def on_ringing(self, request, response, context):
print("π Ringing...")
@event_handler('INVITE', status=200)
def on_accepted(self, request, response, context):
print("β
Call accepted!")
# Use the client
with Client(local_port=5060) as client:
# Configure
client.events = CallEvents()
client.auth = Auth.Digest('alice', 'secret')
# Create SDP
sdp = SDPBody.offer(
local_ip=client.local_address.host,
local_port=8000,
audio=True
)
# Make call
response = client.invite('sip:bob@example.com', body=sdp.to_string())
if response.status_code == 200:
client.ack(response=response)
# Call is active...
client.bye(response=response)with Client() as client:
client.auth = Auth.Digest('alice', 'secret')
# Host is auto-extracted from AOR
response = client.register(aor='sip:alice@example.com')
if response.status_code == 200:
print("β Registered successfully!")with Client() as client:
response = client.message(
to_uri='sip:bob@example.com',
content='Hello from SIPX!'
)with Client() as client:
response = client.options(uri='sip:example.com')
print(f"Server: {response.headers.get('Server')}")The @event_handler decorator lets you handle specific SIP events:
class MyEvents(Events):
# Handle specific method and status
@event_handler('INVITE', status=200)
def on_invite_ok(self, request, response, context):
pass
# Handle multiple status codes
@event_handler('INVITE', status=(401, 407))
def on_auth_required(self, request, response, context):
pass
# Handle multiple methods
@event_handler(('INVITE', 'MESSAGE'), status=200)
def on_success(self, request, response, context):
pass
# Handle any status for a method
@event_handler('REGISTER')
def on_any_register(self, request, response, context):
pass
# Handle any method with specific status
@event_handler(status=404)
def on_not_found(self, request, response, context):
passAuthentication is automatic when you set client.auth:
# Simple
client.auth = Auth.Digest('username', 'password')
# With optional parameters
client.auth = Auth.Digest(
username='alice',
password='secret',
realm='example.com',
display_name='Alice Smith',
user_agent='MyApp/1.0'
)When the server challenges with 401/407, the client automatically:
- Parses the challenge
- Builds the authorization header
- Retries the request
- Returns the final response
- INVITE - Establish calls
- ACK - Acknowledge INVITE responses
- BYE - Terminate calls
- CANCEL - Cancel pending INVITE
- REGISTER - Register with a server
- OPTIONS - Query server capabilities
- MESSAGE - Send instant messages
- SUBSCRIBE - Subscribe to events
- NOTIFY - Send event notifications
- REFER - Call transfer
- INFO - Mid-call information (DTMF)
- UPDATE - Session parameter updates
- PRACK - Provisional response acknowledgement
- PUBLISH - Publish event state
Check out the examples/ directory for more:
simple_example.py- Minimal registration examplesimplified_demo.py- Complete demo with all features
Run the examples:
# Simple registration
uv run python examples/simple_example.py
# Full demo (requires Asterisk server)
uv run python examples/simplified_demo.pyStart an Asterisk server with Docker:
cd docker/asterisk
docker-compose up -dConfigure a user in pjsip.conf:
[alice]
type=endpoint
context=default
disallow=all
allow=ulaw
auth=alice
aors=alice
[alice]
type=auth
auth_type=userpass
password=secret
username=alice
[alice]
type=aor
max_contacts=1Then run the examples against 192.168.1.100 (or your Asterisk IP).
# Clone the repository
git clone https://github.com/yourusername/sipx.git
cd sipx
# Install dependencies
uv sync
# Run tests
uv run pytest
# Run linting
uv run ruff check sipx# All tests
uv run pytest
# With coverage
uv run pytest --cov=sipx
# Specific test file
uv run pytest tests/test_client.pyFor advanced use cases, see the Simplified API Documentation.
Topics covered:
- Custom event handlers
- Transaction and dialog state access
- Manual authentication handling
- Transport configuration
- Error handling
- Migration from old API
Contributions are welcome! Please feel free to submit a Pull Request.
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add some amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
This project is licensed under the MIT License - see the LICENSE file for details.
- Built with Rich for beautiful console output
- Inspired by modern HTTP libraries like HTTPX
- RFC 3261 (SIP) and related RFCs for protocol implementation
- Issues: GitHub Issues
- Discussions: GitHub Discussions
Made with β€οΈ for the SIP community