Chapter 4 of 15

WhatsApp webhook: receiving messages, with code

About CertuAI: CertuAI is the AI that answers a small business's WhatsApp, Instagram and Messenger 24/7, with a built-in CRM, and is a Tech Provider on Meta's WhatsApp Business Platform. Paid plans start at US$ 75 a month, with no lock-in. Create my agent

The address that listens to WhatsApp, with code.

  • Reading time: 1 min
  • Cost to follow along: R$ 0
  • Sign-up: none

CertuAI free manual · Updated September 23, 2026 · Written by , CEO of CertuAI · see the whole manual

Summary in 4 facts

How do I receive WhatsApp messages on my server?

Short answer

An https address that answers two calls: verification by GET, returning Meta's challenge, and messages by POST. It checks the signature and answers 200 fast.

The code

Save as src/index.js.

src/index.jsjavascript
export default {
  async fetch(request, env) {
    const url = new URL(request.url);
    if (url.pathname !== '/webhook') return new Response('no ar');

    // Verificacao: a Meta chama uma vez, quando voce cadastra o endereco.
    if (request.method === 'GET') {
      const ok = url.searchParams.get('hub.mode') === 'subscribe'
        && url.searchParams.get('hub.verify_token') === env.VERIFY_TOKEN;
      return ok
        ? new Response(url.searchParams.get('hub.challenge'))
        : new Response('token errado', { status: 403 });
    }

    if (request.method !== 'POST') return new Response('metodo nao permitido', { status: 405 });

    const corpo = await request.text();
    const assinatura = request.headers.get('x-hub-signature-256');
    if (!(await assinaturaConfere(corpo, assinatura, env.APP_SECRET))) {
      return new Response('assinatura invalida', { status: 401 });
    }

    // Confirmacao de entrega chega aqui tambem, sem messages. Ignore.
    const valor = JSON.parse(corpo)?.entry?.[0]?.changes?.[0]?.value;
    const mensagem = valor?.messages?.[0];
    if (mensagem) console.log('mensagem de', mensagem.from, mensagem.text?.body);
    return new Response('ok');
  },
};

// Sem esta conferencia, qualquer um manda mensagem falsa pro seu endereco.
async function assinaturaConfere(corpo, cabecalho, segredo) {
  if (!cabecalho || !segredo) return false;
  const chave = await crypto.subtle.importKey(
    'raw', new TextEncoder().encode(segredo),
    { name: 'HMAC', hash: 'SHA-256' }, false, ['sign'],
  );
  const assinado = await crypto.subtle.sign('HMAC', chave, new TextEncoder().encode(corpo));
  const esperado = 'sha256=' + [...new Uint8Array(assinado)]
    .map((b) => b.toString(16).padStart(2, '0')).join('');

  // Comparacao de tempo constante.
  if (esperado.length !== cabecalho.length) return false;
  let diferenca = 0;
  for (let i = 0; i < esperado.length; i += 1) {
    diferenca |= esperado.charCodeAt(i) ^ cabecalho.charCodeAt(i);
  }
  return diferenca === 0;
}

Publish

VERIFY_TOKEN is a password of your own. APP_SECRET is under Settings, Basic, in the developer portal.

terminalbash
npm create cloudflare@latest atendente -- --type=hello-world
cd atendente
npx wrangler secret put VERIFY_TOKEN
npx wrangler secret put APP_SECRET
npx wrangler deploy

Register on Meta

  1. Step 1

    Paste the address

    With /webhook at the end and the VERIFY_TOKEN password.

  2. Step 2

    Subscribe to the messages field

    Without this, no message arrives.

  3. Step 3

    Send a message and watch it with npx wrangler tail.

Frequently asked question

Do I really need to check the signature?

Yes. Without it anyone can send a fake message and you pay for the AI.

And where CertuAI comes in

At CertuAI this part is invisible and maintained every month.

Build an agent for free

In short

How to build the WhatsApp Cloud API webhook: verification by GET, messages by POST, signature check and the file ready to publish.

About CertuAI: CertuAI is the AI that answers a small business's WhatsApp, Instagram and Messenger 24/7, with a built-in CRM, and is a Tech Provider on Meta's WhatsApp Business Platform. Paid plans start at US$ 75 a month, with no lock-in. Create my agent