Events

View as MarkdownOpen in Claude

RELAY events are delivered as typed class instances that wrap the raw JSON-RPC event payloads from the SignalWire WebSocket connection. When you register a handler with Call.on() or Message.on(), the handler automatically receives a typed event object with named properties for each field.

All typed event classes inherit from RelayEvent, which provides access to the raw params dictionary alongside the typed properties. You can also use the parseEvent() helper to manually parse raw event payloads.

1import { RelayClient, CallStateEvent } from '@signalwire/sdk';
2
3const client = new RelayClient({
4 project: process.env.SIGNALWIRE_PROJECT_ID!,
5 token: process.env.SIGNALWIRE_TOKEN!,
6 contexts: ['default']
7});
8
9client.onCall(async (call) => {
10 const handleState = (event: CallStateEvent) => {
11 console.log(`Call state: ${event.callState}`);
12 };
13
14 call.on('calling.call.state', handleState);
15 await call.answer();
16});
17
18await client.run();

RelayEvent

Base event class. All other event classes inherit from this. Every handler receives at minimum a RelayEvent instance, which provides access to the raw event data.

eventType
string

The event type string (e.g., "calling.call.state", "messaging.receive"). See Constants for the full list.

params
Record<string, unknown>

The raw parameters dictionary from the event payload. Contains all event-specific fields, including those not surfaced as typed attributes on subclasses.

callId
string

The call identifier associated with this event, if applicable.

timestamp
numberDefaults to 0.0

Server timestamp of the event.

Methods

fromPayload

Static method. Parse a raw event object into a RelayEvent instance.

Parameters

payload
Record<string, unknown>Required

Raw event payload dictionary.

payload.event_type
stringRequired

The event type string (e.g., "calling.call.state").

payload.params
Record<string, unknown>Required

Event-specific parameters.

Returns

RelayEvent — A new event instance with typed properties.

Example

1import { RelayEvent } from '@signalwire/sdk';
2
3const event = RelayEvent.fromPayload({
4 event_type: 'calling.call.state',
5 params: { call_state: 'answered' },
6});
7console.log(event.eventType); // "calling.call.state"

parseEvent

Standalone helper function. Parses a raw event object and returns the appropriate typed event subclass based on the event_type field. Falls back to RelayEvent for unrecognized event types.

Parameters

payload
Record<string, unknown>Required

Raw event payload dictionary.

payload.event_type
stringRequired

The event type string (e.g., "calling.call.state", "calling.call.play"). Determines which typed subclass is returned.

payload.params
Record<string, unknown>Required

Event-specific parameters. Contents vary by event type.

Returns

RelayEvent — The appropriate typed subclass based on the event_type field, or a base RelayEvent for unrecognized types.

Example

1import { parseEvent, PlayEvent } from '@signalwire/sdk';
2
3const event = parseEvent({
4 event_type: 'calling.call.play',
5 params: { control_id: 'abc-123', state: 'playing' },
6});
7// Returns a PlayEvent instance — narrow the type to access subclass properties
8if (event instanceof PlayEvent) {
9 console.log(event.state); // "playing"
10}

Calling Events

calling.call.state

Emitted when the call state changes through its lifecycle: created -> ringing -> answered -> ending -> ended.

CallStateEvent

Handlers for this event receive a CallStateEvent with the following properties:

callState
string

The new call state.

  • "created" — call object has been initialized
  • "ringing" — call is ringing at the destination
  • "answered" — call has been answered and is active
  • "ending" — hangup is in progress
  • "ended" — call has been fully terminated
endReason
string

Reason the call ended. Only present when callState is "ended".

  • "hangup" — normal disconnect by a party on the call
  • "cancel" — call was cancelled before being answered
  • "busy" — destination signaled busy
  • "noAnswer" — call rang but was not answered within the timeout
  • "decline" — destination actively declined the call
  • "error" — an error occurred during call processing
  • "abandoned" — caller hung up before the call was answered
  • "max_duration" — call reached the maximum allowed duration
  • "not_found" — destination could not be found or routed
direction
string

Call direction.

  • "inbound" — incoming call
  • "outbound" — outgoing call
device
Record<string, unknown>

Device information for the call endpoint.

Example

