RELAY

RELAY

Python API reference for RelayClient, Call, Message, and real-time events

View as MarkdownOpen in Claude

The RELAY namespace provides imperative, event-driven control over voice calls and SMS/MMS messages through a persistent WebSocket connection to SignalWire. While the Agents namespace handles AI-driven conversations declaratively via SWML, RELAY gives you fine-grained, async control over every step of a call — answering, playing prompts, collecting digits, recording, bridging, conferencing, and more.

RELAY uses the JSON-RPC 2.0 protocol over WebSocket (wss://). The client authenticates once, subscribes to contexts for inbound events, and processes call and message events in an async event loop. Automatic reconnection with exponential backoff ensures resilience against transient network failures.

Context Routing

Contexts are routing labels that control which inbound calls and messages are delivered to your application. When you assign a phone number to a context in the SignalWire dashboard, all calls to that number are routed to RELAY clients subscribed to that context.

1from signalwire.relay import RelayClient
2
3# Subscribe to specific contexts
4client = RelayClient(
5 project="your-project-id",
6 token="your-api-token",
7 host="your-space.signalwire.com",
8 contexts=["support", "sales"],
9)
10
11@client.on_call
12async def handle_call(call):
13 await call.answer()
14
15 # Or subscribe/unsubscribe dynamically
16 # await client.receive(["billing"]) # Add a context
17 # await client.unreceive(["sales"]) # Remove a context
18
19client.run()

A client only receives events for its subscribed contexts. This enables multiple applications or workers to handle different call flows on the same project by subscribing to different contexts.

Example

An IVR that answers calls, plays a menu, collects a digit, and routes accordingly:

1from signalwire.relay import RelayClient
2
3client = RelayClient(
4 project="your-project-id",
5 token="your-api-token",
6 host="your-space.signalwire.com",
7 contexts=["default"],
8)
9
10@client.on_call
11async def handle_call(call):
12 await call.answer()
13
14 # Play a menu and collect one digit
15 action = await call.play_and_collect(
16 media=[{"type": "tts", "text": "Press 1 for sales, 2 for support."}],
17 collect={"digits": {"max": 1, "digit_timeout": 5.0}},
18 )
19 event = await action.wait()
20
21 digit = event.params.get("result", {}).get("digits", "")
22
23 if digit == "1":
24 await call.play([{"type": "tts", "text": "Transferring to sales."}])
25 await call.transfer(dest="+15551234567")
26 elif digit == "2":
27 await call.play([{"type": "tts", "text": "Transferring to support."}])
28 await call.transfer(dest="+15559876543")
29 else:
30 await call.play([{"type": "tts", "text": "Goodbye."}])
31 await call.hangup()
32
33client.run()

Classes