Amazon Connect WhatsApp End User Messaging 18 min read

WhatsApp Business Integration
with Amazon Connect

Complete setup guide for connecting a WhatsApp Business Account (WABA) to Amazon Connect via AWS End User Messaging Social — including IAM configuration, phone number provisioning, CLI commands, and a full troubleshooting playbook.

Overview

AWS End User Messaging Social1 is the service that owns the connection between Meta's WhatsApp Cloud API and your AWS account. Amazon Connect acts as the destination for inbound messages — routing each WhatsApp conversation to an available agent through the Contact Control Panel (CCP) or Agent Workspace, exactly like a chat contact.

This guide walks through the full integration from a clean start, plus a troubleshooting section covering the most common failure modes encountered in real deployments.

SNS is not required. If you're using Amazon Connect as the destination, events go directly via connect:SendIntegrationEvent. An SNS topic is only needed if you want a parallel processing pipeline — which requires a different architecture. Each WABA supports only one event destination.

Prerequisites

Meta / WhatsApp side

  • Meta Business Portfolio (Business Manager account)
  • A phone number that can receive an SMS or voice OTP, and is not already registered to a WhatsApp account
  • Acceptance of WhatsApp Business Terms, Solution Terms, and Messaging Policy
  • Business Verification completed (strongly recommended before go-live — prevents auto-restriction)

AWS side

  • An Amazon Connect instance already created2
  • IAM permissions to create roles and policies
  • Access to AWS End User Messaging Social console (same region as your Connect instance)
  • AWS CLI configured with credentials for the account

How it works

When a customer sends a WhatsApp message to your business number, it travels through three layers before reaching an agent:

Customer's phone Sends a WhatsApp message to your registered number
Meta → AWS Social Messaging Meta delivers the webhook to AWS End User Messaging Social
connect:SendIntegrationEvent Social Messaging assumes your IAM role and calls Connect
Agent Workspace / CCP Contact flow routes to an available agent
One WABA, one destination. Every phone number on a given WABA funnels events to the same Amazon Connect instance. If you need different routing per number, use separate WABAs.

Setup

1

Link your WABA to AWS End User Messaging Social

Open the AWS End User Messaging Social console and run the Sign up with WhatsApp embedded flow.3 This is the only correct starting point — do not create the WABA in Meta Business Manager first and then try to import it.

In the embedded flow you will:

  1. Authorize AWS to act as the billing party for your WhatsApp messages
  2. Select or create your Meta Business Portfolio
  3. Select or create a WhatsApp Business Account (WABA)
  4. Select or create a WhatsApp Business Profile
  5. Add and verify your phone number via OTP (SMS or voice call)

Under the hood this calls AssociateWhatsAppBusinessAccount on your behalf. When the flow completes, the WABA appears in the console under WhatsApp Business accounts with status COMPLETE.

Do not choose "Use a display name only." Meta does not support connecting their internally-generated virtual numbers to third-party Cloud API providers via the setup finalization handshake. The association will fail with a DependencyException on every attempt. Always choose Add a new number or choose an existing Registered number.
2

Create the IAM role

You need a customer-managed IAM role that AWS End User Messaging Social can assume to deliver events to Connect and import your phone number. This is a single dual-purpose role — do not create separate roles for delivery and import.

Permission policy — attach this to the role:

IAM Permission Policy
JSON
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "AllowOperationsForEventDelivery",
      "Effect": "Allow",
      "Action": ["connect:SendIntegrationEvent"],
      "Resource": "*"
    },
    {
      "Sid": "AllowOperationsForPhoneNumberImport",
      "Effect": "Allow",
      "Action": [
        "connect:ImportPhoneNumber",
        "social-messaging:GetLinkedWhatsAppBusinessAccountPhoneNumber",
        "social-messaging:TagResource"
      ],
      "Resource": "*"
    }
  ]
}

Trust policy — allows social-messaging.amazonaws.com to assume the role:

IAM Trust Policy
JSON
{
  "Version": "2012-10-17",
  "Statement": [{
    "Effect": "Allow",
    "Principal": {
      "Service": ["social-messaging.amazonaws.com"]
    },
    "Action": "sts:AssumeRole"
  }]
}
No Condition blocks in the trust policy. Any condition — even a well-intentioned aws:SourceAccount — can silently block the service from assuming the role, causing zero SendIntegrationEvent events with no obvious error. See trust policy troubleshooting.

Name the role whatever you'd like. The resulting role ARN will be in this format:

Example role ARN
arn:aws:iam::123456789012:role/EndUserMessagingSocialWABAConnectDestination

