Skip to main content

siphon-control (Python)

Python client for the SIPhon external control plane (siphon-control.v1) — an ARI/ESL-class rail for driving handed-over calls out of process. Built with PyO3 over the async Rust client, so the wire is hidden: no manual JSON, no request-id bookkeeping.

Two connection modes

The plane runs in one of two modes; both are exposed here and share the SAME @on_call decorator and the SAME Call handle — only the transport differs.

  • Inbound-persistent (ControlClient) — the app dials siphon and holds one long-lived socket (does the hello handshake). Simplest to reason about; use it for development and single-process controllers.
  • Per-call-connect (ControlServer) — siphon dials the app per handed-over call, so the app is a WebSocket server. Each accepted connection owns exactly one call and the first frame is a pushed StasisStart (no hello). This is the documented production default for multi-pod controllers: because the accepting socket is the call, "the audio lands on the wrong pod" can't happen.

Inbound-persistent

import asyncio
from siphon_control import ControlClient, ControlError

client = ControlClient(app="ivr-app", token="s3cr3t",
                       url="ws://siphon:9090/control/ws")

@client.on_call
async def handle(call):
    await call.answer()
    try:
        await call.transfer("sip:agent@pbx")   # REFER, awaits correlated reply
    except ControlError as error:
        print("transfer rejected:", error.code)

async def main():
    async with client:          # closes on the way out — see Shutdown below
        await client.run()

asyncio.run(main())

Per-call-connect

import asyncio
from siphon_control import ControlServer, ControlError

server = ControlServer(app="ivr-app", token="s3cr3t", bind="0.0.0.0:8790")

@server.on_call
async def handle(call):
    await call.answer()
    try:
        await call.transfer("sip:agent@pbx")
    except ControlError as error:
        print("transfer rejected:", error.code)

async def main():
    async with server:
        await server.serve()

asyncio.run(main())

Shutdown

Both classes are async context managers, and async with is the recommended shape. close() is the same thing explicitly.

It matters more than it looks. run() / serve() are driven by a background tokio task, and every handed-over call is dispatched from another one. Nothing joins those tasks and the runtime outlives the interpreter, so an app that finishes without closing leaves them delivering results into an asyncio loop — and then into a Python — that is no longer there. Closing first means there is nothing in flight to strand.

Not closing is handled rather than fatal: a handover arriving after the loop or interpreter has gone is dropped, and a handler cancelled during teardown is not reported as a failure. That is damage control, not a substitute for closing.

API

ControlClient (inbound-persistent)

  • ControlClient(app, token, url=…, protocol=1, reply_timeout_ms=…, reconnect_backoff_ms=…)
  • @client.on_call — register an async (or sync) per-call handler.
  • await client.connect() / await client.run() — connect / drive (reconnect + resync).
  • await client.command(verb, module=None, target=None, args=None) — the generic {module, verb, target, args} primitive for any adapter (SIP today; SMPP/SS7 later).
  • await client.originate(channel, to, *, media=False, sdp=None, body=None, content_type=None, …, session_timer=None) — place an outbound call under a channel id you choose; resolves to {"channel", "call_id", "sip_call_id"} once the INVITE is on the wire. Exactly one media plan (media=True, sdp= or body=). session_timer={"expires", "min_se", "refresher"} runs an RFC 4028 session timer on the call, each key left out taking the server's default. What the server would refuse raises ValueError before a frame goes out.
  • await client.describe() — adapter schema.
  • client.shutdown() — stop the client and unblock run().
  • client.close() — shutdown, plus drop the handler so nothing else is dispatched. async with client: does this on the way out. See Shutdown above.

