Start free
All posts

WhatsApp coexistence: the Business app and the Cloud API on the same number

You can keep answering from the WhatsApp Business app on your phone and, at the same time, connect the same number to the Cloud API — without giving up the number your customers know or your chat history. Meta calls it onboarding business app users; the market calls it coexistence. What it requires, what changes in the app, the 24 hours you do not get back and what the integration has to do to avoid ruining six months of history.

CCX EngineeringPlatform · Channel rules · Oct 17, 2026 · 15 min read
Illustration of a phone and an inbox showing the same conversation, linked by a two-way sync
With coexistence, the same number answers from the app on the phone and through the Cloud API — and the history comes along, once. Illustration.

What you'll take away

  • Requirements, onboarding and the contact and history sync that happens only once, within 24 hours
  • What stops working in the app, the fixed throughput of 20 messages per second and who pays for what
  • The integration traps: history treated as new conversations, echoes, phone number formats and disconnection

What coexistence is, and why it matters if you already serve customers from the app

The Onboarding WhatsApp Business app users page of the Cloud API documentation describes a flow in which a business already using the WhatsApp Business app connects the same number to Meta's platform, through a partner, and starts using both at the same time. The page itself notes that the feature is sometimes called “Coexistence” in support channels and partner documentation. It launched on 11 February 2025, according to the changelog.

For small and mid-sized businesses, it answers the question that comes up most whenever the API is mentioned: do I have to give up the app? With coexistence, no. The owner keeps replying from the phone, with the usual labels, catalogue and quick replies, and the same conversation now also lives in a shared inbox with several agents, in automations, template campaigns and integrations with the rest of the stack.

The alternative is a full migration, and Meta is clear about its cost. To move a number from the app to the Cloud API without coexistence, you have to delete the app account, and, according to the page describing that migration, the existing chat history is lost and the number cannot be used in the app again until it is deregistered from the Cloud API. With coexistence, the history is preserved. That is why, for businesses with years of conversations on the phone, coexistence tends to be the first step — and sometimes the only one.

On availability, an honest caveat: the current page publishes no list of countries. The exclusion list that existed in 2025 did not include Brazil, and the changelog records markets being enabled gradually — India, Australia, Japan, the European Union, the United Kingdom and, in 2026, Nigeria and South Africa. Error 3441042, for a feature unavailable for numbers from the region, still exists, which suggests some geographic restriction still applies somewhere.

Requirements and the onboarding path

The official requirements are few. The WhatsApp Business app must be on version 2.24.17 or newer. The connection goes through a Meta partner — Solution Partner or Tech Provider — via Embedded Signup, the sign-up flow embedded in the partner's site. In the documented configuration, the partner passes whatsapp_business_app_onboarding as featureType; in more recent versions of the flow, Meta also routes into coexistence automatically when it detects that the number entered is already on the app.

For the owner, the path is short: they enter the number, receive a message in the app from the official Facebook Business account, tap to connect, choose whether to share their chat history and confirm — in one variant of the flow, by scanning a QR code from inside the app. Registering the number on the Cloud API, a separate step in regular onboarding, is skipped: the number is already registered. At the end, the partner receives the FINISH_WHATSAPP_BUSINESS_APP_ONBOARDING event and can check the number's is_on_biz_app and platform_type fields.

The errors along the way say more than the requirements list. 3441045, with a message saying more activity on the app is needed, shows up on new or lightly used numbers — Meta does not publish how many days of use are enough. 2655093 warns that switching partners is not supported in this flow and tells you to disconnect the current partner from the app itself. And after a disconnection, the error page asks for a 15-minute wait before trying again.

The 24 hours you do not get back: contacts and history

Once onboarding is done, the clock that matters most starts. According to the coexistence page, the partner has 24 hours to sync the customer's contacts and chat history; after that, the customer has to be offboarded and redo the whole flow. And the sync can only be performed once — to repeat it, the same path: disconnect and start over.

The request is POST /<PHONE_NUMBER_ID>/smb_app_data, with sync_type set to smb_app_state_sync for contacts or history for conversations. The response only acknowledges the request, with a request_id; the data arrives later, through webhooks. In our implementation, the order is contacts first and history second, so conversations have someone to attach to when they arrive. Meta asks the owner to keep the app open during the sync, which can take several minutes.

What comes back has clear limits. One-to-one chats from the last six months — 180 days counted from onboarding. Group chats are not synced. Media only comes with the file if it was sent within 14 days of onboarding; the rest arrives as a placeholder, with no way to fetch it later. Contacts come in full, as long as they have a WhatsApp number. If the owner declined to share history, the history webhook arrives with error 2593109, and there is nothing to import.

