Skip to content

Route inbound calls from Amazon Connect to a Vapi AI assistant via AWS Chime SDK Voice Connector and SIP trunking, with custom SIP headers for caller context

Notifications You must be signed in to change notification settings

VapiAI/example-amazon-connect-sip-vapi

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Amazon Connect to Vapi via Chime SDK SIP Trunking

Route inbound calls from Amazon Connect to a Vapi AI assistant using AWS Chime SDK Voice Connector and SIP trunking. Pass contact flow variables as custom SIP headers so Vapi knows caller context.

Architecture

sequenceDiagram
    participant Caller
    participant Connect as Amazon Connect
    participant CL as Connect Lambda
    participant DDB as DynamoDB
    participant Chime as Chime Phone<br/>(SIP Rule → SMA)
    participant SL as SMA Lambda
    participant VC as Voice Connector
    participant Vapi as Vapi AI

    Caller->>Connect: Calls Connect phone number
    Connect->>Connect: Contact flow sets attributes<br/>(e.g. CustomerName)
    Connect->>CL: Invoke Lambda
    CL->>DDB: Store attributes keyed by caller number
    CL-->>Connect: OK
    Connect->>Chime: Transfer to Chime phone number
    Chime->>SL: NEW_INBOUND_CALL
    SL->>DDB: Query attributes by caller number
    DDB-->>SL: {CustomerName: "John"}
    SL-->>Chime: CallAndBridge with SipHeaders:<br/>x-customername: John
    Chime->>VC: SIP INVITE
    VC->>Vapi: SIP INVITE to<br/>sip:user@{id}.sip.vapi.ai
    Vapi-->>VC: 200 OK
    Vapi->>Caller: AI assistant answers
Loading

AWS Resources Overview

graph LR
    subgraph Amazon Connect
        CF[Contact Flow]
        CPN[Connect Phone Number]
    end

    subgraph Lambda
        CL[Connect Lambda<br/>stores metadata]
        SL[SMA Lambda<br/>CallAndBridge + headers]
    end

    subgraph Chime SDK
        VC[Voice Connector<br/>origination → Vapi]
        SMA[SIP Media Application]
        SR[SIP Rule]
        CP[Chime Phone Number]
    end

    subgraph Storage
        DDB[(DynamoDB<br/>call metadata)]
    end

    subgraph Vapi
        VSIP[SIP Credential<br/>+ Phone Number]
        VA[AI Assistant]
    end

    CPN --> CF
    CF --> CL
    CL --> DDB
    CF --> CP
    CP --> SR
    SR --> SMA
    SMA --> SL
    SL --> DDB
    SL --> VC
    VC --> VSIP
    VSIP --> VA
Loading

Prerequisites

  • AWS Account with CLI access configured
  • Amazon Connect instance with a claimed phone number
  • Vapi account with an AI assistant created
  • AWS CLI v2 installed

Part 1: AWS Setup

1.1 Create a Voice Connector

In the AWS Console or via CLI:

aws chime-sdk-voice create-voice-connector \
  --name "Vapi SIP Trunk" \
  --aws-region us-west-2 \
  --require-encryption false

Save the VoiceConnectorId from the response. You'll need it for config.env.

Why require-encryption: false? Vapi's SIP endpoint accepts unencrypted UDP on port 5060. If your security requirements demand TLS/SRTP, you'll need to coordinate with Vapi support.

1.2 Get the Voice Connector's Outbound IPs

You need these IPs to whitelist in Vapi. The Voice Connector has a DNS hostname:

# Replace with your Voice Connector ID
dig +short YOUR_VC_ID.voiceconnector.chime.aws

This returns a set of IPs (typically in a /24 range, e.g. 99.77.253.0/24). Note these for the Vapi setup.

1.3 Configure and Deploy

Create config.env:

# Required
AWS_REGION=us-west-2
VOICE_CONNECTOR_ID=your-voice-connector-id

# The user part of your Vapi SIP URI
# If your Vapi SIP URI is sip:myuser@abc123.sip.vapi.ai, set this to "myuser"
VAPI_SIP_URI_USER=myuser

