Updated on October 25, 2026
With WhatsApp coexistence, three things sync to the API: the app contacts that have WhatsApp, the last six months of one-to-one chat history (if the business allows it) and, from then on, every message the business sends from the phone, through the smb_message_echoes webhook. Groups, calls, catalog, status, labels, quick replies and broadcast lists do not sync. The initial sync must be requested within 24 hours of onboarding, and each type can only be requested once.
This article covers what comes across, what stays behind, how the data arrives in your webhook and what changes in the app after onboarding. Coexistence is the feature that lets a business keep using its number in the WhatsApp Business app while also connecting it to the Cloud API.
Summary: what syncs and what doesn’t
The table below follows the feature comparison on Meta’s Onboard WhatsApp Business app users page:
| Item | Syncs to the API? | How it arrives |
|---|---|---|
| Contacts with a WhatsApp number | Yes | smb_app_state_sync webhook |
| One-to-one chats from the last 6 months | Yes, if the business allows it | history webhook |
| Media from older chats | Only media IDs from the last 14 days | Separate history webhooks |
| New messages sent from the app | Yes | smb_message_echoes webhook |
| New incoming messages | Yes | messages webhook |
| Message edits and deletions | Yes (newly supported) | Edit and revoke events |
| Groups | No | — |
| Voice and video calls | No | — |
| Catalog, orders, status | No | — |
| Greeting, away messages, quick replies, labels | No | — |
| Business profile and channels | No | — |
| Broadcast lists | No; read-only in the app | — |
Contacts: smb_app_state_sync
Contact sync is requested through the SMB App Data API (smb_app_data) right after onboarding:
curl -X POST "https://graph.facebook.com/<API_VERSION>/<BUSINESS_PHONE_NUMBER_ID>/smb_app_data" \
-H "Authorization: Bearer <ACCESS_TOKEN>" \
-H "Content-Type: application/json" \
-d '{ "messaging_product": "whatsapp", "sync_type": "smb_app_state_sync" }'
The response includes a request_id, which Meta recommends storing for support tickets. Then smb_app_state_sync webhooks arrive with the app contacts. Each contact has full_name, first_name, phone_number and action:
add: contact added or edited;remove: contact removed (without the name fields).
After the initial load, the same webhook keeps firing whenever the business adds, edits or removes a contact in the app. Only contacts with a WhatsApp number are included.
Chat history: the history webhook
History is requested with the same API, changing the sync_type:
curl -X POST "https://graph.facebook.com/<API_VERSION>/<BUSINESS_PHONE_NUMBER_ID>/smb_app_data" \
-H "Authorization: Bearer <ACCESS_TOKEN>" \
-H "Content-Type: application/json" \
-d '{ "messaging_product": "whatsapp", "sync_type": "history" }'
What the documentation says about the content:
- Time range: messages sent and received up to 180 days before onboarding.
- One-to-one chats only: group messages are excluded.
- Media: media messages arrive without the file ID; media IDs come in separate webhooks and only for media from the last 14 days.
- Consent: the business chooses in the app whether to share its history. If it declines, a
historywebhook arrives with error2593109.
Phases and chunks
History arrives in three phases, counted from the onboarding day (day 0):
| Phase | Period |
|---|---|
| 0 | Day 0 to day 1 |
| 1 | Day 1 to day 90 |
| 2 | Day 90 to day 180 |
Each phase can come in several chunks, not necessarily in order. Use chunk_order to sort chunks, phase to track the phase and progress for the overall status: 100 means the sync is complete. If a phase has no messages, no webhook is sent for it.
Meta warns that a single webhook can describe thousands of messages. The recommendation is to store the payload first and process it asynchronously so your endpoint does not time out.
New messages: smb_message_echoes
After onboarding, the owner keeps replying from the phone. Every message sent from the app (or from a supported linked device) triggers an smb_message_echoes webhook, which you should save in the contact’s thread. Example from the documentation:
{
"object": "whatsapp_business_account",
"entry": [{
"id": "102290129340398",
"changes": [{
"value": {
"messaging_product": "whatsapp",
"metadata": {
"display_phone_number": "15550783881",
"phone_number_id": "106540352242922"
},
"message_echoes": [{
"from": "15550783881",
"to": "16505551234",
"id": "wamid.HBgLMTY0NjcwNDM1OTUVAgARGBIyNDlBOEI5QUQ4NDc0N0FCNjMA",
"timestamp": "1700255121",
"type": "text",
"text": { "body": "Here's the info you requested! https://www.meta.com/quest/quest-3/" }
}]
},
"field": "smb_message_echoes"
}]
}]
}
Note that the array is called message_echoes (not messages) and that it includes a to field with the customer’s number. Without this webhook, your system only sees incoming messages and the ones sent through the API: half the conversation. This matters especially for multi-agent support, where agents need to see what the owner replied from the phone.
Routing events in your endpoint
A Node.js skeleton to separate the fields:
export async function handleWebhook(body, queue) {
for (const entry of body.entry ?? []) {
for (const change of entry.changes ?? []) {
const { field, value } = change;
switch (field) {
case 'messages':
await queue.add('message', value); // incoming and statuses
break;
case 'smb_message_echoes':
await queue.add('app_echo', value.message_echoes);
break;
case 'history':
await queue.add('history', value); // process asynchronously
break;
case 'smb_app_state_sync':
await queue.add('contacts', value);
break;
case 'account_update':
await queue.add('account', value); // e.g. PARTNER_REMOVED
break;
}
}
}
}
Return 200 quickly and process from the queue. To try these events before going live, see how to test the webhook locally.
Linked devices: where sync breaks
The app supports up to four linked devices. During onboarding, all of them are unlinked, and the business can re-link the supported ones. WhatsApp for Windows and WhatsApp for WearOS are not supported.
Documented consequences:
- messages from customers using an unsupported linked device do not trigger the
messageswebhook, so they do not show up in your system; - in those cases, an unsupported message webhook with error
131060may arrive. The same error also appears when someone messages the business for the first time (common after an ad click) and usually resolves within seconds.
When you get 131060, tell the business to check the message in the app.
What changes in the app after onboarding
Some app features are turned off or change:
- Disappearing messages: turned off for one-to-one chats.
- View once: disabled for one-to-one chats.
- Live location: disabled for one-to-one chats.
- Broadcast lists: disabled; no new lists can be created and existing ones become read-only.
- Message edit and delete: now supported and mirrored.
Everything else (groups, calls, catalog, status, greeting and away messages, quick replies, labels, profile and channels) stays the same in the app but does not exist in the API. If your operation relies on app labels to organize customers, for example, you will need to rebuild that logic in your system.
The 24-hour deadline: checklist
The initial sync has strict rules: the business must be synced within 24 hours of onboarding, and each request (contacts and history) can only be made once. Missed the deadline or need to redo it? The business has to disconnect and go through the flow again.
- Subscribe to
account_update,history,smb_app_state_syncandsmb_message_echoesbefore opening the flow to the customer. - Make sure your endpoint stores the payload and responds quickly.
- Request contacts and history right after onboarding.
- Tell the customer the sync is running and ask them to keep the app open.
- Track
progressuntil 100 and let the customer know when it is done. - Keep the
request_idfrom both calls.
To check whether a number is in coexistence, request is_on_biz_app and platform_type on the number; true and CLOUD_API mean app and API at the same time. If the number is not in the Business app and you want to move it straight to the API, see how to free up a number already on WhatsApp.
Coexistence with Vectalk
Vectalk supports coexistence: the number stays in the WhatsApp Business app and also works through the API. The webhooks are the ones in Meta’s documentation, so smb_message_echoes, history and smb_app_state_sync arrive at the URLs you register with POST /api/webhooks, in the same format shown above. Authentication and webhook details are in the documentation; questions about your account’s initial sync can go through the Help Center.
Frequently asked questions
How much chat history does coexistence bring over?
Up to six months (180 days) of one-to-one chats before onboarding, if the business allows sharing in the app. Groups are not included.
Do old photos and audio come along?
Only partly. Media messages in the history arrive without the file; media IDs come in separate webhooks and only for media from the last 14 days before onboarding.
Can I sync the history again later?
Not through the API. Each sync can only be requested once. To repeat it, the business has to disconnect and go through onboarding again.
Do messages I send from my phone show up in the system?
Yes, through the smb_message_echoes webhook, as long as they are sent from the app or a supported linked device. Messages sent from the app do not open or extend the API customer service window; see coexistence with a CRM and limits.
Do app groups move to the API?
No. Groups keep working in the app but are not synced or available through the API.
Official sources consulted on October 25, 2026: Onboard WhatsApp Business app users (Coexistence), Use an existing WhatsApp number, messages webhook reference.
