Skip to content

There are two ways to connect WhatsApp:

AdapterBest forPublic URL neededNotes
WhatsApp (Meta Cloud API)Production business numbersYes (webhook callback)Official, supported by Meta. Requires a Meta Business account.
WhatsApp (Personal account)Personal use, testingNo (QR pairing)Unofficial. ⚠ Risk of account ban: see below.

If you have a WhatsApp Business number and Meta Business access, use Cloud API. If you want to wire up your personal phone, use the Personal adapter.

Option 1: WhatsApp Cloud API

This is the official Meta-supported path. Messages are delivered to Frona via webhook from Meta's servers.

What you need

  • A Meta for Developers account
  • A verified Meta Business account
  • A WhatsApp Business app set up in Meta for Developers with at least one Phone Number ID
  • A publicly reachable URL for the engine. See server.external_url. For local development, ngrok works.

Setting up the Meta app

  1. In Meta for Developers, open your WhatsApp Business app (or create one).
  2. Go to WhatsApp → API Setup. Note the Phone Number ID and WhatsApp Business Account ID.
  3. Generate a System User access token in Business Settings → System Users with the whatsapp_business_messaging scope. (The temporary token shown on the API Setup page works for testing but expires in 24 hours.)
  4. From the app's Settings → Basic page, copy the App Secret.
  5. Pick any random string to serve as the Verify Token. You'll paste the same value in two places (Frona and Meta).

Connecting the channel

Connection happens in three stages. A short dialog creates the channel, then you fill in the Meta IDs and secrets on the detail page, then you wire the webhook URL in the Meta dashboard.

Step 1: Create the channel

  1. In Frona, open Settings → Channels and click Add channel.
  2. Pick WhatsApp (Meta Cloud API) from the provider list. The create dialog opens.
  3. Fill in the dialog:
    • Space. Defaults to WhatsApp (Meta Cloud API). This is the space the conversation will live in. Keep the default to create a new space with that name, type any other name to create a different one, or pick an existing space from the dropdown. A space can host only one channel, so spaces already bound to another channel are hidden.
    • Agent. The agent that reads every incoming message and sends the reply.
    • When a message arrives. How inbound messages are handled:
      • Treat as a message from you (default). The agent runs full inference and replies.
      • Hand off to a waiting agent. The message goes to whichever task is currently waiting on a signal (e.g., a 2FA code). The agent does not reply on this channel. See Signals.
  4. Click Create.

You land on the channel detail page. The status is Setup until the config is filled in.

Step 2: Configure the channel

Open the Config tab on the channel detail page. The Provider Config panel lists five fields.

The two non-secret IDs are text inputs. Type the values you noted from Meta:

  • phone_number_id
  • business_account_id

The three secrets are set via Frona's credential picker. For each one (access_token, verify_token, app_secret):

  1. Click Configure.
  2. Pick a vault connection. You can use a configured password manager (1Password, Bitwarden, HashiCorp Vault, KeePass) or Local to keep the secret in Frona's encrypted store.
  3. Either pick an existing vault item, or click New credential to create one. For Local, choose API key, name it, and paste the value.
  4. Pick the field on the item that holds the value.
  5. Click Save in the dialog.

When all five fields are populated, click Save at the top of the channel page. A Webhook URL now appears.

Step 3: Wire the webhook in Meta

  1. Copy the Webhook URL from the channel page.
  2. In Meta for Developers, go to WhatsApp → Configuration:
    • Paste the URL into Callback URL.
    • Paste the same Verify Token value you stored in step 2.
    • Click Verify and save.
    • Subscribe to the messages webhook field for this phone number.
  3. (Optional) Send a test message from the Meta dashboard to confirm delivery.

The channel transitions to Connected once Meta successfully calls the webhook.

Step 4: Pair your phone

By default the channel doesn't trust any sender, so even your own messages are ignored. Pair the channel to your personal number so the agent treats you as a self-source:

  1. On the channel detail page, click Pair. A short code appears (e.g. XYZ-123).
  2. From your phone, message the connected WhatsApp Business number with that code.
  3. The channel records your number as a paired address and the conversation goes live.

From then on, messages from that number pass the default receive_message policy and the agent replies. To pair another phone, click Re-pair and repeat. To allow other contacts through, add a policy.

Configuration fields (Cloud API)

FieldRequiredDescription
phone_number_idYesPhone Number ID from the WhatsApp app in Meta for Developers.
business_account_idYesWhatsApp Business Account ID.
access_tokenYesSystem User access token with the whatsapp_business_messaging scope. Stored encrypted.
verify_tokenYesArbitrary string. Paste the same value here and in the Meta dashboard. Stored encrypted.
app_secretYesMeta App Secret, used to verify X-Hub-Signature-256 on incoming events. Stored encrypted.

