Bottom Linear Gradient  Lines image

Article

4 min

read

Call Forwarding with the SignalWire Server SDK

A new way to build voice automation using SignalWire RELAY.

SignalWire Team Headshot

SignalWire

In this article

Share

Angular Gradient Image

Build it free.

Create a space and ship your first call flow in minutes.

Subscribe

Tags

Contact Center

PUC

Voice AI

SIP Trunking

Developer Tutorials

Call Forwarding with SignalWire's Server SDK

SignalWire RELAY enables real-time call control over persistent WebSocket connections, so your application can receive inbound call events and issue commands with low latency. This guide walks through a call forwarder pattern where a Node.js RELAY Consumer registers a context, answers inbound calls to a SignalWire phone number mapped to that context, plays a text-to-speech message to the caller, then connects the call to a verified destination number. It also explains how disconnect events are handled so the call can be cleanly ended when either side hangs up.

Understanding the Server SDK and RELAY

Most providers use REST APIs that rely on one-way communication. This adds latency and limits the interactivity of real-time events. SignalWire’s Server SDK allows for simultaneous, bi-directional data transmission.

Complete control will enable easy transfers and injections across all endpoints, making it easier and quicker to build applications.

RELAY enables communications tools to perform in the most popular and widely used environments, like web browsers, mobile devices, in the cloud, or within your own infrastructure.

We’ve published a SignalWire RELAY example that can answer a call with text-to-speech before connecting it to a designated number. All you need is a SignalWire account and phone number to get started.

The instructions to run this code are in the SignalWire GitHub Repository. In this post we’ll go through all the inner workings of the example and explain how RELAY can supercharge your automation.

Call forwarding example

The call forwarding example uses the SignalWire Server SDK to connect as a RELAY Consumer. A RELAY Consumer is essentially a client connected to the SignalWire RELAY API over WebSockets. This creates a persistent, secure connection that allows the client SDK to subscribe to events and send commands.

RELAY uses Contexts, a named string to separate events to specific consumers for specific types of calls or messages or to scale them independently.

When creating outbound requests, or configuring phone numbers for inbound requests, you can specify the context. RELAY will then deliver that call or event to Consumers that are configured to listen for that context.

The above diagram shows how this example works. The RELAY Consumer first connects to the SignalWire cloud using a Project ID and API Token to authenticate. It then registers the context voice-forwarder.

copy

01

02

03

04

05

06

07

08

09

10

11

12

const { RelayConsumer } = require('@signalwire/node')
require('dotenv').config()

const projectId = process.env.SIGNALWIRE_PROJECT_KEY
const token = process.env.SIGNALWIRE_TOKEN
const verifiedNumber = process.env.VERIFIED_NUMBER