1import { RelayClient } from '@signalwire/sdk';
2
3const client = new RelayClient({
4 project: process.env.SIGNALWIRE_PROJECT_ID!,
5 token: process.env.SIGNALWIRE_TOKEN!,
6 contexts: ['default']
7});
8
9client.onCall(async (call) => {
10 const handleState = (event: CallStateEvent) => {
11 console.log(`State: ${event.callState}, reason: ${event.endReason}`);
12 };
13
14 call.on('calling.call.state', handleState);
15 await call.answer();
16});
17
18await client.run();

calling.call.receive

Emitted when an inbound call is received on a subscribed context. This event is dispatched at the client level via client.onCall() rather than through call.on().

CallReceiveEvent

Handlers for this event receive a CallReceiveEvent with the following properties:

callState
string

Initial call state (typically "ringing").

direction
string

Always "inbound" for receive events.

device
Record<string, unknown>

Device information for the caller.

nodeId
string

RELAY node handling this call.

projectId
string

SignalWire project ID.

context
string

The context the call was received on.

segmentId
string

Call segment identifier.

tag
string

Correlation tag for the call.

calling.call.play

Emitted when playback state changes on a play operation.

PlayEvent

Handlers for this event receive a PlayEvent with the following properties:

controlId
string

The control ID of the play operation. Matches the control_id on the PlayAction.

state
string

Playback state.

  • "playing" — audio is actively playing
  • "paused" — playback has been paused
  • "finished" — playback completed successfully
  • "error" — an error occurred during playback

Example

1import { RelayClient } from '@signalwire/sdk';
2
3const client = new RelayClient({
4 project: process.env.SIGNALWIRE_PROJECT_ID!,
5 token: process.env.SIGNALWIRE_TOKEN!,
6 contexts: ['default']
7});
8
9client.onCall(async (call) => {
10 const handlePlay = (event: PlayEvent) => {
11 console.log(`Playback: ${event.state}`);
12 };
13
14 call.on('calling.call.play', handlePlay);
15 await call.answer();
16 await call.play([{ type: 'tts', text: 'Hello!' }]);
17});
18
19await client.run();

calling.call.record

Emitted when recording state changes on a record operation.

RecordEvent

Handlers for this event receive a RecordEvent with the following properties:

controlId
string

The control ID of the record operation.

state
string

Recording state.

  • "recording" — audio recording is in progress
  • "paused" — recording has been paused
  • "finished" — recording completed successfully
  • "no_input" — recording ended due to no audio input detected
url
string

URL of the recording file (available when state is "finished").

duration
numberDefaults to 0.0

Recording duration in seconds.

size
numberDefaults to 0

Recording file size in bytes.

record
Record<string, unknown>

Full record metadata object containing url, duration, size, and other fields.

Example

1import { RelayClient } from '@signalwire/sdk';
2
3const client = new RelayClient({
4 project: process.env.SIGNALWIRE_PROJECT_ID!,
5 token: process.env.SIGNALWIRE_TOKEN!,
6 contexts: ['default']
7});
8
9client.onCall(async (call) => {
10 const handleRecord = (event: RecordEvent) => {
11 console.log(`Recording ${event.state}: ${event.url}`);
12 };
13
14 call.on('calling.call.record', handleRecord);
15 await call.answer();
16 await call.record({ direction: 'both' });
17});
18
19await client.run();

calling.call.collect

Emitted when input collection state changes on a collect() or playAndCollect() operation.

CollectEvent

Handlers for this event receive a CollectEvent with the following properties:

controlId
string

The control ID of the collect operation.

state
string

Collection state.

  • "finished" — input was collected successfully
  • "error" — an error occurred during collection
  • "no_input" — no input was detected within the timeout
  • "no_match" — collected input did not match any configured patterns
result
Record<string, unknown>

The collected input result. Contains type and the collected value.

  • "digit" — DTMF digit input was collected
  • "speech" — speech input was collected
final
boolean | undefined

Whether this is the final result. May be undefined for non-continuous collect operations.

Example

