<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Dainik Times</title>
    <description>The latest articles on DEV Community by Dainik Times (@dainik_times_363e0b9e9b18).</description>
    <link>https://dev.to/dainik_times_363e0b9e9b18</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4115625%2Fb9fddeb6-7f6b-4dc4-b948-dc26e3224fed.jpg</url>
      <title>DEV Community: Dainik Times</title>
      <link>https://dev.to/dainik_times_363e0b9e9b18</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/dainik_times_363e0b9e9b18"/>
    <language>en</language>
    <item>
      <title>WhatsApp Cloud API: the limits and error codes nobody documents</title>
      <dc:creator>Dainik Times</dc:creator>
      <pubDate>Tue, 08 Sep 2026 11:48:48 +0000</pubDate>
      <link>https://dev.to/dainik_times_363e0b9e9b18/whatsapp-cloud-api-the-limits-and-error-codes-nobody-documents-5g4g</link>
      <guid>https://dev.to/dainik_times_363e0b9e9b18/whatsapp-cloud-api-the-limits-and-error-codes-nobody-documents-5g4g</guid>
      <description>&lt;p&gt;I run a WhatsApp Business Platform, so I spend a lot of time watching the Meta Cloud API do things the documentation does not prepare you for. None of what follows is secret. It is just scattered, or only discoverable after it has already cost you a day.&lt;/p&gt;

&lt;p&gt;Nine things I wish someone had written down.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. A new number can only start 250 conversations a day
&lt;/h2&gt;

&lt;p&gt;Register a number today, plan a 10,000-contact launch broadcast for tomorrow, and it will not send.&lt;/p&gt;

&lt;p&gt;Every newly registered number begins on the &lt;strong&gt;250 tier&lt;/strong&gt;: it can &lt;em&gt;start&lt;/em&gt; conversations with 250 unique customers per rolling 24 hours. The ladder from there is 250 → 1,000 → 10,000 → 100,000 → unlimited, and Meta raises you automatically as volume and quality hold.&lt;/p&gt;

&lt;p&gt;Two consequences people miss:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Replies inside an open 24-hour window do not count.&lt;/strong&gt; The tier limits &lt;em&gt;business-initiated&lt;/em&gt; conversations only. A support-heavy number can talk to thousands of people a day on the 250 tier.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Quality rating moves the tier both ways.&lt;/strong&gt; Send templates people mute or report and you go down, not up.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you are migrating a brand with a real list, plan for the ramp. It is not a setting you can ask to have raised on day one.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. &lt;code&gt;/register&lt;/code&gt; has a rate limit that gets &lt;em&gt;worse&lt;/em&gt; when you retry
&lt;/h2&gt;