Note the single path segment after role/. The API regex rejects service-linked role ARNs, which have a multi-segment path. See wrong role troubleshooting if you hit a 400 error.

3

Set Amazon Connect as the event destination

In the Social Messaging console → WhatsApp Business accounts → select your WABA → Event destination tab:4

  1. Click Edit destination
  2. Toggle the destination to Enable
  3. Set Destination type to Amazon Connect
  4. Select your Connect instance from the dropdown
  5. Under Two-way channel role, select Choose Existing Role and in the dropdown, select the custom role you created in Step 2
  6. Click Save changes

Saving the event destination triggers ImportPhoneNumber, which pushes the WhatsApp number into your Connect instance.

4

Import the phone number into Connect

After saving the destination, confirm the import completed via CLI:

Verify and trigger phone number import
bash
# 1. Find the Social Messaging phone number ARN
aws socialmessaging list-linked-whatsapp-business-accounts --region <region>

aws socialmessaging get-linked-whatsapp-business-account \
  --id waba-<your-waba-id> \
  --region <region>
# Note the phoneNumbers[].arn value

# 2. If the import didn't fire automatically, run it manually
WHATSAPP_NUMBER_ID=$(aws connect import-phone-number \
  --instance-id <your-connect-instance-id> \
  --source-phone-number-arn "<social-messaging-phone-arn>" \
  --phone-number-description "WhatsApp WABA" \
  --region <region> \
  --query 'PhoneNumberId' \
  --output text)

echo "Phone Number ID: $WHATSAPP_NUMBER_ID"

# 3. Check import status
aws connect describe-phone-number \
  --phone-number-id $WHATSAPP_NUMBER_ID \
  --region <region>
You won't be able to use an Amazon Connect DID for both voice and WhatsApp. If you used an existing Connect voice number to receive the OTP, you must release the phone number from Amazon Connect before importing it as a WhatsApp channel. Otherwise, the integration will be incomplete, and WhatsApp messages sent to that phone number will not reach Amazon Connect.

aws connect release-phone-number --phone-number-id <old-phone-number-id> --region <region>

Then re-run import-phone-number. The number is not lost — it comes back as a WhatsApp channel. If you need voice capability, this can be configured separately in WhatsApp Manager > Phone Numbers > Call Settings.9
5

Attach a contact flow

The imported number needs an inbound contact flow to route messages — without one, contacts arrive and are dropped silently.

Attach contact flow
bash
# Find your contact flow ID
aws connect list-contact-flows \
  --instance-id <your-connect-instance-id> \
  --region <region>

# Attach the flow to the WhatsApp number
aws connect associate-phone-number-contact-flow \
  --instance-id <your-connect-instance-id> \
  --phone-number-id $WHATSAPP_NUMBER_ID \
  --contact-flow-id <your-flow-id> \
  --region <region>

Alternatively, do this in the Connect console: Channels → Phone numbers → select the WhatsApp number → Edit → Flow/IVR → pick your inbound flow. The number should show WhatsApp in the Active Channels column.

If the flow handles both voice and chat, add a Check Contact Attributes block checking segment attribute Subtype == connect:WhatsApp to route WhatsApp contacts separately from voice.
6

Verify end-to-end

  1. Open the Agent Workspace (or CCP) in Connect and set your status to Available
  2. Send a plain text "hi" from a personal phone to your registered WhatsApp number
  3. The contact should appear as a chat in the Agent Workspace
  4. Confirm in CloudTrail: look for a connect:SendIntegrationEvent event — its presence means the full pipeline is working

Phone number options

10DLC and toll-free SMS registration are not required for WhatsApp — those are US carrier compliance requirements for SMS, which WhatsApp bypasses entirely. The only requirement is that the number can receive one OTP during Meta's verification step.5

Source Best for Notes
Amazon Connect voice DID Most deployments Claim a new number in Connect. No registration paperwork for voice numbers. Release the voice claim before importing as WhatsApp.
AWS End User Messaging SMS number If you already have one Works, but requires 10DLC/toll-free registration for SMS use. Wasted overhead if you're only using it for the OTP.
External number (mobile, landline, other DID) Migrating an existing business number Any number that can receive an SMS or voice call works. Simplest path if you already have a business number.
Once a number is registered with WhatsApp it cannot reliably be used for its original voice/SMS purpose. If you need both voice and WhatsApp, claim two separate numbers.

Customer entry points

Customers can send a WhatsApp message directly to your business number — but don't ask them to type it manually. Publish one of these instead:

wa.me click-to-chat link

https://wa.me/15551234567

