WhatsApp

Many of your customers already use WhatsApp. For instance, a customer sends your business number "What is your return policy?", and the agent answers in the same WhatsApp chat. The whatsapp connector does this with your own Meta app.

Answer on WhatsApp

Add the whatsapp connector to your agent:

agents/support/agent.yaml
name: support
mode: text
llm: llm-fast
connectors:
  - name: whatsapp
    connection: acme-whatsapp # the label of your WhatsApp connection

You need five things from Meta: your app's ID and App Secret, your number's phone number ID, its WhatsApp account ID, and an access token. We recommend starting with Meta's test number. Setup takes six steps:

Create a Meta app

At developers.facebook.com, create an app with the use case Connect with customers through WhatsApp. The App ID and App Secret are under App settings > Basic. Under Use cases > Customize > Step 1. Try it out, copy the test number's Phone Number ID and Messaging account ID, and add your own phone as a Recipient.

Create a token that doesn't expire

At business.facebook.com, open Settings > Users > System users and add an Admin system user. Give it full control of your app and your WhatsApp account, then choose Generate token with Never as the expiration and the whatsapp_business_messaging and whatsapp_business_management permissions.

Save your Meta app

Give Stream the App ID and the App Secret:

curl -fsSL https://getstream.io/cli/beta/install.sh | bash # the agents commands are in the beta CLI
echo "$META_APP_SECRET" | getstream agents connectors client set whatsapp --provider-app-id "$META_APP_ID" --signing-secret -

The CLI prints Saved the provider app for whatsapp.

Connect the number

Create the connection with the phone number ID and the access token:

echo "$WHATSAPP_ACCESS_TOKEN" | getstream agents connections create whatsapp --label acme-whatsapp --input phone_number_id=$PHONE_NUMBER_ID --token -

The CLI prints Connected: whatsapp / acme-whatsapp, with the connection's id.

Point Meta at Stream

Warning:

Do it after steps 3 and 4: Meta checks the URL at once.

The verify token is your Meta app ID, and $WABA_ID is the Messaging account ID:

curl -X POST "https://graph.facebook.com/v25.0/$META_APP_ID/subscriptions" \
  --data-urlencode "access_token=$META_APP_ID|$META_APP_SECRET" \
  --data-urlencode "object=whatsapp_business_account" \
  --data-urlencode "callback_url=$STREAM_ACCELERATION_URL/v1/connectors/events/whatsapp/$META_APP_ID" \
  --data-urlencode "verify_token=$META_APP_ID" \
  --data-urlencode "fields=messages"

curl -X POST "https://graph.facebook.com/v25.0/$WABA_ID/subscribed_apps" \
  -H "Authorization: Bearer $WHATSAPP_ACCESS_TOKEN"

Both answer {"success": true}.

Sync the agent

getstream agents sync support

You can't start a chat with a test number from your phone, so send yourself Meta's hello_world first. Reply "What is your return policy?" in that chat, and the agent's answer comes back in the same chat.

In the Dashboard

Steps 3 and 4 work in the Dashboard too. In the Stream Dashboard, go to Agents > Library > Connectors and open WhatsApp.

  1. Click Set OAuth client. The dialog has two fields: fill Provider app ID with your Meta app ID and Signing secret with the App Secret, then click Save client.
  2. Click Create connection. Owner starts on Signed-in user: pick App. Type acme-whatsapp in Label, the phone number ID in phone_number_id and the access token in Token, then click Create connection. The connection's page opens, and the connection is connected.

Say hello from a test number

Put your own phone in to:

curl -X POST "https://graph.facebook.com/v25.0/$PHONE_NUMBER_ID/messages" \
  -H "Authorization: Bearer $WHATSAPP_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"messaging_product": "whatsapp", "to": "+12025550100", "type": "template", "template": {"name": "hello_world", "language": {"code": "en_US"}}}'

Send a photo

A photo reaches the agent. Send a photo with "What is in this photo?", and the agent answers about the photo. A photo with no caption works too.

If photos do not reach the agent, save the token again. Run the third call in With the API once more with your access token. Set expected_revision to the revision that GET $STREAM_ACCELERATION_URL/v1/agents/connections/$CONNECTION_ID returns.

Keywords

Stream handles these, not the agent:

  • HELP: Stream answers "Reply STOP to unsubscribe."
  • STOP: the person is opted out. Stream answers "You are unsubscribed and will receive no more messages. Reply START to resubscribe.", and the agent answers nothing more from them until they send START.
  • START: the person is opted back in. Stream answers "You are subscribed again. Reply STOP to unsubscribe."

Limitations

The agent replies only within 24 hours of the person's last message.

With the API

Your server can save your Meta app and create the connection instead of the CLI. $STREAM_ACCELERATION_URL is your router's URL, and $SERVER_TOKEN is a server token:

curl -X PUT "$STREAM_ACCELERATION_URL/v1/agents/connectors/whatsapp/oauth-client" \
  -H "api_key: $STREAM_API_KEY" -H "stream-auth-type: jwt" \
  -H "Authorization: Bearer $SERVER_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"provider_app_id": "<Meta app ID>", "signing_secret": "<App Secret>"}'

curl -X POST "$STREAM_ACCELERATION_URL/v1/agents/connections" \
  -H "api_key: $STREAM_API_KEY" -H "stream-auth-type: jwt" \
  -H "Authorization: Bearer $SERVER_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"connector_id": "whatsapp", "owner": {"type": "app"}, "label": "acme-whatsapp", "inputs": {"phone_number_id": "<phone number ID>"}}'

curl -X PUT "$STREAM_ACCELERATION_URL/v1/agents/connections/$CONNECTION_ID/credentials" \
  -H "api_key: $STREAM_API_KEY" -H "stream-auth-type: jwt" \
  -H "Authorization: Bearer $SERVER_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"expected_revision": 1, "values": {"token": "<access token>"}}'

$CONNECTION_ID is the id the second call returns. After the third call, the connection is connected.

When a message gets no answer

What you see Why What to do
WhatsApp says your test number is not on WhatsApp A test number can't be found in a search Send yourself hello_world
Meta answers (#133010) Account not registered The number isn't registered with Meta's API yet Register it, as below
A person gets no reply after STOP The person opted out The person sends START

To register a number, pick a six-digit PIN and keep it. It becomes the number's two-step verification PIN:

curl -X POST "https://graph.facebook.com/v25.0/$PHONE_NUMBER_ID/register" \
  -H "Authorization: Bearer $WHATSAPP_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"messaging_product": "whatsapp", "pin": "<six digits>"}'

Going further