1import { RelayClient } from '@signalwire/sdk';
2
3const client = new RelayClient({
4 project: process.env.SIGNALWIRE_PROJECT_ID!,
5 token: process.env.SIGNALWIRE_TOKEN!,
6 contexts: ['default']
7});
8
9client.onCall(async (call) => {
10 const handleCollect = (event: CollectEvent) => {
11 console.log(`Collected: ${JSON.stringify(event.result)}`);
12 };
13
14 call.on('calling.call.collect', handleCollect);
15 await call.answer();
16 await call.playAndCollect(
17 [{ type: 'tts', text: 'Press 1 or 2.' }],
18 { digits: { max: 1 } }
19 );
20});
21
22await client.run();

calling.call.connect

Emitted when a connect operation changes state.

ConnectEvent

Handlers for this event receive a ConnectEvent with the following properties:

connectState
string

Connection state.

  • "connecting" — bridge is being established to the destination
  • "connected" — bridge has been successfully established
  • "disconnected" — bridge has been disconnected
  • "failed" — connection attempt failed
peer
Record<string, unknown>

Information about the connected peer call.

Example

1import { RelayClient } from '@signalwire/sdk';
2
3const client = new RelayClient({
4 project: process.env.SIGNALWIRE_PROJECT_ID!,
5 token: process.env.SIGNALWIRE_TOKEN!,
6 contexts: ['default']
7});
8
9client.onCall(async (call) => {
10 const handleConnect = (event: ConnectEvent) => {
11 console.log(`Connection: ${event.connectState}`);
12 };
13
14 call.on('calling.call.connect', handleConnect);
15 await call.answer();
16 await call.connect(
17 [[{ type: 'phone', params: { to_number: '+15559876543', from_number: '+15551234567' } }]]
18 );
19});
20
21await client.run();

calling.call.detect

Emitted when detection results arrive from a detect operation.

DetectEvent

Handlers for this event receive a DetectEvent with the following properties:

controlId
string

The control ID of the detect operation.

detect
Record<string, unknown>

Detection result. Structure depends on the detection type.

  • "machine" — voicemail or answering machine detection
  • "fax" — fax tone detection
  • "digit" — DTMF digit detection

Example

1import { RelayClient } from '@signalwire/sdk';
2
3const client = new RelayClient({
4 project: process.env.SIGNALWIRE_PROJECT_ID!,
5 token: process.env.SIGNALWIRE_TOKEN!,
6 contexts: ['default']
7});
8
9client.onCall(async (call) => {
10 const handleDetect = (event: DetectEvent) => {
11 console.log(`Detected: ${JSON.stringify(event.detect)}`);
12 };
13
14 call.on('calling.call.detect', handleDetect);
15 await call.answer();
16 await call.detect({ type: 'machine', params: { initial_timeout: 5.0 } });
17});
18
19await client.run();

calling.call.fax

Emitted when a sendFax() or receiveFax() operation changes state.

FaxEvent

Handlers for this event receive a FaxEvent with the following properties:

controlId
string

The control ID of the fax operation.

fax
Record<string, unknown>

Fax result data including pages, status, and document URL.

Example

1import { RelayClient } from '@signalwire/sdk';
2
3const client = new RelayClient({
4 project: process.env.SIGNALWIRE_PROJECT_ID!,
5 token: process.env.SIGNALWIRE_TOKEN!,
6 contexts: ['default']
7});
8
9client.onCall(async (call) => {
10 const handleFax = (event: FaxEvent) => {
11 console.log(`Fax: ${JSON.stringify(event.fax)}`);
12 };
13
14 call.on('calling.call.fax', handleFax);
15 await call.answer();
16 await call.sendFax('https://example.com/invoice.pdf');
17});
18
19await client.run();

calling.call.tap

Emitted when a tap operation changes state.

TapEvent

Handlers for this event receive a TapEvent with the following properties:

controlId
string

The control ID of the tap operation.

state
string

Tap state.

  • "finished" — tap operation completed
tap
Record<string, unknown>

Tap configuration details.

device
Record<string, unknown>

The device receiving the tapped media.

Example

1import { RelayClient } from '@signalwire/sdk';
2
3const client = new RelayClient({
4 project: process.env.SIGNALWIRE_PROJECT_ID!,
5 token: process.env.SIGNALWIRE_TOKEN!,
6 contexts: ['default']
7});
8
9client.onCall(async (call) => {
10 const handleTap = (event: TapEvent) => {
11 console.log(`Tap ${event.state}: ${JSON.stringify(event.tap)}`);
12 };
13
14 call.on('calling.call.tap', handleTap);
15 await call.answer();
16});
17
18await client.run();