# Optional
AWS_ACCOUNT_ID=          # auto-detected if blank
CALL_TIMEOUT_SECONDS=30
AREA_CODE=503            # area code for the Chime phone number

Run the deployment script:

chmod +x deploy.sh
./deploy.sh

This creates all AWS resources in order:

Step Resource Purpose
1 IAM Role Lambda execution role with CloudWatch + DynamoDB permissions
1b DynamoDB Table Stores call metadata between Connect Lambda and SMA Lambda
2 SMA Lambda Handles CallAndBridge to route calls through Voice Connector
3 Connect Lambda Stores contact attributes from Connect flow in DynamoDB
4 VC Origination Points Voice Connector at your Vapi SIP endpoint
5 VC Termination Enables inbound SIP signaling on the Voice Connector
6 SIP Media Application Links the SMA Lambda to Chime call processing
7 Chime Phone Number The number Connect will transfer calls to
8 SIP Rule Routes calls to the Chime phone number through the SMA

The script is idempotent -- safe to run multiple times.

1.4 Voice Connector Origination

The deploy script configures this automatically, but for reference, the origination route points to your Vapi SIP endpoint:

{
  "Routes": [{
    "Host": "<credential-id>.sip.vapi.ai",
    "Port": 5060,
    "Protocol": "UDP",
    "Priority": 1,
    "Weight": 1
  }],
  "Disabled": false
}

Important: The Host must match the Vapi credential domain. If your Vapi SIP URI is sip:user@abc123.sip.vapi.ai, the host is abc123.sip.vapi.ai. Update the origination route in deploy.sh accordingly.

1.5 Associate Lambda with Connect

The Connect Lambda must be associated with your Connect instance:

aws connect associate-lambda-function \
  --instance-id YOUR_CONNECT_INSTANCE_ID \
  --function-arn arn:aws:lambda:us-west-2:ACCOUNT:function:chime-connect-metadata-handler

1.6 Amazon Connect Contact Flow

An example contact flow is included at contact-flow.json. Before importing, replace these placeholders:

  • REPLACE_WITH_CONNECT_LAMBDA_ARN -- the ARN of the Connect Lambda (chime-connect-metadata-handler) from the deploy output
  • REPLACE_WITH_CHIME_PHONE_NUMBER -- the Chime phone number from the deploy output (e.g. +15035551234)

To import:

  1. Open the Amazon Connect console → Contact flows
  2. Create a new contact flow → click the dropdown arrow next to SaveImport flow
  3. Select contact-flow.json
  4. Update the Lambda ARN and phone number placeholders in the blocks
  5. Save and publish
graph LR
    A[Set Contact<br/>Attributes] --> B[Invoke<br/>Lambda]
    B --> C[Transfer to<br/>Phone Number]
    C -->|Error| D[Play Error<br/>Message]
    D --> E[Disconnect]
    C -->|Success| E
Loading

Block details:

  1. Set contact attributes -- Set any key/value pairs you want forwarded to Vapi:

    • CustomerName = "John"
    • AccountId = "12345"
    • Language = "en"
  2. Invoke AWS Lambda function -- Select the Connect Lambda (chime-connect-metadata-handler). This stores the attributes in DynamoDB.

  3. Transfer to phone number -- Enter the Chime phone number from the deploy output (e.g. +15035551234). Set ThirdPartyConnectionTimeLimitSeconds to 30.

  4. Error handling -- Play an error message and disconnect if the transfer fails.

Associate your Connect phone number with this flow.

Part 2: Vapi Setup

2.1 Create a SIP Trunk Credential

Create a BYO SIP trunk credential in Vapi. The gateway IPs are the Voice Connector's outbound IPs you found in step 1.2. These tell Vapi which IPs to expect inbound SIP traffic from.

curl -X POST https://api.vapi.ai/credential \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_VAPI_API_KEY" \
  -d '{
    "provider": "byo-sip-trunk",
    "name": "Amazon Chime Voice Connector",
    "gateways": [
      {"ip": "99.77.253.57", "inboundEnabled": true},
      {"ip": "99.77.253.24", "inboundEnabled": true},
      {"ip": "99.77.253.36", "inboundEnabled": true}
    ]
  }'