Tapping the link on a phone opens a pre-populated WhatsApp chat. Add ?text=Hello to pre-fill the first message. Use on websites, email signatures, and receipts.

QR codes

Generated in Meta Business Manager under WhatsApp Account settings. Scanning opens the same wa.me flow. Good for physical locations, packaging, and business cards.

Click-to-WhatsApp ads

Facebook/Instagram ads with a "Send Message" CTA that drops the user into a WhatsApp chat. Configured in Meta Ads Manager.

24-hour service window. Once a customer messages you, you have a rolling 24-hour window to reply with freeform text. After 24 hours of silence you can only re-engage with a pre-approved message template sent via the SendWhatsAppMessage API.

What message types are supported inbound?6

Message typeStatus
Plain text (≤ 1,024 chars)Supported
Images, documents, audio, video (≤ 20 MB) — after contact opensSupported
Interactive message responses (button/list taps)Supported
Text > 1,024 charactersDropped
Attachment as first message (before text)Dropped
Attachment > 20 MBDropped
StickersDropped
Location pin/shareDropped
Contact cards (vCard)Dropped
Emoji reactionsDropped
Threaded reply (quote-reply) — quoted context is strippedPartial

Troubleshooting

When messages aren't appearing, CloudTrail is your first stop. Two events tell you which leg is failing:

  • connect:SendIntegrationEvent — Social Messaging calling Connect when an inbound WhatsApp message arrives. Not present = problem is on the Social/WABA side. AccessDeniedException = IAM role misconfigured.
  • connect:SendChatIntegrationEvent — subsequent events on an existing chat contact.

No SendIntegrationEvent in CloudTrail

If SendIntegrationEvent never fires, Social Messaging either isn't receiving the message from Meta, or can't resolve the phone number. Work through these in order:

1
Confirm event destination is enabled
Social Messaging console → WABA → Event destination tab. Verify status is Enabled, type = Amazon Connect, correct instance, and role ARN is populated.
2
Verify the phone number is on the AWS-controlled WABA
In Meta Business Manager → WhatsApp Accounts, confirm the WABA linked to AWS owns the phone number. Numbers registered under a different WABA (e.g. a marketing WABA) will not route inbound to AWS.
3
Check the WABA's webhook subscription
Meta Business Manager → WhatsApp Accounts → select WABA → Settings → Webhooks / Subscribed Apps. The subscribed app must be the AWS-controlled one. Under Webhook fields, messages must be checked.
4
Check if the WABA is in test/unverified state
If not yet Business Verified, only phone numbers added to the allowed test recipients list in Meta can message in. Add the test number or complete Business Verification.
5
Test with a plain text message
Attachments, stickers, locations, reactions, and emoji-first messages are filtered by Social Messaging before forwarding — none produce a SendIntegrationEvent. Always test with a plain-text "hi" as the very first message.

ResourceNotFoundException: "Origination phone number id not found"

This error from GetLinkedWhatsAppBusinessAccountPhoneNumber means Connect holds a phone-number-id that no longer exists in Social Messaging. The number shows "Active, WhatsApp" in Connect but points at a ghost record.

Most likely causes:

  • The phone number was removed and re-added on the Social side after Connect imported it — the phone-number-id changed but Connect still holds the old one.
  • Cross-account drift — the IAM role belongs to an account where the phone number ID doesn't exist.
  • You have two WABAs; the event destination was set on WABA A but the number being tested belongs to WABA B.

Diagnosis:

Compare phone number IDs
bash
# What Social actually knows
aws socialmessaging list-linked-whatsapp-business-accounts --region <region>
aws socialmessaging get-linked-whatsapp-business-account \
  --id <waba-id> --region <region>
# Note phoneNumbers[].phoneNumberId

# What Connect holds
aws connect list-phone-numbers-v2 \
  --instance-id <connect-instance-id> --region <region>
# Check SourcePhoneNumberArn — phone-number-id is embedded

Fix: Release the number from Connect, then re-save the event destination in the Social console to re-trigger ImportPhoneNumber with the current ID. Re-attach the contact flow.

DependencyException: "Error while communicating with Meta"

AssociateWhatsAppBusinessAccount has two phases. Phase 1 (OAuth handshake) almost always succeeds. Phase 2 (setupFinalization) fails with a 502 from Meta for several reasons:

  • Using a Meta-generated virtual number — Meta does not support connecting their virtual numbers to third-party Cloud API providers. Switch to Add a new number and provide a real phone number.
  • WABA in a bad state from prior restriction or billing history — repeated failed attempts make this worse. Stop retrying and open an AWS Support ticket with the RequestID from the most recent DependencyException.
  • Rate limiting — more than ~40 AssociateWhatsAppBusinessAccount calls in a day triggers Meta's abuse detection. Stop all attempts and wait before retrying.
