Skip to main content
A warm transfer briefs a human representative before the caller is connected. In this guide, you’ll build a Twilio integration where:
  1. An inbound agent answers the call and collects the caller’s reason for calling.
  2. While the inbound agent keeps the caller company, an outbound agent calls a customer service representative and briefs them.
  3. Once the representative is ready, both calls are transferred into a shared Twilio conference.
New to Guava + Twilio? Start with the Twilio Programmable Voice / TwiML guide for the basics of routing Twilio calls to a Guava agent.

Prerequisites

  • Two Guava SIP codes, one for the inbound agent and one for the outbound agent. Create them on the SIP page in the Guava dashboard.
  • A Twilio phone number, and a Twilio API key.
  • A public URL that Twilio can reach for webhooks (e.g. using ngrok during development).
Install dependencies:

Configure your Twilio number

In the Twilio Console, go to Phone Numbers > Manage > Active Numbers and select your number. Under Voice Configuration, set A call comes in to Webhook with the URL https://<your-public-url>/inbound-call and method HTTP POST. Then click Save configuration.

Inbound call reaches the inbound agent

When a call comes in, Twilio requests /inbound-call. This returns a Dial command telling Twilio to transfer to the inbound agent’s SIP code. The referUrl attribute tells Twilio to send any later transfers from this agent to /refer.
main.py

Inbound agent collects the reason and stalls

The inbound agent collects reason_for_calling. Once that task is complete, the agent is given a new task: keep the caller on the line while a representative is found.
main.py
At the same time, the handler generates a random conference ID and uses the Twilio API to start an outbound call to the representative. When the representative answers, Twilio connects them to the outbound agent’s SIP code. The reason for calling, the conference ID, and the inbound call’s ID are passed through to the outbound agent as X- SIP headers.
main.py
Twilio only forwards custom SIP headers prefixed with X-. SipUri URL-encodes the header values, but the URI still has to be XML-escaped in TwiML.

Outbound agent briefs the representative

The outbound agent reads X-Call-Reason from call.call_info.sip_headers, explains the caller’s issue to the representative, and confirms that they’re ready to take the call.
main.py

Both calls join the conference

Once the representative is ready, the outbound agent uses guava.RemoteCall with X-Original-Call-Id to control the waiting inbound call, and transfers both calls to sip:<conference_id>@conference.internal. Each agent says a short message before it transfers.
main.py
Twilio sends each transfer to /refer with the target in ReferTransferTarget. The handler extracts the conference ID and returns <Conference> TwiML, which places the caller and the representative in the same room. endConferenceOnExit="true" ends the conference when either party hangs up.
main.py

Run the example

Save the full example below as main.py, then set your Twilio credentials and start the server:
Call your Twilio number. After you give a reason for calling, the representative’s phone will ring. Once they’ve been briefed, you’ll both be connected in a conference.

Full example

main.py