calling.call.stream

Emitted when a stream operation changes state.

StreamEvent

Handlers for this event receive a StreamEvent with the following properties:

controlId
string

The control ID of the stream operation.

state
string

Stream state.

  • "finished" — stream operation completed
url
string

The WebSocket URL the stream is connected to.

name
string

The stream name.

Example

1import { RelayClient } from '@signalwire/sdk';
2
3const client = new RelayClient({
4 project: process.env.SIGNALWIRE_PROJECT_ID!,
5 token: process.env.SIGNALWIRE_TOKEN!,
6 contexts: ['default']
7});
8
9client.onCall(async (call) => {
10 const handleStream = (event: StreamEvent) => {
11 console.log(`Stream ${event.state}: ${event.url}`);
12 };
13
14 call.on('calling.call.stream', handleStream);
15 await call.answer();
16});
17
18await client.run();

calling.call.send_digits

Emitted when a send_digits operation changes state.

SendDigitsEvent

Handlers for this event receive a SendDigitsEvent with the following properties:

controlId
string

The control ID of the send_digits operation.

state
string

Send digits state.

Example

1import { RelayClient } from '@signalwire/sdk';
2
3const client = new RelayClient({
4 project: process.env.SIGNALWIRE_PROJECT_ID!,
5 token: process.env.SIGNALWIRE_TOKEN!,
6 contexts: ['default']
7});
8
9client.onCall(async (call) => {
10 const handleDigits = (event: SendDigitsEvent) => {
11 console.log(`Send digits: ${event.state}`);
12 };
13
14 call.on('calling.call.send_digits', handleDigits);
15 await call.answer();
16});
17
18await client.run();

calling.call.dial

Emitted during outbound dial state changes. This event is dispatched at the client level rather than through call.on().

DialEvent

Handlers for this event receive a DialEvent with the following properties:

tag
string

Correlation tag for the dial operation.

dialState
string

Dial state.

  • "answered" — outbound call was answered
  • "failed" — outbound call failed to connect
call
Record<string, unknown>

Call information for the dialed leg.

calling.call.refer

Emitted when a SIP REFER operation changes state.

ReferEvent

Handlers for this event receive a ReferEvent with the following properties:

state
string

Refer state.

sipReferTo
string

The SIP URI the call was referred to.

sipReferResponseCode
string

SIP response code from the REFER request.

sipNotifyResponseCode
string

SIP response code from the NOTIFY message.

Example

1import { RelayClient } from '@signalwire/sdk';
2
3const client = new RelayClient({
4 project: process.env.SIGNALWIRE_PROJECT_ID!,
5 token: process.env.SIGNALWIRE_TOKEN!,
6 contexts: ['default']
7});
8
9client.onCall(async (call) => {
10 const handleRefer = (event: ReferEvent) => {
11 console.log(`Refer to ${event.sipReferTo}: ${event.state}`);
12 };
13
14 call.on('calling.call.refer', handleRefer);
15 await call.answer();
16});
17
18await client.run();

calling.call.hold

Emitted when hold state changes via hold() or unhold().

HoldEvent

Handlers for this event receive a HoldEvent with the following properties:

state
string

Hold state.

Example

1import { RelayClient } from '@signalwire/sdk';
2
3const client = new RelayClient({
4 project: process.env.SIGNALWIRE_PROJECT_ID!,
5 token: process.env.SIGNALWIRE_TOKEN!,
6 contexts: ['default']
7});
8
9client.onCall(async (call) => {
10 const handleHold = (event: HoldEvent) => {
11 console.log(`Hold: ${event.state}`);
12 };
13
14 call.on('calling.call.hold', handleHold);
15 await call.answer();
16});
17
18await client.run();

calling.call.denoise

Emitted when noise reduction state changes.

DenoiseEvent

Handlers for this event receive a DenoiseEvent with the following properties:

denoised
booleanDefaults to false

Whether noise reduction is currently active.

Example