Every failed retry of AssociateWhatsAppBusinessAccount deepens Meta's rate limit window for this WABA. If you're hitting consistent DependencyExceptions after checking all other causes, stop retrying and escalate to AWS Support.

Messages not arriving despite everything looking correct

If the WABA is COMPLETE, the event destination is enabled, and the phone number is imported — but SendIntegrationEvent never fires — check for a Condition block in the IAM role's trust policy.

A condition that looks valid (e.g., aws:SourceAccount) can silently block sts:AssumeRole calls from social-messaging.amazonaws.com. The trust policy should be exactly:

Correct trust policy (no conditions)
JSON
{
  "Version": "2012-10-17",
  "Statement": [{
    "Effect": "Allow",
    "Principal": { "Service": "social-messaging.amazonaws.com" },
    "Action": "sts:AssumeRole"
  }]
}

No conditions. If you added any, remove them and wait a few minutes for the policy to propagate.

WABA is Account Restricted

A restricted WABA blocks all three things needed for the integration: initiating conversations, responding to messages, and adding phone numbers. This is a Meta enforcement action — no AWS config change can unblock it.

Immediate restriction at account creation (with zero activity) is caused by the Business Portfolio's trust score, not a policy violation. Common triggers:

  • The Business Portfolio has prior enforcement history from any associated asset (ad accounts, pages, apps)
  • The admin's personal Facebook account is new, thin, or previously flagged
  • The selected business category falls into a high-risk group (finance, healthcare, legal, real estate)
  • No Business Verification, no verified domain, no ad spend history on the Portfolio
  • Account created from an IP Meta associates with fraud or VPN traffic

What to do:

  1. Check Meta Business Manager → Account quality — if there is a "Request Review" button, submit an appeal with business documentation. This works even for "permanent" restrictions.
  2. Complete Business Verification: Meta Business Manager → Business Settings → Security Center → Start Verification.
  3. Verify your domain under Brand Safety → Domains.
  4. If the Portfolio itself is irrecoverable, create a new one under a clean, established Facebook admin account. A new WABA under a flagged Portfolio will be immediately restricted again.

Billing currency error: "WABA was previously billed in a currency other than USD"

AWS End User Messaging Social invoices in USD and pays Meta. Meta only allows a WABA's billing currency to be set once. If this WABA previously had messages billed in a non-USD currency through any provider, the currency is locked and AWS cannot assume billing.

There is no fix — Meta does not expose a "change billing currency" operation. Options:

  • Create a brand new WABA under the same Business Portfolio, do not send any messages through another platform first, then link it to AWS. A fresh WABA will have its currency set to USD when AWS links it.
  • Move the phone number to the new WABA in Meta Business Manager before linking to AWS, so customers keep the same number. Meta requires the number to be unregistered from the old WABA first.
If Business Verification was completed on the old WABA, the new one will require verification again (up to 2 weeks). Plan the cutover so the new WABA is verified before releasing the number from the old one to minimize downtime.

400 error: "Value at roleArn failed to satisfy constraint"

This 400 validation error occurs when the service-linked role AWSServiceRoleForSocialMessaging is passed as the event destination role ARN. Service-linked roles have a multi-segment path (role/aws-service-role/...) that fails the API regex, which requires a single-segment path.

The two roles serve completely different purposes:

  • AWSServiceRoleForSocialMessaging — auto-created by AWS for its own internal operations (WABA linking, Meta sign-up plumbing). You cannot and should not use it as a delivery role.
  • Event destination role — a customer-managed role you create (Step 2 above) that Social Messaging assumes to call connect:SendIntegrationEvent.

Fix: If you haven't already, create the customer-managed role from Step 2 and switch to Enter IAM role ARN in the console instead of using the dropdown.

Display name changed — number needs to be re-registered

After a WABA display name change is approved by Meta, you may see the following message in the AWS End User Messaging Social console or WhatsApp Manager:

"The new display name has been approved. Register your number to start using it."

Re-importing the phone number alone is not sufficient. Meta requires the phone number to be fully re-registered under the new display name, which means a complete unlink and re-link cycle through the embedded sign-up flow.

  1. In the AWS End User Messaging Social console, disassociate (unlink) the WABA.
  2. Click Link WABA and go through the embedded sign-up flow again. Pay close attention to select the exact same Business Profile, same WABA name, and the registered phone number — do not create new resources or choose a different number.
  3. Once the WABA is re-linked, release the phone number from Amazon Connect.
  4. Re-import the phone number using import-phone-number (see Step 6 above).
  5. Re-attach the contact flow to the newly imported number.

