← Blog

Claude API WhatsApp Business Integration Guide

2026-10-21 · 5 min read · SubToAPI Team

Can you connect Claude to WhatsApp Business?

Yes. Claude has no native WhatsApp connector, but Anthropic's models work well behind WhatsApp Business because the integration pattern is simple: WhatsApp sends you a webhook when a user messages your business number, your server calls Claude with that message, and you send Claude's reply back through the WhatsApp Cloud API. There's no official bridge between the two — you build a small relay service that sits in the middle.

This guide walks through that relay: registering a WhatsApp Business number, handling inbound webhooks, calling Claude for a response, and sending the reply back, including how to manage conversation history and tool calls so the bot feels coherent across a multi-turn chat.

The architecture

WhatsApp user → Meta Cloud API webhook → your server → Claude API → your server → Meta Cloud API → WhatsApp user

You need three pieces:

  1. A WhatsApp Business Platform account (via Meta's Cloud API, the free-tier option most developers use instead of self-hosting the On-Premises API).
  2. A webhook endpoint that receives incoming messages and sends outgoing ones.
  3. A Claude API client that turns the incoming text into a prompt, keeps track of conversation state, and returns a reply.

Step 1: Set up the WhatsApp Cloud API

  1. Create a Meta Business app at developers.facebook.com and add the WhatsApp product.
  2. Get a test phone number (or connect your verified business number) and note the Phone Number ID and a temporary access token.
  3. Configure a webhook URL pointing at your server, with a verify token you choose yourself.
  4. Subscribe to the messages field so Meta sends you a POST request every time a user writes to your number.

A minimal webhook verification handler:

app.get("/webhook", (req, res) => {
  const { "hub.mode": mode, "hub.verify_token": token, "hub.challenge": challenge } = req.query;
  if (mode === "subscribe" && token === process.env.WHATSAPP_VERIFY_TOKEN) {
    res.send(challenge);
  } else {
    res.sendStatus(403);
  }
});

Step 2: Receive and parse inbound messages

Meta's webhook payload nests the actual message text a few levels deep. Extract the sender's phone number and text body:

app.post("/webhook", async (req, res) => {
  const entry = req.body.entry?.[0];
  const change = entry?.changes?.[0]?.value;
  const message = change?.messages?.[0];

  if (message?.type === "text") {
    const from = message.from;          // user's WhatsApp number
    const text = message.text.body;     // user's message
    await handleIncomingMessage(from, text);
  }

  res.sendStatus(200); // acknowledge immediately, Meta expects a fast 200
});

Always return a 200 quickly — WhatsApp retries if you're slow, which can duplicate processing. Do the Claude call asynchronously if your response times are inconsistent.

Step 3: Call Claude for a reply

This is where most of the actual "integration" work happens: deciding how to format the prompt, how much history to keep, and how to call the model reliably. Using SubToAPI as the Claude access layer keeps this part simple because you get a standard HTTPS endpoint, an application API key, and usage metadata without separately managing provider credentials or billing per model.

async function getClaudeReply(from, text) {
  const history = getConversationHistory(from); // your own storage, keyed by phone number

  const response = await fetch("https://api.subtoapi.app/v1/messages", {
    method: "POST",
    headers: {
      "Authorization": `Bearer ${process.env.SUBTOAPI_KEY}`,
      "Content-Type": "application/json"
    },
    body: JSON.stringify({
      model: "claude-sonnet-4-5",
      max_tokens: 500,
      messages: [...history, { role: "user", content: text }]
    })
  });

  const data = await response.json();
  return data.content[0].text;
}

Keep max_tokens conservative — WhatsApp messages are short-form by nature, and long Claude replies get awkward when rendered as chat bubbles. If you need Claude to call external functions (checking order status, booking a slot, looking up inventory) before replying, the same endpoint supports tool use; see /docs/tools for the request shape.

Step 4: Send the reply back through WhatsApp

async function sendWhatsAppMessage(to, text) {
  await fetch(
    `https://graph.facebook.com/v19.0/${process.env.WHATSAPP_PHONE_ID}/messages`,
    {
      method: "POST",
      headers: {
        "Authorization": `Bearer ${process.env.WHATSAPP_ACCESS_TOKEN}`,
        "Content-Type": "application/json"
      },
      body: JSON.stringify({
        messaging_product: "whatsapp",
        to,
        type: "text",
        text: { body: text }
      })
    }
  );
}

Chain it together: handleIncomingMessage calls getClaudeReply, then sendWhatsAppMessage, then persists both turns to history.

Managing conversation state per contact

WhatsApp doesn't give you sessions — every webhook is a standalone HTTP call. You're responsible for mapping from (the phone number) to a stored conversation. A simple key-value store (Redis, a Postgres table, even a JSON file for a prototype) keyed by phone number works fine. Trim history to the last 10–15 turns to control token usage and latency; Claude doesn't need the full chat history to stay coherent in a support or sales context.

Streaming isn't useful here — but latency still matters

WhatsApp doesn't support partial message streaming the way a web chat UI does, so you don't need Claude's streaming mode for this integration (that's more relevant for /docs/streaming use cases like live chat widgets). What matters instead is total round-trip time: users expect a WhatsApp reply within a few seconds. Keep prompts tight, cap max_tokens, and avoid chaining multiple Claude calls per incoming message unless you're doing something like a tool-use lookup that genuinely requires it.

Production considerations

Questions

Do I need Anthropic API access directly, or can I use a wrapper? Either works. A direct Anthropic key is fine for a single project; a hosted layer like SubToAPI (/signup) gives you a standard REST endpoint, per-key usage tracking, and team seats if more than one person manages the bot.

Can Claude send images or documents through WhatsApp? Claude can generate text describing content, but actually sending media requires WhatsApp's media message types (image, document) — you'd upload the file to Meta's media endpoint separately and reference it in the outgoing message payload.

How do I handle users texting outside the 24-hour window? You must send a pre-approved WhatsApp template message to re-open the conversation; once the user replies, free-form messages (including Claude-generated ones) work again until the window closes.

Turn your Claude access into an HTTPS API

SubToAPI gives you application API keys, streaming, tool use and usage insights on top of your existing Claude access — set up in minutes.

Start free  Read the quickstart →