1import { RelayClient } from '@signalwire/sdk';
2
3const client = new RelayClient({
4 project: process.env.SIGNALWIRE_PROJECT_ID!,
5 token: process.env.SIGNALWIRE_TOKEN!,
6 contexts: ['default']
7});
8
9client.onCall(async (call) => {
10 const handleDenoise = (event: DenoiseEvent) => {
11 console.log(`Denoise active: ${event.denoised}`);
12 };
13
14 call.on('calling.call.denoise', handleDenoise);
15 await call.answer();
16});
17
18await client.run();

calling.call.pay

Emitted when a pay operation changes state.

PayEvent

Handlers for this event receive a PayEvent with the following properties:

controlId
string

The control ID of the pay operation.

state
string

Payment state.

  • "finished" — payment collection completed
  • "error" — payment operation failed

Example

1import { RelayClient } from '@signalwire/sdk';
2
3const client = new RelayClient({
4 project: process.env.SIGNALWIRE_PROJECT_ID!,
5 token: process.env.SIGNALWIRE_TOKEN!,
6 contexts: ['default']
7});
8
9client.onCall(async (call) => {
10 const handlePay = (event: PayEvent) => {
11 console.log(`Payment: ${event.state}`);
12 };
13
14 call.on('calling.call.pay', handlePay);
15 await call.answer();
16});
17
18await client.run();

calling.call.echo

Emitted when an echo operation changes state.

EchoEvent

Handlers for this event receive an EchoEvent with the following properties:

state
string

Echo state.

Example

1import { RelayClient } from '@signalwire/sdk';
2
3const client = new RelayClient({
4 project: process.env.SIGNALWIRE_PROJECT_ID!,
5 token: process.env.SIGNALWIRE_TOKEN!,
6 contexts: ['default']
7});
8
9client.onCall(async (call) => {
10 const handleEcho = (event: EchoEvent) => {
11 console.log(`Echo: ${event.state}`);
12 };
13
14 call.on('calling.call.echo', handleEcho);
15 await call.answer();
16});
17
18await client.run();

calling.call.queue

Emitted when queue state changes via queueEnter() or queueLeave().

QueueEvent

Handlers for this event receive a QueueEvent with the following properties:

controlId
string

The control ID of the queue operation.

status
string

Queue status.

queueId
string

The queue identifier.

queueName
string

The queue name.

position
numberDefaults to 0

Current position in the queue.

size
numberDefaults to 0

Total number of calls in the queue.

Example

1import { RelayClient } from '@signalwire/sdk';
2
3const client = new RelayClient({
4 project: process.env.SIGNALWIRE_PROJECT_ID!,
5 token: process.env.SIGNALWIRE_TOKEN!,
6 contexts: ['default']
7});
8
9client.onCall(async (call) => {
10 const handleQueue = (event: QueueEvent) => {
11 console.log(`Queue ${event.queueName}: position ${event.position}/${event.size}`);
12 };
13
14 call.on('calling.call.queue', handleQueue);
15 await call.answer();
16});
17
18await client.run();

calling.conference

Emitted when conference state changes.

ConferenceEvent

Handlers for this event receive a ConferenceEvent with the following properties:

conferenceId
string

The conference identifier.

name
string

The conference name.

status
string

Conference status.

Example

1import { RelayClient } from '@signalwire/sdk';
2
3const client = new RelayClient({
4 project: process.env.SIGNALWIRE_PROJECT_ID!,
5 token: process.env.SIGNALWIRE_TOKEN!,
6 contexts: ['default']
7});
8
9client.onCall(async (call) => {
10 const handleConference = (event: ConferenceEvent) => {
11 console.log(`Conference ${event.name}: ${event.status}`);
12 };
13
14 call.on('calling.conference', handleConference);
15 await call.answer();
16});
17
18await client.run();

calling.call.transcribe

Emitted when a transcribe operation changes state.

TranscribeEvent

Handlers for this event receive a TranscribeEvent with the following properties:

controlId
string

The control ID of the transcribe operation.

state
string

Transcription state.

  • "finished" — transcription completed successfully
url
string

URL of the transcription result.

recordingId
string

Associated recording ID.

duration
numberDefaults to 0.0

Duration of the transcribed audio in seconds.

size
numberDefaults to 0

Size of the transcription data in bytes.

Example