Once the import completes successfully, the updated display name will be reflected in both WhatsApp Manager and the AWS End User Messaging Social console.

ImportPhoneNumber fails: phone number quota exceeded

Amazon Connect enforces a default limit of 5 phone numbers per instance.7 When this limit is reached, ImportPhoneNumber will fail. This typically affects numbers that are not already present in your Connect phone number list, or numbers listed as Display Only. If the WhatsApp number already appears in your Connect phone number list (for example, previously claimed as a voice DID), releasing it first and then re-importing it as a WhatsApp channel works fine — releasing frees the slot before the import reclaims it. You may also see this error the very first time you claim a number if the instance has a pre-existing restriction, in which case only AWS Support can resolve it.

Display Only numbers cannot be imported into Amazon Connect. If the WhatsApp number in your Social Messaging console is listed as Display Only, it is not eligible for ImportPhoneNumber regardless of your quota. You must register a real phone number through the embedded sign-up flow to use the Connect integration.

How to check your current usage:

List claimed phone numbers in your instance
bash
aws connect list-phone-numbers-v2 \
  --instance-id <connect-instance-id> \
  --region <region> \
  --query 'length(ListPhoneNumbersSummaryList)' \
  --output text

Options to resolve:

  • Release an unused number — if you have numbers in Connect that are no longer in use, release one to free up the slot:
    aws connect release-phone-number --phone-number-id <id> --region <region>
  • Request a quota increase — open the Service Quotas console or use the AWS CLI to request a higher limit for your Connect instance.8 This is a resource-level quota, so the increase applies to the specific instance ARN:
Request phone number quota increase via CLI
bash
# Find the quota code for "Phone numbers per instance"
aws service-quotas list-service-quotas \
  --service-code connect \
  --region <region> \
  --query 'Quotas[?contains(QuotaName, `Phone number`)].[QuotaName,QuotaCode,Value]' \
  --output table

# Request an increase (replace quota-code and desired-value)
aws service-quotas request-service-quota-increase \
  --service-code connect \
  --quota-code <quota-code> \
  --desired-value 10 \
  --region <region>
You can also request a quota increase from the Service Quotas console: Service Quotas → AWS services → Amazon Connect → Phone numbers per instance → Request quota increase. Quota increase requests are typically reviewed within 1–2 business days.

CLI reference

All commands use the account and region where both your Connect instance and WABA live. Substitute your own IDs — the values below are illustrative.

Inspect the Social Messaging side

List WABAs and phone number ARNs
bash
aws socialmessaging list-linked-whatsapp-business-accounts --region <region>

aws socialmessaging get-linked-whatsapp-business-account \
  --id waba-<your-waba-id> \
  --region <region>

Inspect the Connect side

List phone numbers in Connect
bash
aws connect list-phone-numbers-v2 \
  --instance-id <connect-instance-id> \
  --region <region>

Full release + re-import sequence

Release voice DID, import as WhatsApp, attach flow
bash
# Release the existing voice claim
aws connect release-phone-number \
  --phone-number-id <old-voice-phone-number-id> \
  --region <region>

# Import the WhatsApp number — capture the returned PhoneNumberId
WHATSAPP_NUMBER_ID=$(aws connect import-phone-number \
  --instance-id <connect-instance-id> \
  --source-phone-number-arn "<social-messaging-phone-arn>" \
  --phone-number-description "WhatsApp WABA" \
  --region <region> \
  --query 'PhoneNumberId' \
  --output text)

# Confirm CLAIMED status
aws connect describe-phone-number \
  --phone-number-id $WHATSAPP_NUMBER_ID \
  --region <region>

# Attach the inbound contact flow
aws connect associate-phone-number-contact-flow \
  --instance-id <connect-instance-id> \
  --phone-number-id $WHATSAPP_NUMBER_ID \
  --contact-flow-id <contact-flow-id> \
  --region <region>

Finding your IDs

ValueHow to find it
--instance-id Connect console → instance ARN, or aws connect list-instances
WABA ID aws socialmessaging list-linked-whatsapp-business-accounts
--source-phone-number-arn get-linked-whatsapp-business-accountphoneNumbers[].arn
--phone-number-id (release) aws connect list-phone-numbers-v2PhoneNumberId
--phone-number-id (describe/associate) Returned by import-phone-numberPhoneNumberId
--contact-flow-id aws connect list-contact-flows --instance-id <id>