Because it is a single chance, the sync cannot be allowed to fail silently. Our parser was written from the documentation, and the worst possible outcome would be to receive the history, not recognise its shape, extract zero messages and acknowledge the webhook as if there were nothing — six months would vanish without warning, and the request does not repeat. So when history arrives and nothing is extracted, we log the shape of the payload, keys and counts only, with no phone numbers, names or message bodies. That is what makes it possible to fix the parser without needing a second customer to reproduce the problem.

History is not a new conversation

The history webhook delivers conversations in chunks. Each one carries metadata.phase — 0 for the first day, 1 for up to 90 days, 2 for up to 180 —, a chunk_order and a progress value that reaches 100 at the end. Inside are the conversations in threads[], each message with id, timestamp, type and a history_context.status. Meta warns that a single webhook can describe thousands of messages and recommends capturing the contents first and processing them asynchronously.

Chunks arrive out of order, and Meta redelivers them. The engineering consequence is that nothing can depend on sequence: real idempotency is each message's wamid hitting a unique index, and the end of the process is progress: 100, not the arrival of the last chunk_order. A message without a wamid or a usable timestamp should be discarded — and counted, so the log does not claim everything was imported.

The most important lesson, though, is about the product: history cannot go down the same path as live incoming messages. If it does, every months-old conversation opens a 24-hour customer service window on the wrong clock, starts service-level timers and triggers the AI, auto-replies, phone notifications and the customer's own webhooks. And there is a worse, less obvious effect: a “STOP” the customer sent four months ago, reprocessed as a new message, marks the contact as opted out and blocks campaigns for someone who never asked for that now.

In our implementation, history is a record, not a conversation: it goes straight to storage, with each message's real timestamp, without opening a window or triggering anything. Media that did not come through becomes an explicit placeholder — photo unavailable, audio unavailable — instead of a broken image bubble, which would look like a system defect the moment an agent clicked on it.

Phone numbers without the “+”, and formats that changed

Meta sends the customer's phone number without the “+”, in wa_id format — 5511… instead of +5511…. It is the same format as regular webhooks, but history has a peculiarity: it brings old conversations, and old conversations bring numbers stored in different ways. In Brazil, where mobile numbers gained a ninth digit, the same customer can appear in the history with and without it, and in your database in a third form.

Without matching the formats, six months of history turn into duplicated contacts and conversations at scale: the same person split across two records, each holding half the conversation. In our implementation, history goes through the same phone matching the inbox uses — including both versions of the Brazilian mobile number — before deciding which contact each conversation belongs to.

And the default decision has to be merge, not skip. On a number that was already serving customers from the app and has just joined the API, there will normally already be a live conversation for many of the phones in the history: the customer wrote yesterday, and the message already came in through the regular webhook. The history should be merged into that conversation, ordered by real timestamp — not discarded because it “already exists”, nor written as a second thread.

Contacts call for a similar rule. The smb_app_state_sync webhook carries the phone's address book, with an action of add or remove. A recommendation of ours: use additions to fill in names, and ignore removals. Deleting a contact from the system because it disappeared from the owner's phone address book would destroy service history over an event that is not about that.

The owner replies from the phone: echoes

Coexistence is not just onboarding. Afterwards, the owner keeps replying from the app, and every message sent from there reaches the partner through the smb_message_echoes webhook, with sender, recipient, id, timestamp and type. According to the reference, an echo also arrives when the owner edits or deletes a message in the app. It is continuous, and it is what keeps the conversation complete on both sides.

Without ingesting echoes, the agent using the inbox sees the customer's question and no answer, and replies again. The customer gets the same information twice, from two people, sometimes with different answers. Every echo is an outbound message — it is the business speaking — and it joins the conversation with the time it was sent, as if it had gone out from the inbox itself.

One window rule that confuses people: messages sent from the app do not create, extend or affect the Cloud API customer service window, says the coexistence page. The window only opens when the customer writes after onboarding. For someone who wrote just before the connection, the business can only reply through the API with a template. The owner may have just chatted with the customer from the phone, and the inbox still needs a template to talk to them.

Then there are linked devices. The business can keep up to four companion devices, but at onboarding all of them are unlinked, and the owner has to link again the ones they use. All are supported except WhatsApp for Windows and WhatsApp for WearOS — and messages sent from an unsupported companion do not trigger webhooks. In practice, what an employee answers from the Windows app does not show up in the system. It is worth telling the customer before connecting.

What changes in the app after connecting

