Skip to content
Agent Integration12 min read·

Putting an AI agent on WhatsApp: everything Meta makes you do before a single message sends

The API call is twenty minutes. Before it works you need a number you can never use in the app again, a verified business, a template somebody at Meta approves, and, since 1 October, a payment method on file or the replies simply stop being delivered.

AI AgentsAgent IntegrationWhatsAppCloud APIWebhooksArchitecture

Every tutorial about putting an agent on WhatsApp is the same curl command. One POST to the Cloud API with a bearer token and a phone number id, and a message appears on somebody's phone. It takes twenty minutes and it genuinely works.

It works because the tutorial begins after everything difficult has already happened. The number was already registered. The business was already verified. The template was already approved. And the test recipient had messaged in first, which quietly opened the only window in which you are allowed to send an arbitrary sentence at all.

Four gates, two of them owned by somebody at Meta rather than by you, and on 1 October 2026 the cost model underneath all four changed. That is the part of a WhatsApp build that sets your launch date, and it is the part no ranking page covers. Here it is, in the order it will actually hit you.

customers a new account may message first, per 24 hourscounted across the whole business portfolio
250
window for a free-form reply, reset by every inbound messageoutside it, approved templates only
24h
free service messages per number per monthsince 1 October 2026; previously unlimited
1,000
numbers that can run the Cloud API and the app at onceregistering one deletes the other
0

The phone number is the first decision you cannot reverse

Registering a number with the Cloud API takes it away from the apps, and the documentation is blunt about the sequence. A number in use in WhatsApp Messenger has to have its account deleted before it can be registered. Delete it and the message history goes with it, the number takes up to three minutes to become available, and it cannot go back to the WhatsApp Business app unless you deregister it from the Cloud API first.

Read that against the number most clients instinctively offer. The one printed on the website. The one the support team answers in the Business app all day. The one with four years of customer conversations in it. Registering that number is a migration with data loss in the middle of it, performed on the channel your customers already use, and it is usually proposed in the same meeting where somebody says we already have WhatsApp, so this should be quick.

There is one way to keep both, and it is worth knowing before you promise anything: onboard through a partner that supports Business app number onboarding. Then the history is preserved and the Business app keeps working alongside the platform. That is a real decision with a vendor attached to it rather than a configuration flag, and it has to be made before anybody registers anything.

Verification is the only way out of 250

A new business portfolio can message 250 unique customers first in a rolling 24 hours. Not 250 messages: 250 unique phone numbers you initiate contact with. The limit sits on the portfolio rather than on a number, so the staging number, the production number and the number the sales team wanted all share one allowance, and one of them can spend all of it.

The ladder above it, as Meta documents it:

  • 250 to 2,000 by verifying your business, or by delivering 2,000 messages outside customer service windows to unique numbers within a 30 day moving period, using high quality templates. Verification is the path you control.
  • 2,000 to 10,000 to 100,000 to unlimited by automatic scaling, which wants high quality messages across every number and template, plus at least half your current limit used in the last seven days.
  • Once you qualify, the increase lands within six hours. Nobody approves it by hand, which also means nobody can be asked to hurry.
  • Replies inside the 24 hour window are not capped at all. They are not business initiated, so they never touch this number.

That last point reframes the entire limit, and it decides whether 250 matters to you. If the agent answers people who messaged in, you could handle ten thousand conversations a day at tier 250 and never notice the ceiling exists. If the product ever speaks first, a delivery notification, a renewal reminder, a reactivation campaign, then 250 is not a technical detail but your whole launch plan, and automatic scaling will not begin until you are reliably using half of what you already have.

So verification starts in week one, in parallel with the build, alongside the display name review that nobody budgets for either. It wants documents, a legal entity name that matches them, and a queue you cannot compress by working the weekend. I have watched a finished agent sit idle for eleven days waiting on a business document, which is an expensive way to learn the order of operations.

The 24 hour window is a product constraint, not an API detail

This is the one that changes what you are allowed to build. Inside a customer service window you can send whatever the agent composes. Outside it you can send approved templates and nothing else. Attempt anything else and the API returns error 131047, which the documentation politely calls a re-engagement message.

The window opens when the customer messages or calls you, and resets every time they message again. It is not a session, not a flag on a contact record, and not something you can extend by sending. It is the age of their last inbound message, which means the only correct implementation is to store that timestamp and read it before every send.

Flowchart: what the agent is allowed to say, and when
  1. The customer sends a message

    The window opens here, and reopens on every inbound message after it.

  2. Agent core handles it and composes a reply

    Normalise, resolve identity, call the model, run tools.

  3. Is the last inbound message under 24 hours old?

    ↳ no? a free-form send is refused with 131047, whatever it says

  4. Inside the window: send the text the agent wrote

    Billable as a service message once you are past the monthly free tier.

  5. Outside it: find an approved template that fits the intent

  6. No template fits? Then the agent does not get to say it

    Queue it for a human or drop it. Do not retry the free-form send.