Save the returned id -- this is your credential ID. Your Vapi SIP endpoint becomes:

sip:<user>@<credential-id>.sip.vapi.ai

Note on IP whitelisting: The Voice Connector resolves to many IPs. You need to whitelist all of them as gateways. Run dig +short YOUR_VC_ID.voiceconnector.chime.aws to get all current IPs. Whitelisting by domain name is not yet supported by Vapi at the time of writing. Failing to whitelist all signaling IPs will result in 401 Unauthorized errors on inbound calls.

2.2 Create a Vapi Phone Number

Associate a phone number with the SIP trunk credential and link it to your Vapi assistant:

curl -X POST https://api.vapi.ai/phone-number \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_VAPI_API_KEY" \
  -d '{
    "provider": "byo-phone-number",
    "name": "Chime Inbound",
    "number": "myuser",
    "numberE164CheckEnabled": false,
    "credentialId": "YOUR_CREDENTIAL_ID",
    "assistantId": "YOUR_ASSISTANT_ID"
  }'

The number field must match VAPI_SIP_URI_USER in your config.env -- this is the user part of the SIP URI that the Voice Connector sends (e.g. sip:myuser@<credential-id>.sip.vapi.ai). Set numberE164CheckEnabled to false since this is a SIP URI user, not an E.164 phone number.

2.3 Update Voice Connector Origination Host

Make sure the Voice Connector origination host matches the credential-specific domain:

aws chime-sdk-voice put-voice-connector-origination \
  --voice-connector-id YOUR_VC_ID \
  --origination '{
    "Routes": [{
      "Host": "<credential-id>.sip.vapi.ai",
      "Port": 5060,
      "Protocol": "UDP",
      "Priority": 1,
      "Weight": 1
    }],
    "Disabled": false
  }'

Part 3: Passing Variables via SIP Headers

The key value of this integration is passing context from Amazon Connect to Vapi through custom SIP headers. Here's how the data flows:

graph TD
    A["Connect Flow<br/>Set Attributes:<br/>CustomerName=John<br/>AccountId=12345"] -->|Invoke Lambda| B["Connect Lambda<br/>Stores in DynamoDB:<br/>{CustomerName: John,<br/>AccountId: 12345}"]
    B --> C["Connect transfers to<br/>Chime Phone Number"]
    C -->|SIP Rule + SMA| D["SMA Lambda<br/>Reads DynamoDB<br/>Builds SipHeaders"]
    D -->|"CallAndBridge<br/>SipHeaders:<br/>x-customername: John<br/>x-accountid: 12345"| E["Voice Connector"]
    E -->|"SIP INVITE with<br/>x-customername: John<br/>x-accountid: 12345"| F["Vapi AI Assistant"]
Loading

How It Works

Step 1: Connect flow sets contact attributes

In the contact flow, use the "Set contact attributes" block to define key-value pairs. These can be static values or dynamic references (e.g. from a CRM lookup, Lex bot, or customer input).

Step 2: Connect Lambda stores attributes in DynamoDB

The Connect Lambda (connect-handler.mjs) receives all contact attributes and stores them in DynamoDB, keyed by the caller's phone number with a 5-minute TTL:

// connect-handler.mjs (simplified)
const attributes = event.Details.ContactData.Attributes; // {CustomerName: "John", ...}
await ddb.send(new PutItemCommand({
  TableName: TABLE_NAME,
  Item: {
    CallerNumber: { S: callerNumber },
    Timestamp: { N: String(Date.now()) },
    Attributes: { S: JSON.stringify(attributes) },
    TTL: { N: String(Math.floor(Date.now() / 1000) + 300) },
  },
}));

Step 3: SMA Lambda reads attributes and sets SIP headers

When the call arrives at the SMA, the Lambda (index.mjs) queries DynamoDB by caller number, builds x- prefixed SIP headers, and includes them in the CallAndBridge action:

