Drawing 1 · Interactive
Can your workers keep up with a history burst?
4.8× slow motionService time S = 280 ms per job on average · 4 workers
Queue diagram: 4 history chunks waiting, 3 of 4 workers busy, 7 done, 1 needs review (decline or bad chunk).
- Backlog
- 3.5
- history chunks waiting on average
- Throughput
- 12/s
- 11.5/s done · 0.5/s needs review (decline or bad chunk)
- Average wait
- 293 ms
- 67% of history chunks wait at all
- Utilisation ρ
- 0.84
- ≈ 3.4 of 4 busy
ρ = λ × S ÷ c = 12/s × 280 ms ÷ 4 = 0.84
Utilisation is below 1: the workers keep up.
What is message history sync?
Message history sync is the step of Coexistence onboarding in which a WhatsApp Business app number that has just been connected to the Cloud API through Embedded Signup hands its earlier one-to-one conversations to the partner's platform. The business approves sharing inside the app, the partner asks Meta to start the sync, and Meta replays the chats to the partner's webhook in batches. The import covers up to six months (180 days) of one-to-one chats; media files are included only for the last 14 days, and groups are not imported.
Technically it is two requests and a stream of webhooks. The partner calls POST /{PHONE_NUMBER_ID}/smb_app_data with sync_type: "smb_app_state_sync" to receive contacts, and with sync_type: "history" to receive conversations. History then arrives under the webhook field history: each payload holds a history array whose entries carry metadata.phase, metadata.chunk_order and metadata.progress, and a list of threads, one per contact, each with messages (from the customer) and message_echoes (sent by the business). Past messages carry a history_context.status such as READ or DELIVERED.
Message history sync is a backfill of the past and happens once per onboarding. It is different from the Message Echoes Webhook (smb_message_echoes), which keeps mirroring each new message the business sends from the app after onboarding, and from ordinary messages webhooks for new inbound chats. A complete Coexistence integration needs all three to build one continuous timeline.
Key takeaways
- Message history sync is a one-time backfill of a Coexistence number's past one-to-one chats, delivered to the partner as
historywebhooks. - It covers up to 180 days of chats, with media files from the last 14 days only; group chats are not imported.
- The partner must request it with
POST /{PHONE_NUMBER_ID}/smb_app_dataand the sync has to finish within 24 hours of onboarding. - Chunks arrive in phases (0: day 0–1, 1: day 1–90, 2: day 90–180) with a
chunk_orderandprogress, and may come out of order. - The business can decline sharing in the app; the webhook then carries an error instead of threads, which is a normal outcome.
Operating sequence
How does message history sync work?
Finish Coexistence onboarding
The business connects its Business app number through the Coexistence variant of Embedded Signup and, in the app's confirmation screen, chooses whether to share chat history. Your app must be subscribed to the
history,smb_app_state_syncandsmb_message_echoeswebhook fields.Request contacts and history
Call
POST /{PHONE_NUMBER_ID}/smb_app_datatwice with the business token: once withsync_type: "smb_app_state_sync"and once withsync_type: "history". Without these calls Meta never sends the sync. Do it right after onboarding: the window is 24 hours.Accept chunks fast and queue them
Each
historywebhook can carry many threads. Verify the signature, write the raw payload to a queue and return 200 immediately; parse and store in workers so a slow database never causes Meta to retry.Store idempotently by phase and chunk
Key each chunk by phone number ID,
phaseandchunk_order, and each message by itsid. Insert bothmessages(inbound) andmessage_echoes(outbound) so threads are not one-sided, and keep the original timestamps.Track completion and declines
Use
progressto show a progress bar and mark the sync complete when phase 2 reaches 100. If the payload holdserrorswith code 2593109, the business declined sharing: show "history not shared" rather than raising an alert.
Implementation
Message history sync in code
# Contacts first, then conversation history (both within 24h of onboarding)curl -X POST "https://graph.facebook.com/v26.0/{PHONE_NUMBER_ID}/smb_app_data" \-H "Authorization: Bearer {BUSINESS_TOKEN}" \-H "Content-Type: application/json" \-d '{ "messaging_product": "whatsapp", "sync_type": "smb_app_state_sync" }'curl -X POST "https://graph.facebook.com/v26.0/{PHONE_NUMBER_ID}/smb_app_data" \-H "Authorization: Bearer {BUSINESS_TOKEN}" \-H "Content-Type: application/json" \-d '{ "messaging_product": "whatsapp", "sync_type": "history" }'
Specifications
Message history sync: key facts and limits
- History depth
- Up to 180 days of one-to-one chats
- Media included
- Files from the last 14 days only
- Groups
- Not imported
- Deadline
- Sync must finish within 24 hours of onboarding
- Trigger
- POST /{PHONE_NUMBER_ID}/smb_app_data (sync_type history)
- Webhook fields
- history, smb_app_state_sync (contacts)
- Phases
- 0 = day 0–1 · 1 = day 1–90 · 2 = day 90–180
- Declined sharing
- errors[] with code 2593109
Failure modes
Common mistakes with message history sync
Never requesting the sync
Subscribing to the
historyfield is not enough; nothing arrives until you callsmb_app_data. Make the two requests part of the onboarding job and alert if no chunk or decline arrives within a few hours.Reading only messages[]
Business replies live in
message_echoesinside each thread. Ingest both arrays with the right direction, or the archive shows customers talking to nobody.Treating a decline as an outage
A business choosing not to share history produces an error payload by design. Surface it to the customer in plain words and keep it out of on-call alerting.
Processing chunks inline
Thousands of large payloads in minutes will time out a handler that writes to the database before answering, which triggers retries and duplicates. Acknowledge, queue, and deduplicate by chunk and message ID.
Ignoring retention rules
You are importing months of personal conversations. Apply your data-retention and DPDP Act policies to the archive from day one, including deletion when the business offboards.
Design intent
Why does message history sync matter?
For a business moving from the app to a shared team inbox, history is what makes the switch feel safe: an agent opening a customer's thread sees last month's order discussion instead of a blank screen. For the developer, the sync is a burst of hundreds or thousands of webhook deliveries arriving in minutes, out of order and with a hard deadline, so it tests idempotency, queueing and data-retention design more than any normal day of traffic.
Example: A Kochi spice exporter brings its chats across
A Kochi spice exporter has used the WhatsApp Business app for three years and connects it to a team inbox through Coexistence on a Tuesday morning, choosing to share history. The platform requests the sync at once. Over the next 40 minutes it receives roughly 1,900 history webhooks: phase 0 first (the last day), then phase 1 and phase 2 in bursts. Workers store about 48,000 messages across 1,100 threads; voice notes older than 14 days appear as placeholders. When phase 2 reports 100 the inbox shows "History imported", and new messages sent from the phone keep appearing through echoes.
Recommended practice
Best practices for message history sync
- Show onboarding customers a progress bar driven by
progress; it removes "where are my chats?" tickets. - Media older than 14 days will not arrive, so render a clear placeholder instead of a broken attachment.
- Some media resolves in a later
historywebhook shaped like a normalmessagespayload; handle both shapes. - Size your queue workers for the onboarding burst, not for steady-state traffic.