Skip to main content

rstream Python SDK

rstreamlabs-rstream is the Python SDK for rstream tunnels and webhook receivers. Python code imports it as rstream.

The SDK is async-first, framework-neutral, and uses the same runtime protocol and CLI-compatible configuration model as the Go, JavaScript, Java, and C++ SDKs. It is designed for Python services that need to publish local HTTP applications, dial private tunnels, accept bytestream tunnel connections directly, or verify rstream webhook deliveries in a backend framework.

SDK Surface

This repository targets Python 3.10 and newer.

The first public release focuses on the Python-native surface that is ready for production use:

Area Supported
Runtime client Async control-channel client
Published tunnels HTTP/1.1 bytestream tunnels
Private tunnels Dial by tunnel name or ID
Local forwarding BytestreamTunnel.forward_to(host, port)
Direct accept await tunnel.accept() and async iteration
ASGI helper Direct HTTP/1.1 bridge for ASGI apps
WSGI helper Direct HTTP/1.1 bridge for WSGI apps
Live inventory client.list_tunnels() and client.list_clients() with filters
Real-time events client.watch() over SSE or WebSocket
Webhooks Signature generation, verification, and event parsing
Config CLI-compatible YAML config and environment variables

Datagram tunnels, QUIC runtime transport, HTTP/3 tunnel creation, custom transport proxies, and external credential stores are rejected explicitly by this SDK version instead of being ignored.

Install

pip install rstreamlabs-rstream

For ASGI/FastAPI helpers:

pip install "rstreamlabs-rstream[asgi]"

For WSGI/Flask/Django helpers:

pip install "rstreamlabs-rstream[wsgi]"

For managed project endpoint discovery through the Control plane API:

pip install "rstreamlabs-rstream[api]"

For local example applications:

pip install "rstreamlabs-rstream[examples]"

Configuration

The SDK reads the same config file as the CLI by default:

~/.rstream/config.yaml

Configuration is resolved in this order:

  1. Explicit Client(...) options.
  2. Environment variables.
  3. The selected context in the config file.
  4. SDK defaults.

Environment variables

Variable Purpose
RSTREAM_CONFIG Override the config file path.
RSTREAM_CONTEXT Select a context from the config file.
RSTREAM_ENGINE Use an explicit engine host and optional port.
RSTREAM_AUTHENTICATION_TOKEN Use an explicit authentication token.
RSTREAM_MTLS_CERT_FILE Client certificate file for mTLS authentication.
RSTREAM_MTLS_KEY_FILE Client private key file for mTLS authentication.
RSTREAM_API_URL Control plane API URL for managed project discovery.
RSTREAM_REGION Authorized region to select for a managed project.
RSTREAM_CONTROL_PLANE_HEADERS Additional Control plane request headers encoded as a JSON object.

RSTREAM_ENGINE_ADDRESS is also accepted for compatibility with older local SDK workflows. Prefer RSTREAM_ENGINE in new code.

See docs/001-configuration.md for supported YAML fields and error behavior.

FastAPI tunnel

import asyncio

from fastapi import FastAPI

import rstream

app = FastAPI()


@app.get("/")
async def root() -> dict[str, str]:
    return {"status": "ok"}


async def main() -> None:
    async with (
        rstream.Client.from_env() as client,
        await client.connect() as control,
    ):
        tunnel = await control.create_tunnel(
            protocol="http",
            http_version="http/1.1",
            publish=True,
        )
        print("Forwarding address:", tunnel.forwarding_address)
        await rstream.asgi.serve(app, tunnel)


asyncio.run(main())

The ASGI helper parses accepted rstream streams and dispatches them to the app in-process. It does not start a loopback server.

Local forwarding

forward_to() remains available for existing services that already listen on a local TCP port:

await tunnel.forward_to("127.0.0.1", 8000)

It keeps accepting rstream streams and relays them to the local TCP service until the tunnel or control channel is closed.

The control channel uses a negotiated heartbeat deadline. If that deadline expires, or the control transport ends unexpectedly, the SDK immediately stops accepting new streams but lets already accepted streams and active forward_to() relays drain normally. This avoids interrupting an established application session because of a transient or asymmetric control-path outage. An explicit tunnel/control close or a protocol violation remains a hard close and terminates active local forwarding. Applications should use each stream's EOF/error as its payload-lifecycle signal; control.done() only describes the control plane.

Private dial

import asyncio

import rstream


async def main() -> None:
    async with (
        rstream.Client.from_env() as client,
        await client.dial("private-api") as stream,
    ):
        stream.write(b"ping")
        await stream.drain()
        print(await stream.read(1024))


asyncio.run(main())

Private tunnels are addressed by name or ID. They do not expose a public forwarding address.