// index.mjs (simplified)
const metadata = await getMetadata(callFrom); // {CustomerName: "John", AccountId: "12345"}

const sipHeaders = {};
for (const [key, value] of Object.entries(metadata)) {
  sipHeaders[`x-${key.toLowerCase()}`] = String(value);
}
// sipHeaders = {"x-customername": "John", "x-accountid": "12345"}

return {
  SchemaVersion: "1.0",
  Actions: [{
    Type: "CallAndBridge",
    Parameters: {
      CallTimeoutSeconds: 30,
      CallerIdNumber: callFrom,
      Endpoints: [{
        BridgeEndpointType: "AWS",
        Arn: VOICE_CONNECTOR_ARN,
        Uri: VAPI_SIP_URI_USER,
      }],
      SipHeaders: sipHeaders,
    },
  }],
};

SIP Header Rules

Per AWS documentation:

  • Custom headers must use the x- prefix (lowercase)
  • The prefix x-amzn is reserved and will cause an error
  • Header values are limited to 2048 characters
  • The User-to-User and Diversion standard headers are also supported

Accessing Headers in Vapi

On the Vapi side, the SIP headers arrive with the inbound call. You can access them in your Vapi assistant's server URL webhook, tool calls, or assistant configuration to personalize the AI conversation based on the caller's context.

Part 4: Testing

Make a Test Call

  1. Call your Amazon Connect phone number
  2. The flow sets attributes, invokes the Lambda, then transfers to the Chime number
  3. The SMA Lambda bridges the call to Vapi with SIP headers
  4. Your Vapi assistant answers

Check Logs

Monitor each stage in CloudWatch:

# Connect Lambda (stores metadata)
aws logs tail /aws/lambda/chime-connect-metadata-handler --follow

# SMA Lambda (CallAndBridge)
aws logs tail /aws/lambda/chime-sma-vapi-handler --follow

Enable SIP Message Logging

To see the actual SIP INVITE and responses:

aws chime-sdk-voice put-voice-connector-logging-configuration \
  --voice-connector-id YOUR_VC_ID \
  --logging-configuration EnableSIPLogs=true

# After a test call, check logs:
aws logs filter-log-events \
  --log-group-name "/aws/ChimeVoiceConnectorSipMessages/YOUR_VC_ID" \
  --start-time $(date -v-10M +%s000)

Common Issues

Symptom Cause Fix
CallRejected in Lambda logs Vapi doesn't recognize the SIP URI Verify VAPI_SIP_URI_USER matches the Vapi phone number's sipUri user part
CallRejected instantly Voice Connector IPs not whitelisted in Vapi Run dig +short YOUR_VC_ID.voiceconnector.chime.aws and add all IPs to the Vapi credential
No metadata in SIP headers Connect Lambda not invoked before transfer Ensure the contact flow invokes the Lambda before the transfer block
Call stays open after hangup SMA Lambda not handling HANGUP event Return a Hangup action for HANGUP and ACTION_FAILED events
InvalidActionParameter Reserved SIP header name used Don't use x-amzn prefix; use x- with your own naming

Part 5: Cleanup

To tear down all created resources:

chmod +x cleanup.sh
./cleanup.sh

This removes (in reverse order): SIP Rule, SMA, Chime phone number, Voice Connector config, Lambda functions, DynamoDB table, and IAM role. The Voice Connector itself is not deleted.

File Structure

amazon-chime-sip-calls/
├── config.env.example       # Configuration template (copy to config.env)
├── deploy.sh                # Creates all AWS resources
├── cleanup.sh               # Tears down all resources
├── contact-flow.json        # Example Amazon Connect contact flow (importable)
├── lambda/
│   ├── index.mjs            # SMA Lambda (CallAndBridge + SIP headers)
│   └── connect-handler.mjs  # Connect Lambda (stores metadata in DynamoDB)
└── README.md                # This file

References

About

Route inbound calls from Amazon Connect to a Vapi AI assistant via AWS Chime SDK Voice Connector and SIP trunking, with custom SIP headers for caller context

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Contributors 2

  •  
  •