const consumer = new RelayConsumer({
  project: projectId,
  token: token,
  contexts: ['voice-forwarder'],
  ready: async ({ client }) => {
    console.log('Consumer Ready!')....

copy

01

02

03

04

05

06

07

08

09

10

11

12

const { RelayConsumer } = require('@signalwire/node')
require('dotenv').config()

const projectId = process.env.SIGNALWIRE_PROJECT_KEY
const token = process.env.SIGNALWIRE_TOKEN
const verifiedNumber = process.env.VERIFIED_NUMBER

const consumer = new RelayConsumer({
  project: projectId,
  token: token,
  contexts: ['voice-forwarder'],
  ready: async ({ client }) => {
    console.log('Consumer Ready!')....

copy

01

02

03

04

05

06

07

08

09

10

11

12

const { RelayConsumer } = require('@signalwire/node')
require('dotenv').config()

const projectId = process.env.SIGNALWIRE_PROJECT_KEY
const token = process.env.SIGNALWIRE_TOKEN
const verifiedNumber = process.env.VERIFIED_NUMBER

const consumer = new RelayConsumer({
  project: projectId,
  token: token,
  contexts: ['voice-forwarder'],
  ready: async ({ client }) => {
    console.log('Consumer Ready!')....

copy

01

02

03

04

05

06

07

08

09

10

11

12

const { RelayConsumer } = require('@signalwire/node')
require('dotenv').config()

const projectId = process.env.SIGNALWIRE_PROJECT_KEY
const token = process.env.SIGNALWIRE_TOKEN
const verifiedNumber = process.env.VERIFIED_NUMBER

const consumer = new RelayConsumer({
  project: projectId,
  token: token,
  contexts: ['voice-forwarder'],
  ready: async ({ client }) => {
    console.log('Consumer Ready!')....


When an inbound call is made to a SignalWire phone number configured to the context voice-forwarder, the Consumer is notified.

The Consumer has a handler function, onIncomingCall, which uses the RELAY SDK method call.playTTS to play a text-to-speech message to let the caller know they are being connected to another number.

copy

01

02

03

04

05

06

07

08

09

10

11

12

onIncomingCall: async (call) => {
    const { successful } = await call.answer()
    if (!successful) { return }

    await call.playTTS({ text: 'Please wait on the line while we connect you.' })

copy

01

02

03

04

05

06

07

08

09

10

11

12

onIncomingCall: async (call) => {
    const { successful } = await call.answer()
    if (!successful) { return }

    await call.playTTS({ text: 'Please wait on the line while we connect you.' })

copy

01

02

03

04

05

06

07

08

09

10

11

12

onIncomingCall: async (call) => {
    const { successful } = await call.answer()
    if (!successful) { return }

    await call.playTTS({ text: 'Please wait on the line while we connect you.' })

copy

01

02

03

04

05

06

07

08

09

10

11

12

onIncomingCall: async (call) => {
    const { successful } = await call.answer()
    if (!successful) { return }

    await call.playTTS({ text: 'Please wait on the line while we connect you.' })


Another RELAY SDK method, call.connect, is used to command the SignalWire cloud to connect the incoming call to a verified number.

copy

01

02

03

04

05

06

07

08

09

10

11

12

const connectResult = await call.connect({ type: 'phone', to: verifiedNumber, timeout: 30 })

copy

01

02

03

04

05

06

07

08

09

10

11

12

const connectResult = await call.connect({ type: 'phone', to: verifiedNumber, timeout: 30 })

copy

01

02

03

04

05

06

07

08

09

10

11

12

const connectResult = await call.connect({ type: 'phone', to: verifiedNumber, timeout: 30 })

copy

01

02

03

04

05

06

07

08

09

10

11

12

const connectResult = await call.connect({ type: 'phone', to: verifiedNumber, timeout: 30 })


If any member of the call disconnects an event, connect.disconnected is sent to the Consumer and the method call.hangup is used to end the call.

copy

01

02

03

04

05

06

07

08

09

10

11

12

call.on('connect.disconnected', async (call) => {
          console.log('Call disconnected, hanging up')
          await call.hangup()
        })

copy

01

02

03

04

05

06

07

08

09

10

11

12

call.on('connect.disconnected', async (call) => {
          console.log('Call disconnected, hanging up')
          await call.hangup()
        })

copy

01

02

03

04

05

06

07

08

09

10

11

12

call.on('connect.disconnected', async (call) => {
          console.log('Call disconnected, hanging up')
          await call.hangup()
        })

copy

01

02

03

04

05

06

07

08

09

10

11

12

call.on('connect.disconnected', async (call) => {
          console.log('Call disconnected, hanging up')
          await call.hangup()
        })


SignalWire RELAY gives you a powerful set of tools to build telecommunications automation. Forwarding a call is just the tip of the iceberg. RELAY allows you to automate the sending and receiving of SMS, user input from voice calls, and much more.

You can modify this particular example to pull from a list of verified numbers and direct calls to the appropriate number based on user input. With some of the other features of RELAY, it is also possible to create automation flows that wait until a user performs an action on a website.

Sign up for a free account to start building with our SDKs, and join us in our Community Discord to connect with our team and other members of our community!

Top Linear Gradient  Lines image

Frequently asked questions

Frequently asked questions

The questions we hear most, answered.

The questions we hear most, answered.

What is call forwarding?

Call forwarding automatically redirects an incoming call from the number that was dialed to a different destination number, so the caller reaches someone (or somewhere) other than the original line.

Why would I want to build my own call forwarder instead of using a basic forwarding setting?

A programmable call forwarder lets you add logic around the transfer — like playing a message to the caller first, choosing a destination based on time of day or caller input, logging call details, or handling what happens if the destination doesn't pick up — instead of a fixed, one-to-one redirect.

Does the caller know their call is being forwarded?

That's up to you. You can play a message like "Please wait while we connect you" before the transfer, or forward the call silently with no indication to the caller.

Can a call forwarder handle multiple destination numbers?

Yes — instead of always forwarding to one fixed number, the destination can be chosen dynamically, for example based on caller input (like a menu selection), the time of day, or which agent is available.

Does call forwarding work for both inbound phone numbers and SIP or web-based calls?

Yes — the same forwarding logic can apply regardless of whether the original call came in via a phone number (PSTN), a SIP endpoint, or a WebRTC-based app, since the forwarding logic operates on the call itself, not just the entry point.

Bottom Linear Gradient  Lines image

The Communications Stack for What's Next

APIs built for speed. Infrastructure built for scale. AI built in from day one.

The Communications Stack for What's Next

APIs built for speed. Infrastructure built for scale. AI built in from day one.

The Communications Stack for What's Next

APIs built for speed. Infrastructure built for scale. AI built in from day one.

The Communications Stack for What's Next

APIs built for speed. Infrastructure built for scale. AI built in from day one.