Every proactive feature in your specification has to survive the fifth box. If the sentence cannot be written weeks in advance and approved by somebody else, the agent cannot send it.

Which kills a specific feature that gets sold constantly. The agent will follow up tomorrow once it has an answer is not something an agent can do on WhatsApp. Tomorrow is outside the window, so the follow up is a template you wrote three weeks earlier, submitted for review, and which the agent now fills four blanks in. The intelligence has to happen inside the slots, and the slots hold data, not prose.

ts
// The window is not state you own. It is the age of their last inbound
// message, so read it on every send rather than tracking a session.
async function decideOutbound(contact: Contact, reply: AgentReply) {
  const lastInbound = await inbox.lastInboundAt(contact.waId);
  const open = lastInbound !== null && Date.now() - lastInbound < 24 * 3600 * 1000;

  if (open) {
    return { kind: "text", body: reply.text };   // anything the agent composed
  }

  // Outside the window the agent does not get to write the sentence.
  const template = templates.matching(reply.intent);
  if (!template) {
    await handoff.toHuman(contact, reply);       // honest, and better than silence
    return null;
  }

  return { kind: "template", name: template.name, params: template.fill(reply) };
}

The design rule that falls out of it: finish the job inside the window, or hand off through a template. An agent that needs three business days and two human approvals to answer a question is not a WhatsApp agent, it is a ticket with extra steps, and the channel will make that obvious to your customers before it becomes obvious to you.

What changed on 1 October 2026

Every tutorial published before this month is now wrong about cost, including the ones that were updated this year. The history is worth having in one place, because the direction only goes one way.

MessageUntil 30 September 2026Now
Free-form reply inside the windowFree and unlimited, since 1 November 2024First 1,000 per business phone number per month are free. Billable after that.
Utility template inside an open windowFree, since 1 July 2025Billable, at the utility rate for the recipient's country.
Any template outside the windowBillable per message, since 1 July 2025Unchanged. Per message, on delivery, priced by country and category.
Anything inside a free entry point windowFreeStill free, for up to seven days after a Click to WhatsApp ad response.

The free tier is 1,000 service messages per business phone number per month, it does not roll over, and it resets at midnight in the messaging account's timezone rather than in yours. Eligible governments and non-profits keep service messages free beyond the tier until 31 December 2027, which is worth checking if you are one.

Metering it is less work than it sounds, because Meta tells you which side of the line each message landed on. The status webhook carries a pricing object, and the field to watch is its type: inside the monthly allowance it comes back as free customer service, and once you are past the allowance the same message comes back as regular.

json
{
  "statuses": [
    {
      "id": "wamid.HBgMNDQ3...",
      "status": "sent",
      "pricing": {
        "billable": true,
        "category": "service",
        "type": "regular"
      }
    }
  ]
}

Store that per message and you have an accurate running count against the allowance, a cost per conversation, and the number finance will ask for in month two. Field names here move between API versions, so check the current status webhook reference rather than trusting a blog post, this one included.

And keep the proportions straight when you quote the work. In most countries the model tokens are the small half of a WhatsApp agent's running cost, and the messaging bill is the half that grows with success. Meta now sells its own agent on the platform at two dollars per million tokens, which tells you fairly precisely where it expects the margin to be, and it is not in the inference. The same arithmetic as not sending every call to the expensive model, one layer further out.

Templates get rejected for reasons the error does not contain

Every template is one of three categories, authentication, marketing or utility, and the category sets the price. Review is automatic when you create or edit one and can take up to 24 hours. Approved means sendable, anything else means not, and the rejection arrives as a status rather than as an explanation.

The patterns below are what the rejections have actually been, across the builds I have shipped. None of them are in an error message.

What you submittedWhat happensWhat to do instead
A utility template with a discount or an upsell in itRecategorised as marketing, or rejected. Either way the price changes under you.One job per template. If the sentence sells anything, submit it as marketing and accept the rate.
A template that is mostly variablesRejected. A reviewer cannot tell what it will say, so they assume the worst version.Fixed prose carrying the meaning, variables for data only: a name, an order id, a date, an amount.
A variable sitting in a slot meant for a whole sentenceRejected, or approved and then paused once it starts reading like spam.One template per intent. Five narrow templates beat one clever template with a free text slot.
A perfectly good template, sent to people who did not opt inQuality rating falls, the template is paused, then disabled on repeated feedback.Fix the list, not the copy. Blocks and reports are what is being measured, not grammar.

Pausing is the failure mode worth designing for, because it arrives without a deploy. A template that has been live for months stops sending, the API returns 132015, and the cause is customer feedback rather than anything in your code. Meta does not publish the pause durations, so do not build a retry schedule around a number you read somewhere. Treat template sends as fallible instead: catch the template error codes separately from transport errors, never retry them in a loop, and have something that notices when an entire category of notification has gone quiet. It is the same instinct as bounding an agent's loop and putting a human where the risk is, applied to somebody else's moderation queue.

Practically, this means the templates are the first thing you write rather than the last. Draft them in week one, submit in week two, expect to rewrite at least one. A build that leaves them until the agent is finished has put a 24 hour review queue, and possibly a rewrite, on the critical path for no reason at all.