Option 2: WhatsApp Personal (linked device)

This adapter links your personal WhatsApp account as a secondary device via QR code, using the wa-rs protocol bindings.

Risk of account suspension

Using a personal WhatsApp account through an unofficial client may violate WhatsApp's Terms of Service and could result in your account being banned. You are responsible for any actions taken against your account.

What you need

  • A working WhatsApp account on your phone
  • Your phone within reach to scan a QR code

No public URL, no Meta Business account, no API tokens.

Connecting the channel

  1. In Frona, open Settings → Channels and click Add channel.
  2. Pick WhatsApp (Personal account) from the provider list. The create dialog opens.
  3. Fill in the dialog:
    • Space. Defaults to WhatsApp (Personal account). This is the space the conversation will live in. Keep the default to create a new space with that name, type any other name to create a different one, or pick an existing space from the dropdown. A space can host only one channel, so spaces already bound to another channel are hidden.
    • Agent. The agent that reads every incoming message and sends the reply.
    • When a message arrives. How inbound messages are handled:
      • Treat as a message from you (default). The agent runs full inference and replies.
      • Hand off to a waiting agent. The message goes to whichever task is currently waiting on a signal. The agent does not reply on this channel. See Signals.
  4. Click Create.

You land on the channel detail page with a QR code displayed. The personal adapter has no config fields, so the QR pairing finishes the setup.

  1. On your phone, open WhatsApp → Settings → Linked Devices → Link a Device and scan the QR code.
  2. The connection completes automatically once the scan succeeds. If the QR expires before you scan, click Refresh on the channel page for a new one.

The channel transitions to Connected, but it won't reply yet. Pair your number next.

Pair your phone

By default the channel doesn't trust any sender, so even your own messages are ignored. Pair the channel to your personal number so the agent treats you as a self-source:

  1. On the channel detail page, click Pair. A short code appears (e.g. XYZ-123).
  2. From the phone you want to pair, send the code as a WhatsApp message to the linked account (e.g., from a second phone, or from any contact you want to treat as self).
  3. The channel records that number as a paired address and the conversation goes live.

To pair another number, click Re-pair and repeat. To allow other contacts through, add a policy.

Configuration fields (Personal)

The personal adapter takes no configuration. The QR pairing flow handles authentication.

How messages flow

  • Direct messages to the connected number land in a chat tagged as direct.
  • Group messages are delivered when your number is a member of the group.
  • Replies are sent back to the same WhatsApp chat. Markdown is converted to WhatsApp's formatting: *bold*, _italic_, ~strikethrough~, ```code```. Headings and tables are flattened to plain text.

Allowlisting senders

By default only your own number (Cloud API: the connected business number; Personal: the linked phone number) passes receive_message. To allow other contacts, add a policy:

cedar
permit(
  principal == Policy::Agent::"assistant",
  action == Policy::Action::"receive_message",
  resource in Policy::Channel::"whatsapp_cloud"
) when { resource.sender.address == "+15551234567" };

For the personal adapter, swap whatsapp_cloud for whatsapp_user. See Policies for channel-wide allows and group rules.

Tips

  • Use Cloud API for anything serious. It's the only path Meta supports, and account bans are not a concern.
  • The Personal adapter is fine for testing and personal use. Just keep in mind WhatsApp can revoke linked-device sessions at any time, and excessive automated traffic can flag the account.
  • Keep the verify token and app secret secret. They're how Frona proves to Meta that incoming webhooks are real.
  • Markdown is limited. WhatsApp only supports a handful of inline styles. Don't rely on tables or headings in agent output if the conversation lives here.

Troubleshooting

SymptomLikely cause
Cloud API: Channel Failed right after creationBad access_token, wrong phone_number_id, or the token lacks whatsapp_business_messaging.
Cloud API: Webhook verification fails in Meta dashboardverify_token in Frona doesn't match what you typed in Meta. They must be identical.
Cloud API: Outbound works, inbound doesn'tYou forgot to subscribe to the messages webhook field, or app_secret is wrong so signature validation rejects every event.
Personal: QR keeps expiringScan it faster. The QR rotates every ~30 seconds. Use Refresh to get a new one.
Personal: Channel Disconnected out of nowhereThe linked device session was revoked from your phone (Settings → Linked Devices), or WhatsApp invalidated it. Re-link via the QR flow.

Next steps

  • Channels. How channels work in general.
  • Policies. Allow specific contacts or groups.