Live inventory and real-time events

The engine exposes its live state through the same client. list_tunnels and list_clients return the current inventory, optionally filtered, and watch streams lifecycle events (tunnel.created, tunnel.updated, tunnel.deleted, and the client equivalents) as an async iterator. Label filters make the inventory usable as a service registry: tag tunnels at creation time, then discover them by label.

import asyncio

import rstream


async def main() -> None:
    async with rstream.Client.from_env() as client:
        filters = rstream.TunnelFilters(labels={"role": "inference"})
        for tunnel in await client.list_tunnels(filters=filters):
            print(tunnel.properties.name, tunnel.status)
        async for event in client.watch(tunnels=filters, transport="websocket"):
            print(event.type, event.object)


asyncio.run(main())

Listing and the SSE transport require the api extra (pip install "rstreamlabs-rstream[api]"); the WebSocket transport requires the realtime extra, which adds the websockets dependency. The watch connection uses the runtime token and ends when the surrounding task is cancelled.

Webhook receiver

from fastapi import Request

import rstream


async def handle_webhook(request: Request) -> None:
    payload = await request.body()
    signature = request.headers["rstream-signature"]
    secret = "whsec_..."

    event = rstream.verify_event(payload, signature, secret)
    resource_id = event.object.get("id")
    if event.type == "tunnel.created":
        print("Tunnel is online:", resource_id)

event.id is suitable for idempotency. Keep the raw request body unchanged when verifying the signature.

See docs/003-webhooks.md for the payload shape and headers.

Examples

Example Purpose
examples/forward-local-port Publish an existing local TCP service.
examples/private-dial Dial a private tunnel by name or ID.
examples/fastapi-tunnel Publish a FastAPI app through the direct ASGI helper.
examples/flask-tunnel Publish a Flask app through the direct WSGI helper.
examples/django-tunnel Publish a Django app through the direct WSGI helper.
examples/aiohttp-local-forwarding Publish an aiohttp app through managed local forwarding.
examples/webhook-receiver Verify webhook deliveries inside a FastAPI route.
examples/flask-webhook-receiver Verify webhook deliveries inside a Flask route.
examples/django-webhook-receiver Verify webhook deliveries inside a Django view.

Development

python -m venv .venv
. .venv/bin/activate
pip install -e ".[dev]"
ruff check .
ruff format --check .
mypy
pytest
python -m build

Real-engine tests are opt-in:

RSTREAM_PYTHON_E2E=1 pytest tests/e2e

See docs/004-testing.md for local-engine and managed-environment test commands.

Repository setup and release

The intended GitHub repository is rstreamlabs/rstream-python. CI requires no secret for normal pull request checks. Release automation uses release-please and requires the maintainer-managed RELEASE_PLEASE_TOKEN secret plus the CI_ALLOWED_ACTOR repository variable.

See docs/006-github-setup.md before creating or publishing the repository.

License

Apache-2.0. See LICENSE.

Metadata

Release files for rstreamlabs-rstream 0.6.1

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

Source distribution (sdist)

Source distribution for rstreamlabs-rstream 0.6.1
File Size Uploaded
rstreamlabs_rstream-0.6.1.tar.gz 87.4 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for rstreamlabs-rstream 0.6.1
File Interpreter ABI Platform
rstreamlabs_rstream-0.6.1-py3-none-any.whl Python 3 none any Details

Total release size: 143.6 kB

Release files / rstreamlabs_rstream-0.6.1.tar.gz

Download URL rstreamlabs_rstream-0.6.1.tar.gz
Size 87.4 kB
Tags Source
SHA-256 checksum
How to use checksums
22facfbc9f0b8edd2c2ea45123da408f003874f95c916d9fdfbeb001cc10e8b8
BLAKE2b-256 checksum
How to use checksums
3dd4577a6530e37391b5897e9b955c168e284667cb33036fe091ab6846e45494
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.13

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 Aug 15, 2026.

Transparency log

Release files / rstreamlabs_rstream-0.6.1-py3-none-any.whl

Download URL rstreamlabs_rstream-0.6.1-py3-none-any.whl
Size 56.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
c583cddc5cf0cd8a0b733a12121daaab7c75a18ffb64ec19614c3c323acfdcc1
BLAKE2b-256 checksum
How to use checksums
fcd5e73adb11b994bda056722249e8f48282ec3cc3205912373e18bee6a2d421
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.13

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 Aug 15, 2026.

Transparency log

Release history Release notifications | RSS feed

0.7.0

2 release files

This release

0.6.1 This release

2 release files

0.5.0

2 release files

0.4.0

2 release files

0.3.0

2 release files

0.2.0

2 release files

0.1.1

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