A phone number is not an identity

The inbound webhook gives you a WhatsApp id and a profile name the sender chose for themselves. That is an unverified claim about who is typing, and it is the most common place I see a WhatsApp agent quietly become a data breach: somebody who knows a customer's order number, messaging from a number nobody checked against an account.

So account linking is a feature with a flow, not a lookup. A one time code sent through a channel you already trust, an explicit confirmation, a stored link you can revoke, and a record of when it happened. Until that exists the agent is talking to a stranger and should hold a stranger's permissions: public information, order status only after a verification step, and no tool that moves money or changes an address. The identity, state and idempotency layer every channel needs is in AI agent integration, channel by channel, and the same authorisation argument applied to your own site is in adding an agent to your website without renting a widget.

The order I build it in

  1. 1Buy the number, start business verification, draft the templates. Day one, all three, before any code. These are the only tasks with somebody else's queue attached, and they run while you work.
  2. 2Stand up the webhook and answer the handshake. Meta sends a GET with a verify token and a challenge, and nothing else happens until you echo the challenge back. Verify the signature on every POST from the first commit rather than adding it the week before launch, because the raw-body detail that breaks it does not show up until a customer sends an emoji.
  3. 3Deduplicate on Meta's message id, not on one you generate. Webhooks retry. The first duplicate reply is embarrassing; the first duplicate tool call is a refund issued twice.
  4. 4Acknowledge fast, do the work on a queue. Return 200 immediately and call the model in a worker, because a slow handler becomes a retry, and a retry becomes the duplicate you just spent a step preventing.
  5. 5Store the last inbound timestamp per contact. Every send decision reads it, and everything in the window section above depends on it existing.
  6. 6Handle media before launch, not after. Voice notes arrive constantly; people treat WhatsApp as a walkie talkie. You get a media id, exchange it for a short lived URL, and fetch that with your access token. Transcription is in scope, and so is deciding what the agent does with ninety seconds of traffic noise.
  7. 7Link accounts, then widen permissions. Nothing that moves money or data goes near an unlinked number.
  8. 8Meter the pricing type from the first message. You want cost per conversation on day one, while it is still a curiosity, rather than in month three when it is a question from finance.

Steps one to five are two to three weeks of engineering for one channel, on top of an agent core that already exists. The calendar is always longer than the engineering, and the gap is verification and template review rather than anything you can do faster.

The twenty minute curl is real. It is also the only part of a WhatsApp agent that does not depend on a number you can never un-register, a document queue, a reviewer who has never seen your product, and a window that closes while your customer is asleep.

None of this is an argument against the channel. WhatsApp is where a great many customers already are, the engagement is unlike anything on email, and an agent that answers inbound messages sidesteps most of the constraints in this article, because the window is open and the messaging limit never applies to it. It is an argument for sequencing the work honestly, and for being suspicious of any quote that hands you a date without naming Meta's two queues.

Tell me what the agent has to do on WhatsApp and whether it ever needs to speak first, and I will come back with a fixed scope and a fixed price, with verification and template review marked on the timeline as the gates they are rather than buried in a contingency. Start that conversation here, or see what I do around this sort of work on the AI capabilities page.

Questions people ask

How do I integrate an AI agent with WhatsApp?

Use Meta's WhatsApp Cloud API and start the slow parts first. On day one, buy a number, start business verification and draft your templates, because those queues belong to Meta. Then stand up the webhook and answer the verification handshake, verify signatures on every POST, deduplicate on Meta's message id, return 200 immediately and call the model from a queue, store the last inbound timestamp per contact, handle voice notes, and link accounts before widening permissions.

How much does it cost to run an AI agent on WhatsApp?

There are two bills, model tokens and Meta's messaging charges, and in most countries the tokens are the smaller half. Since 1 October 2026, free-form replies are free for the first 1,000 per business number per month and billable after that. Utility templates inside an open window are now billable, and templates outside the window are charged per delivered message by country and category. The free tier does not roll over and resets at midnight in the messaging account's timezone.

Can a WhatsApp AI agent send a follow-up message the next day?

Only through an approved template. The customer service window closes 24 hours after the customer's last message, so a next-day follow-up must be a template you wrote and submitted for review in advance, with the agent filling data slots such as a name, an order id, a date or an amount. If no approved template fits what the agent wants to say, queue it for a human or drop it rather than retrying the free-form send.

Why do WhatsApp message templates get rejected?

Mostly for reasons the rejection does not explain. A utility template containing a discount or upsell gets recategorised as marketing or rejected. A template that is mostly variables is rejected because the reviewer cannot tell what it will say. Sending good templates to people who did not opt in lowers the quality rating until the template is paused, then disabled. Use fixed prose with variables for data only, one template per intent, and allow up to 24 hours per review.

Building something like this?

I design and ship these systems for clients: retrieval over private data, agents that complete real tasks, and the Laravel platforms underneath them.

Keep reading