← Blog

Claude API WhatsApp Integration Guide

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

Connecting the Claude API to WhatsApp means wiring together three things: the WhatsApp Business API (which receives and sends messages), a webhook server you control, and a call to Claude that generates the reply text. There's no native "WhatsApp connector" shipped by Anthropic — you build a thin relay layer between Meta's messaging infrastructure and Claude's completion API.

This guide walks through that relay layer end to end: registering a WhatsApp Business number, building a webhook that receives incoming messages, calling Claude to generate a response, and sending that response back through WhatsApp. It also covers the parts people usually get wrong — webhook verification, conversation context, and per-user rate limiting.

Architecture Overview

The flow looks like this:

  1. A user sends a WhatsApp message to your business number.
  2. Meta's WhatsApp Cloud API POSTs that message to your webhook URL.
  3. Your server extracts the message text, builds a prompt (optionally with prior conversation history), and calls the Claude API.
  4. Claude returns a response.
  5. Your server sends that response back to the user via the WhatsApp Cloud API's "send message" endpoint.

There's no persistent connection and no streaming to the end user — WhatsApp messages are discrete request/response pairs, so you wait for Claude's full completion before replying.

Prerequisites

Step 1: Set Up the WhatsApp Business API

In the Meta for Developers dashboard, create a WhatsApp product under your app, note the Phone Number ID and generate a temporary (or permanent, via a system user) access token. You'll also set a webhook verify token — an arbitrary string Meta uses to confirm you own the endpoint.

Meta will send a GET request to your webhook URL during setup:

GET /webhook?hub.mode=subscribe&hub.verify_token=YOUR_TOKEN&hub.challenge=12345

Your server must echo back hub.challenge if the token matches:

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

Step 2: Receive Incoming Messages

Incoming messages arrive as POST requests to the same webhook path. The payload is nested, so extract the text and sender ID carefully:

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

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

  res.sendStatus(200); // acknowledge immediately, respond to WhatsApp async
});

Always return a 200 quickly — Meta retries if your webhook doesn't acknowledge within a few seconds, which can cause duplicate processing if your Claude call is slow.

Step 3: Call Claude and Generate a Reply

Once you have the message text, send it to Claude. If you're using SubToAPI, the call looks like this:

async function handleIncomingMessage(from, text) {
  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-3-5-sonnet-20241022",
      max_tokens: 500,
      messages: [{ role: "user", content: text }]
    })
  });

  const data = await response.json();
  const reply = data.content[0].text;
  await sendWhatsAppMessage(from, reply);
}

The /v1/messages endpoint mirrors the standard message format — see /docs/messages for the full schema, and /docs/quickstart if this is your first integration.

Step 4: Send the Reply Back Through WhatsApp

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

That's a working loop: message in, Claude response out.

Handling Conversation History

WhatsApp doesn't track conversation state for you. For multi-turn context, store recent messages per phone number (Redis or a simple database table works fine) and replay them as the messages array on each call:

const history = await getHistory(from); // array of { role, content }
history.push({ role: "user", content: text });

const data = await callClaude(history);
history.push({ role: "assistant", content: data.content[0].text });
await saveHistory(from, history.slice(-20)); // cap history length

Trim history aggressively — WhatsApp conversations run long and token costs add up fast if you replay the full thread every message.

Production Considerations

questions

Does Claude have a built-in WhatsApp integration? No. Anthropic doesn't offer a native WhatsApp connector. You build a webhook server that receives messages from the WhatsApp Business API and forwards them to Claude's messages endpoint, then sends the response back through WhatsApp's send-message API.

Can I stream Claude's response into WhatsApp? No — WhatsApp messages are sent as complete units, not token-by-token. You wait for Claude's full response before calling the send-message API. Streaming (see /docs/streaming) is useful for web or app UIs, not WhatsApp.

How do I handle multiple users chatting at once? Key your conversation state (history, rate limits) by WhatsApp phone number, not globally. Each incoming webhook payload includes the sender's number — use it to look up and update that user's context independently.

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 →