&lt;p&gt;This one cost a customer of mine most of a day.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;POST /{phone_number_id}/register
→ 400
(#133016) Registration or Deregistration failed because there were
too many attempts for this phone number in a short period of time
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Error &lt;strong&gt;133016&lt;/strong&gt; is a per-number limit on register/deregister. The critical part: it is not a fixed cooldown you can wait out predictably — &lt;strong&gt;each additional attempt extends it&lt;/strong&gt;. A user who taps your "Activate" button eight times in thirty seconds because nothing appears to happen will lock that number out for hours.&lt;/p&gt;

&lt;p&gt;If you build a UI around registration, put a server-side cooldown behind the button. Client-side is not enough — mobile apps hit the same endpoint.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. The useful error message is not in &lt;code&gt;message&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Meta's error envelope buries the sentence you actually need:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"error"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"message"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"(#100) Invalid parameter"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"code"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"error_data"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"details"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Phone Link to WABA Failed - Unverified WABA: You cannot
                  proceed with this operation since your WhatsApp Business
                  account is not verified..."&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you surface &lt;code&gt;error.message&lt;/code&gt; to your users — as most integrations do — they see &lt;strong&gt;"(#100) Invalid parameter"&lt;/strong&gt; and learn nothing. The explanation is in &lt;code&gt;error.error_data.details&lt;/code&gt;, and it frequently contains HTML markup you will want to strip.&lt;/p&gt;

&lt;p&gt;Read &lt;code&gt;error_data.details&lt;/code&gt; first, fall back to &lt;code&gt;error_user_title&lt;/code&gt; / &lt;code&gt;error_user_msg&lt;/code&gt;, and only then &lt;code&gt;message&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. &lt;code&gt;status: PENDING&lt;/code&gt; means the number cannot send anything
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;GET /{phone_number_id}?fields=status,platform_type,display_phone_number
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A number that has been connected but never successfully registered sits at &lt;code&gt;status: PENDING&lt;/code&gt; with &lt;code&gt;platform_type: NOT_APPLICABLE&lt;/code&gt;. It looks connected in your database. It can neither send nor receive.&lt;/p&gt;

&lt;p&gt;Check &lt;code&gt;status == "CONNECTED"&lt;/code&gt; before you tell a user they are live. Storing a &lt;code&gt;phone_number_id&lt;/code&gt; is not the same as having a working number.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. &lt;code&gt;+1 555-xxx-xxxx&lt;/code&gt; is a Meta test number
&lt;/h2&gt;

&lt;p&gt;Meta issues a free test number with every app, and it is formatted like a real US number. Users going through Embedded Signup pick it more often than you would think, then wonder why nothing works.&lt;/p&gt;

&lt;p&gt;Test numbers can only message up to five pre-approved recipients. If &lt;code&gt;display_phone_number&lt;/code&gt; starts with &lt;code&gt;+1 555&lt;/code&gt;, that is what you are looking at — surface it clearly rather than showing "Connected".&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Coexistence does not change &lt;code&gt;platform_type&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Coexistence lets a number stay live in the WhatsApp Business app &lt;em&gt;and&lt;/em&gt; work through the Cloud API. I assumed &lt;code&gt;platform_type&lt;/code&gt; would tell me which numbers were in that mode. It does not — coexistence numbers still report &lt;code&gt;CLOUD_API&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The field that actually distinguishes them is &lt;strong&gt;&lt;code&gt;is_on_biz_app: true&lt;/code&gt;&lt;/strong&gt;. I found this out by comparing a number I knew was in coexistence (it was emitting &lt;code&gt;smb_message_echoes&lt;/code&gt;) against one I knew was not.&lt;/p&gt;

&lt;h2&gt;
  
  
  7. Coexistence has a 7-day age requirement and a 6-month history replay
&lt;/h2&gt;

&lt;p&gt;Two numbers to plan around:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The number must have been &lt;strong&gt;live on the WhatsApp Business app for at least 7 days&lt;/strong&gt; before it can be linked.&lt;/li&gt;
&lt;li&gt;After onboarding, Meta replays &lt;strong&gt;up to 6 months&lt;/strong&gt; of that number's existing chats to your webhook as &lt;code&gt;history&lt;/code&gt; events.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That second one is easy to miss entirely, which brings me to the next point.&lt;/p&gt;

&lt;h2&gt;
  
  
  8. You must subscribe to &lt;code&gt;history&lt;/code&gt; and &lt;code&gt;smb_app_state_sync&lt;/code&gt; explicitly
&lt;/h2&gt;

&lt;p&gt;Webhook fields are subscribed at the &lt;strong&gt;app&lt;/strong&gt; level:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;GET /{app-id}/subscriptions
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;messages&lt;/code&gt; is almost always there. &lt;code&gt;history&lt;/code&gt; (the chat replay), &lt;code&gt;smb_app_state_sync&lt;/code&gt; (the phone's contact book) and &lt;code&gt;smb_message_echoes&lt;/code&gt; (messages the business sent from the phone app) frequently are not. If they are missing, Meta sends them to nobody and you will spend a long time debugging code that was never going to receive anything.&lt;/p&gt;

&lt;p&gt;Two things worth knowing about the payload shape:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;History messages are nested at &lt;code&gt;value.history[].threads[].messages[]&lt;/code&gt; — &lt;strong&gt;not&lt;/strong&gt; at &lt;code&gt;value.messages&lt;/code&gt;. If you handle them in your normal inbound loop by accident, you will replay six months of old chats through your automation and message people who have not talked to you since March. Guard it.&lt;/li&gt;
&lt;li&gt;Direction is &lt;strong&gt;not&lt;/strong&gt; reliably in &lt;code&gt;history_context.from_me&lt;/code&gt;. The documented signal is the presence of a &lt;code&gt;to&lt;/code&gt; field, which appears only on business-sent messages.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  9. Imported history breaks chronological order if you sort by insertion
&lt;/h2&gt;

&lt;p&gt;If your inbox pages messages by autoincrement id — which is the obvious implementation — a six-month history import lands &lt;em&gt;after&lt;/em&gt; today's messages, because the rows are newer even though the messages are older.&lt;/p&gt;

&lt;p&gt;SQLite lets you insert explicit negative rowids, including on an &lt;code&gt;AUTOINCREMENT&lt;/code&gt; table, and &lt;code&gt;sqlite_sequence&lt;/code&gt; is unaffected. Deriving the id from the message's own timestamp puts imported history in correct order below every live row:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;id = timestamp * 1000 + sequence - 4_000_000_000_000_000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Always negative, always monotonic in time. Whatever your database, the general point stands: decide deliberately how imported history sorts against live messages, because the default will be wrong.&lt;/p&gt;




&lt;h2&gt;
  
  
  One billing note
&lt;/h2&gt;

&lt;p&gt;Meta moved from per-conversation to per-message billing on 1 July 2025. It is also reported that from &lt;strong&gt;1 October 2026&lt;/strong&gt;, free-form replies inside the 24-hour service window — free until now — become billable. Check Meta's current pricing docs before you model anything on "replies are free".&lt;/p&gt;




&lt;p&gt;I work on &lt;a href="https://quickwa.com" rel="noopener noreferrer"&gt;QuickWA&lt;/a&gt;, a WhatsApp Business Platform built on the Cloud API. Everything above came out of running it, not out of the docs. If you have hit something on this list — or something that should be on it — I would genuinely like to hear it.&lt;/p&gt;

</description>
      <category>whatsapp</category>
      <category>api</category>
      <category>webdev</category>
      <category>meta</category>
    </item>
  </channel>
</rss>