Some app features are switched off in one-to-one chats when the number enters coexistence: disappearing messages, view once and live location. Broadcast lists too: new ones cannot be created, and existing ones become read-only. For a small business that promotes through broadcast lists, this is the change that weighs most — promotion moves to templates, through the API, with template rules and template costs.

Other features stay in the app but do not exist in the API: groups, voice and video calls, catalogue, orders, status, greeting and away messages, quick replies and labels. The owner keeps using all of that on the phone; the inbox does not see it. The page's comparison is useful for setting expectations: coexistence adds the API to the app, it does not turn the app into an API.

And some platform features are out of reach for app numbers. The groups documentation says they are not available for WhatsApp Business app numbers. The calling API requires the number to be in use with the Cloud API and not with the app. And Meta does not grant official business account status to app numbers. If you plan to use any of these, you will need the full migration at some point.

Throughput, billing and the limit that applies

A coexistence number's throughput is fixed. According to the Throughput page, numbers used in both the app and the Cloud API have “a fixed throughput of 20 mps” — 20 messages per second, counting inbound and outbound, of every type. For comparison, a Cloud API-only number starts at 80 and can be upgraded automatically to 1,000. Going over the ceiling returns error 130429, as with any number.

For a typical small or mid-sized operation, 20 per second is plenty: that is 1,200 messages a minute. The ceiling shows up in large campaigns, and then it becomes planning — a list of 50,000 contacts takes well over a few minutes to go out, and live customer service shares the same throughput with the broadcast. The portfolio messaging limit, which counts unique recipients outside the window in 24 hours, applies as usual.

Billing separates the two ends. The coexistence page says messages sent from the app remain free, and messages sent through the Cloud API follow Cloud API pricing. Since 1 October 2026, that includes service messages: each number gets 1,000 free service messages a month, and from the 1,001st Meta charges. Utility and marketing are charged per delivered message, with the window open or closed.

The practical reading, which is ours and not a Meta rule: replying from the app costs nothing; replying from the inbox uses the number's monthly service allowance and, after it, costs money; and proactive sending, with templates, only exists through the API. That helps decide who answers from where — and explains why some businesses leave the owner on the app and the team on the inbox.

Staying connected, disconnecting and switching partners

The integration depends on the phone. The account_update webhook carries the reason when the connection drops, and two of them are about inactivity: PRIMARY_INACTIVITY, when the main device goes about 14 days without use, and COMPANION_INACTIVITY, about 30 days. WhatsApp's Help Center says the same about linked devices in general. For the owner, the rule is simple: the phone with the app has to stay in use.

Changing phones, reinstalling the app or re-registering the number disconnects the Cloud API automatically, with the ACCOUNT_OFFBOARDED event. On re-registration, the owner sees a pre-selected option to reconnect, and the process usually takes a few minutes, ending with ACCOUNT_RECONNECTED. During reconnection, sending through the API is suspended. If you subscribe to account_update, you know right away; if you do not, you find out from the messages that never went out.

Disconnecting on purpose is done from the app, not the API. The coexistence page says the deregister API does not work for a number in use on both the app and the Cloud API; the path is the owner themselves, in the account settings, in the business platform section. The partner receives PARTNER_REMOVED, with a disconnection_info stating the reason and who initiated it.

Finally, Meta's new account model, which took effect on 23 September 2026, treats coexistence as an exception. At onboarding, Meta converts the existing account into a backward-compatible Messaging account and does not create the partner-specific Messaging account it creates in the regular flow. The flow does not accept switching partners either — error 2655093 says to disconnect the current one first —, and multi-partner conversations do not support app numbers. In practice, a coexistence number works with one partner at a time.

The rules that stay in the code

01One chance to sync24 hours, once only. Miss the deadline and the customer disconnects and redoes the flow.
02History is not inboundDo not open windows, trigger AI or opt-outs from messages sent months ago.
03Idempotency by wamidChunks arrive out of order and get redelivered; the end is progress: 100.
04Match the formatsA phone without +, in an old or new format, is the same customer. Merge, do not duplicate.
05Ingest the echoessmb_message_echoes shows what the owner replied from the phone. Without them, the answer goes out twice.
06Windows does not show upA message sent from WhatsApp for Windows triggers no webhook and never reaches the system.
0720 per second, fixedCoexistence throughput counts inbound and outbound and does not scale up automatically.
08Keep the phone in useAbout 14 days without using the main device drops the connection. Subscribe to account_update.
See how the WhatsApp channel works at CCX

Want to see this running on your own number?

Sign up through the site and get a US$5 test credit.

WhatsApp coexistence: app and Cloud API on one number · CCX Messages