Open in
Connect from Amazon Connect
Send Amazon Connect calls to a ThunderPhone agent over SIP with the contact id and UUI, and resume your flow with the agent
Your Amazon Connect flow sends the caller to the agent with the contact id and any UUI you set. When the agent is done, it hangs up, your flow carries on, and a Lambda fetches the hand-off by contact id.
Before you start
- A ThunderPhone agent and an organization API key.
- Amazon Connect's External voice transfer connector. Request the "External voice transfer connectors per account" quota increase first: the menu stays hidden until AWS approves it. AWS bills each connector per day ($100 a day since July 21, 2025) plus per-minute usage.
1. Create the SIP endpoint
The connector doesn't document SIP digest authentication, so create an endpoint that accepts calls by source address:
curl -X POST https://api.thunderphone.com/v1/sip-endpoints \
-H "Authorization: Bearer sk_live_YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"agent_id": 12,
"name": "Amazon Connect",
"auth": "ip_allowlist",
"allowed_source_cidrs": ["CONNECT_SIGNALLING_RANGE_1", "CONNECT_SIGNALLING_RANGE_2"]
}'Get the connector's SIP signalling ranges for your Region from AWS. Each must be
a public IPv4 range of /16 or narrower (IPv6 /48 or narrower). See
Platforms that authenticate by source IP
for the rules and the risk of an address shared by every customer of the
platform. Keep the response's sip_uri, for example
sip:agent-12-jhxmginwjx@sip.thunderphone.com.
2. Send calls with context
- In the Amazon Connect console, open External Voice Systems → Voice Transfer Integrations and choose Create.
- Pick the destination type (an SBC) and add an outbound route with host
sip.thunderphone.com, port5061and protocol TLS. The endpoint needs TLS or TCP (port5060) and refuses UDP. AWS doesn't document which protocols the connector offers, so confirm with AWS that it can use one of them. - In your flow, add a Transfer to phone number block with Transfer to
set to External voice system, and set:
- Destination ARN: the connector.
- To User: the user part of the endpoint's
sip_uri, such asagent-12-jhxmginwjx. - UUI (optional): context for the agent. Connect sends it hex-encoded.
- Resume flow after disconnect: Yes, so the flow continues when the agent hangs up.
Connect sends the contact id in X-Amzn-ConnectContactId. ThunderPhone stores
it as the call's external_call_id, which is how your flow finds the call
later. The UUI reaches the prompt as {{sip_uui}}. Third-party integrations
document the contact-id header; AWS's own docs don't, so check it on your first
test call.
3. Get the call back
AWS documents no way for Connect to read headers on the BYE or to accept a
REFER from the agent. So the agent returns the call: it says goodbye and
hangs up, and your flow resumes after the transfer block. Add this transfer
number (see Add the transfer number):
{"name": "Amazon Connect", "action": "return"}Then fetch the hand-off with an Invoke AWS Lambda function block after the transfer. The Lambda looks the call up by contact id:
import json
import os
import urllib.error
import urllib.parse
import urllib.request
def lambda_handler(event, context):
contact_id = event["Details"]["ContactData"]["ContactId"]
url = "https://api.thunderphone.com/v1/calls/handoff?" + urllib.parse.urlencode(
{"external_call_id": contact_id}
)
request = urllib.request.Request(
url, headers={"Authorization": "Bearer " + os.environ["THUNDERPHONE_API_KEY"]}
)
try:
with urllib.request.urlopen(request, timeout=5) as response:
call = json.load(response)
except (urllib.error.URLError, TimeoutError):
return {"found": "false"}
handoff = call.get("handoff") or {}
return {
"found": "true",
"intent": handoff.get("intent") or "",
"summary": handoff.get("summary") or "",
}The block returns a flat map, so the flow can branch on intent or set
summary as a contact attribute for the person who takes the call. Run the
block synchronously (up to 8 seconds) and store the API key encrypted, for
example in AWS Secrets Manager. The response fields are in
Look up a handed-off call.
Test it
Call a number on your Connect instance that reaches the transfer block, ask the
agent for a person, and check that the flow resumes. Then open the call with
GET /v1/calls/{call_id}: sip_headers should list
x-amzn-connectcontactid, and external_call_id should equal the ContactId
your Lambda receives. If the transfer fails with SIP 404, ThunderPhone didn't
find the endpoint's user part: it must be in both the request URI and the To
header.
Limits
- AWS documents no way to read headers on the
BYE, includingX-TP-Handoff-Id, so the contact id is the only link back to the call. - AWS doesn't document a maximum UUI length for the connector.
- A synchronous Lambda block times out after 8 seconds.