1import { RelayClient } from '@signalwire/sdk';
2
3const client = new RelayClient({
4 project: process.env.SIGNALWIRE_PROJECT_ID!,
5 token: process.env.SIGNALWIRE_TOKEN!,
6 contexts: ['default']
7});
8
9client.onCall(async (call) => {
10 const handleTranscribe = (event: TranscribeEvent) => {
11 console.log(`Transcription ${event.state}: ${event.url}`);
12 };
13
14 call.on('calling.call.transcribe', handleTranscribe);
15 await call.answer();
16});
17
18await client.run();

calling.error

Emitted when an error occurs on the call.

CallingErrorEvent

Handlers for this event receive a CallingErrorEvent with the following properties:

code
string

Error code.

message
string

Human-readable error description.

Example

1import { RelayClient } from '@signalwire/sdk';
2
3const client = new RelayClient({
4 project: process.env.SIGNALWIRE_PROJECT_ID!,
5 token: process.env.SIGNALWIRE_TOKEN!,
6 contexts: ['default']
7});
8
9client.onCall(async (call) => {
10 const handleError = (event: CallingErrorEvent) => {
11 console.log(`Error ${event.code}: ${event.message}`);
12 };
13
14 call.on('calling.error', handleError);
15 await call.answer();
16});
17
18await client.run();

Messaging Events

messaging.receive

Emitted when an inbound SMS/MMS message is received on a subscribed context. This event is dispatched at the client level via client.onMessage().

MessageReceiveEvent

Handlers for this event receive a MessageReceiveEvent with the following properties:

messageId
string

Unique identifier for the message.

context
string

The messaging context the message was received on.

direction
string

Always "inbound" for receive events.

fromNumber
string

Sender phone number in E.164 format.

toNumber
string

Recipient phone number in E.164 format.

body
string

Text content of the message.

media
string[]

Media URLs for MMS messages.

segments
numberDefaults to 0

Number of SMS segments.

messageState
string

State of the message (typically "received").

tags
string[]

Tags associated with the message.

messaging.state

Emitted when an outbound message’s state changes (e.g., queued -> sent -> delivered).

MessageStateEvent

Handlers for this event receive a MessageStateEvent with the following properties:

messageId
string

Unique identifier for the message.

context
string

The messaging context.

direction
string

Always "outbound" for state events.

fromNumber
string

Sender phone number in E.164 format.

toNumber
string

Recipient phone number in E.164 format.

body
string

Text content of the message.

media
string[]

Media URLs for MMS messages.

segments
numberDefaults to 0

Number of SMS segments.

messageState
string

Current message state.

  • "queued" — message accepted by the platform, waiting to be sent
  • "initiated" — message sending has been initiated
  • "sent" — message has been sent to the carrier
  • "delivered" — message has been delivered to the recipient
  • "undelivered" — message could not be delivered
  • "failed" — message sending failed
reason
string

Failure reason if the message failed or was undelivered.

tags
string[]

Tags associated with the message.

Example

1import { RelayClient, MessageStateEvent } from '@signalwire/sdk';
2
3const client = new RelayClient({
4 project: process.env.SIGNALWIRE_PROJECT_ID!,
5 token: process.env.SIGNALWIRE_TOKEN!,
6 contexts: ['default']
7});
8
9client.onMessage(async (message) => {
10 const handleState = (event: MessageStateEvent) => {
11 console.log(`Message ${event.messageId}: ${event.messageState}`);
12 };
13
14 message.on(handleState);
15});
16
17await client.run();

Event Type Mapping

Reference table mapping event_type strings to their typed event classes.

Event TypeClass
calling.call.stateCallStateEvent
calling.call.receiveCallReceiveEvent
calling.call.playPlayEvent
calling.call.recordRecordEvent
calling.call.collectCollectEvent
calling.call.connectConnectEvent
calling.call.detectDetectEvent
calling.call.faxFaxEvent
calling.call.tapTapEvent
calling.call.streamStreamEvent
calling.call.send_digitsSendDigitsEvent
calling.call.dialDialEvent
calling.call.referReferEvent
calling.call.denoiseDenoiseEvent
calling.call.payPayEvent
calling.call.queueQueueEvent
calling.call.echoEchoEvent
calling.call.transcribeTranscribeEvent
calling.call.holdHoldEvent
calling.conferenceConferenceEvent
calling.errorCallingErrorEvent
messaging.receiveMessageReceiveEvent
messaging.stateMessageStateEvent