ControlServer (per-call-connect)

  • ControlServer(app, token, bind="0.0.0.0:8790", reply_timeout_ms=…) — bind is the address the app listens on for siphon to dial; the token is validated on the incoming upgrade.
  • @server.on_call — the SAME decorator + Call handle as ControlClient.
  • await server.bind() — bind the listener; resolves to the bound address string (bind to …:0 to learn the ephemeral port before siphon dials in).
  • server.local_addr — the bound address once bind() / serve() has run, else None.
  • await server.serve() / await server.run() — accept siphon's per-call dials forever (stop by cancelling the task).
  • server.close() — drop the handler so no further accepted call is dispatched. async with server: does this on the way out. See Shutdown above.

Call (shared by both modes)

  • Call verbs: answer(), answer_with(code, …), progress(), reject(code, reason), hangup(reason=None), refer(to) / transfer(to), set_header(name, value), get_header(name), set_var(key, value), get_var(key), command(verb, args=None), next_event().
  • Media verbs play_file(file) / dtmf(digits) raise ControlError with code == "unsupported_verb" until the server implements media.

Errors

A rejected command raises ControlError carrying a stable .code (not_found, forbidden, unsupported_verb, unauthorized, …).

Build

maturin develop        # into the active venv
maturin build --release

The target interpreter is free-threaded CPython 3.14t (the SIPhon runtime); the wheel also loads on a standard GIL build.

License

MIT

Release files for siphon-control 0.3.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for siphon-control 0.3.0
File Size Uploaded
siphon_control-0.3.0.tar.gz 98.6 kB Details

Built distributions (wheels)

Table of built distributions (wheels) for siphon-control 0.3.0
File
siphon_control-0.3.0-cp314-cp314t-win_amd64.whl CPython 3.14 CPython 3.14 free-threading Windows x86-64 Details
siphon_control-0.3.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl CPython 3.14 CPython 3.14 free-threading Linux glibc 2.17+ x86-64 Details
siphon_control-0.3.0-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl CPython 3.14 CPython 3.14 free-threading Linux glibc 2.17+ ARM64 Details
siphon_control-0.3.0-cp314-cp314t-macosx_11_0_arm64.whl CPython 3.14 CPython 3.14 free-threading macOS 11.0+ ARM64 Details
siphon_control-0.3.0-cp314-cp314-win_amd64.whl CPython 3.14 CPython 3.14 Windows x86-64 Details
siphon_control-0.3.0-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl CPython 3.14 CPython 3.14 Linux glibc 2.17+ x86-64 Details
siphon_control-0.3.0-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl CPython 3.14 CPython 3.14 Linux glibc 2.17+ ARM64 Details
siphon_control-0.3.0-cp314-cp314-macosx_11_0_arm64.whl CPython 3.14 CPython 3.14 macOS 11.0+ ARM64 Details

Total release size: 15.8 MB

Release files / siphon_control-0.3.0.tar.gz

Download URL siphon_control-0.3.0.tar.gz
Size 98.6 kB
Tags Source
SHA-256 checksum
How to use checksums
4f3baf237a0ff90ea8855bc17895c07e81f335e20ece4f7a6ec2bff4688148bf
BLAKE2b-256 checksum
How to use checksums
b202cfa370173f7a8d1d85a751095c8bead1f206f6d9011bab05f02241887513
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 16, 2026.

Transparency log

Release files / siphon_control-0.3.0-cp314-cp314t-win_amd64.whl

Download URL siphon_control-0.3.0-cp314-cp314t-win_amd64.whl
Size 1.8 MB
Tags CPython 3.14 CPython 3.14 free-threading Windows x86-64
SHA-256 checksum
How to use checksums
e7a5e0de2b2b9bf4547efa2d40aac689fd159b6039ccbcd219a8414f299d4127
BLAKE2b-256 checksum
How to use checksums
8fdefb343ea67046e9eb23fe5245067f2cd7446468433e19c65b5e9235c69b65
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 16, 2026.

Transparency log

Release files / siphon_control-0.3.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl

Download URL siphon_control-0.3.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Size 2.0 MB
Tags CPython 3.14 CPython 3.14 free-threading Linux glibc 2.17+ x86-64
SHA-256 checksum
How to use checksums
554a3e929db86aede3678216b44ac2e96ea6502f8a358a419f4bce0a970e6c1b
BLAKE2b-256 checksum
How to use checksums
8add367d9cc6975ef5cc9cebb8a230d8430c8120432690dfcbf498b7b37a4b7c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 16, 2026.

Transparency log

Release files / siphon_control-0.3.0-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl

Download URL siphon_control-0.3.0-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Size 2.2 MB
Tags CPython 3.14 CPython 3.14 free-threading Linux glibc 2.17+ ARM64
SHA-256 checksum
How to use checksums
15c1d092885785bb372fc0f67ba7bfee43b1d20e651aaf8f355f20e7d5b2119c
BLAKE2b-256 checksum
How to use checksums
a1a5dc328e8b6e8ec652412955c2c002a3d5b985a7b4c93e2bc1d959eb16df02
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 16, 2026.

Transparency log

Release files / siphon_control-0.3.0-cp314-cp314t-macosx_11_0_arm64.whl

Download URL siphon_control-0.3.0-cp314-cp314t-macosx_11_0_arm64.whl
Size 1.9 MB
Tags CPython 3.14 CPython 3.14 free-threading macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
24ddf8b18dc5778329ce44c733202bfa8366115d561e6bf86ea114b57d40f178
BLAKE2b-256 checksum
How to use checksums
bfd46114f63c827dbd0d2e57fd907e8014f5a236e910e892e380a1260641c3bc
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 16, 2026.

Transparency log

Release files / siphon_control-0.3.0-cp314-cp314-win_amd64.whl

Download URL siphon_control-0.3.0-cp314-cp314-win_amd64.whl
Size 1.8 MB
Tags CPython 3.14 Windows x86-64
SHA-256 checksum
How to use checksums
a3c5d953eb58cb75740b65ea6ad89acdf9e8c90bf1ad7c1d317a161209734c00
BLAKE2b-256 checksum
How to use checksums
0c06d5783983a933f65ea51a52d85d25276f5af527c5e190bcca0207b6dac6d6
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 16, 2026.

Transparency log

Release files / siphon_control-0.3.0-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl

Download URL siphon_control-0.3.0-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Size 2.0 MB
Tags CPython 3.14 Linux glibc 2.17+ x86-64
SHA-256 checksum
How to use checksums
bb99e6b9d0d255ee9ef0031c07227261056b38c42ca240d9ea0ca0efc45c1904
BLAKE2b-256 checksum
How to use checksums
f073ff391f4212af3de56d44632617cea2dde93637a3b9491119a25ee8dca829
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 16, 2026.

Transparency log

Release files / siphon_control-0.3.0-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl

Download URL siphon_control-0.3.0-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Size 2.2 MB
Tags CPython 3.14 Linux glibc 2.17+ ARM64
SHA-256 checksum
How to use checksums
3452613fe9816b2e5ced0b64846160804bcfb76d18fc4c2ce7134c13dbc9d610
BLAKE2b-256 checksum
How to use checksums
28a9b1cc21c41f77610c42ccb22920c35350d5f093d115b3cc7e6fa160748a93
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 16, 2026.

Transparency log

Release files / siphon_control-0.3.0-cp314-cp314-macosx_11_0_arm64.whl

Download URL siphon_control-0.3.0-cp314-cp314-macosx_11_0_arm64.whl
Size 1.9 MB
Tags CPython 3.14 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
70d981e0c03d701f656e0d87e6e64ecbfd14f7141e3bf31623c8d1848c5cad77
BLAKE2b-256 checksum
How to use checksums
b9b884b81179f253e069bd80af9badf75430414a883241b9d1792044023d15ac
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 16, 2026.

Transparency log

Release history Release notifications | RSS feed

0.5.0

9 release files

0.4.0

9 release files

This release

0.3.0 This release

9 release files

0.2.0

9 release files

0.1.3

9 release files

0.1.2

9 release files

0.1.1

9 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page