Migrate from Evolution API to the official WhatsApp API

In short: to move a bot or an automation from Evolution API in Baileys mode to Meta's official WhatsApp Cloud API, connect the number to ZapClaw through Coexistence, send through ZapClaw's REST API instead of /message/sendText, and read ZapClaw's webhook instead of messages.upsert. The number keeps working in the WhatsApp Business app on your phone. Below: the steps, the text, media and template send fields and the main webhook fields side by side, and what has no equivalent on the official API.

ZapClaw is a hosted gateway on Meta's Cloud API: no Evolution server to keep running and no Meta app of your own.

Business plan: US$ 29 per month, with unlimited numbers

Start for free See the field mapping

Why move to the official API

Meta's policies still apply on the official API: Meta can restrict or disable an account that breaks them, and ZapClaw's API then answers 403 with the reason (errors).

What you need to connect

You do not need a company tax ID or a verified business to connect. The full checklist.

The move, step by step

  1. Map your code first. Change your send calls and your webhook handler with the tables below, or put the shim in front of your flow so it keeps its Evolution calls while you rewrite it.
  2. Back up your chats in the WhatsApp Business app and check the requirements above.
  3. Connect the number. Create your ZapClaw account and connect the number in Meta's window from the dashboard. Meta then unlinks every linked device from the account, so the Evolution instance loses its session. Delete the instance afterwards, so nobody links it again by scanning its QR code and two systems answer the same customer.
  4. Set the webhook. In the dashboard, under Webhook, paste your public HTTPS URL, pick the events and copy the signing secret. Tick Messages sent from the WhatsApp Business app if your flow read messages with fromMe: true.
  5. Create an API key and send with it in the X-API-Key header to https://api.zapclaw.app. The from field names the number, so one key sends from every number of the account.
  6. Create your templates. Outside the 24-hour window, and to write first, Meta accepts only an approved template. Create them in the dashboard or with POST /api/v1/send/templates, and pass language when you send one: the API's default is pt_BR.
  7. Test. Press Send test event on the dashboard's Webhook page, then write to your number from another phone and check that your flow receives the message and replies.

Sending: Evolution API calls and their ZapClaw equivalent

Evolution API v2 as of version 2.3.7, the latest stable release when we checked. Evolution's paths are relative to your Evolution server, and ZapClaw's to https://api.zapclaw.app.

Evolution API v2 ZapClaw
Send text POST /message/sendText/{instance} POST /api/v1/send/text
Send media POST /message/sendMedia/{instance}, plus /sendWhatsAppAudio and /sendSticker POST /api/v1/send/media
Send a template POST /message/sendTemplate/{instance} POST /api/v1/send/template
Authentication apikey header X-API-Key header
Your number The instance, in the path from, in the body
Recipient number: digits with the country code to: digits only, with no @s.whatsapp.net
Text text in the 2.3.7 validator, textMessage.text in the documentation's schema text, up to 4,096 characters
Link preview linkPreview previewUrl
Reply to a message quoted.key.id replyTo: the wamid of the message
Media type mediatype type: image, video, audio, document or sticker
Media file media: a URL or base64 link, a public https URL, or mediaId from POST /api/v1/media
Caption and file name caption, fileName caption (image, video, document), filename (document)
Voice note and sticker audio on /sendWhatsAppAudio, sticker on /sendSticker type audio or sticker (WebP), with link or mediaId
Template fields name, language, components templateName, language, components
Delay and mentions delay, mentioned, mentionsEveryOne No equivalent. POST /api/v1/send/typing shows a typing indicator on a message you received.
Answer key.id, key.remoteJid, status 201 with message.wamid, message.to and message.status

Location, contact cards and reactions go through POST /api/v1/send/location, /send/contacts and /send/reaction (API reference). The shim further down does not convert those calls yet: send them straight to ZapClaw.

Receiving: messages.upsert and its ZapClaw equivalent

Evolution posts event, instance, data, sender and a few more fields; the data paths below are those of a messages.upsert event. ZapClaw posts event, timestamp, data and account to one URL for all your numbers.

Evolution API v2 ZapClaw
Event messages.upsert message.received, also in the X-ZapClaw-Event header
Which of your numbers instance, sender account.phone_number_id, account.display_phone_number
Sender data.key.remoteJid: the number plus @s.whatsapp.net data.from, digits only, and data.user_id, the contact's durable id
Sent by you data.key.fromMe: true A separate message.echo event, with data.to, for messages sent from the WhatsApp Business app or WhatsApp Web (opt-in)
Message id data.key.id data.message_id, a wamid
Contact name data.pushName data.contact_name
Time data.messageTimestamp: seconds, as a number data.timestamp: seconds, as a string
Type data.messageType: conversation, imageMessage, audioMessage and so on data.type: text, image, audio, video, document, sticker and others
Text data.message.conversation data.text.body
Media file data.message.mediaUrl with S3 or MinIO storage on, or data.message.base64 data.<type>.media_url, downloaded with your X-API-Key
Caption and mime type data.message.imageMessage.caption, data.message.imageMessage.mimetype data.image.caption, data.image.mime_type
File name data.message.documentMessage.fileName data.document.filename
Voice note data.message.audioMessage.ptt data.audio.voice
Quoted message data.contextInfo.stanzaId data.context.id
Delivery status messages.update, with SERVER_ACK, DELIVERY_ACK, READ or ERROR message.status, with data.status set to sent, delivered, read or failed
Request authentication None by default. Optional headers of your own, and a jwt_key header becomes a signed Authorization: Bearer token X-ZapClaw-Signature: an HMAC-SHA256 of the raw body, keyed with your signing secret (how to verify it)

A media link from ZapClaw needs your API key, and Meta keeps received media for around 30 days, so download what you want to keep. Deliveries can arrive out of order: when order matters, sort by the top-level sequence.

What has no equivalent, and what to do instead

Keep using the WhatsApp Business app on the phone: Meta disconnects a Coexistence number whose app goes about 14 days without use, and ZapClaw tells your webhook with an account.account_update event (details).

A short adapter

Two functions for Node.js 18 or newer, with no dependency: the first sends where your code called sendText, the second turns a ZapClaw message.received into the messages.upsert fields your flow already reads. Check the X-ZapClaw-Signature header before you trust a body.

// Sending: what was POST /message/sendText/{instance} with an apikey header
const sendText = async ({ number, text }) => {
  const res = await fetch('https://api.zapclaw.app/api/v1/send/text', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'X-API-Key': process.env.ZAPCLAW_API_KEY,
    },
    body: JSON.stringify({ from: process.env.ZAPCLAW_FROM, to: number, text }),
  });
  if (!res.ok) throw new Error(`ZapClaw answered ${res.status}`);
  const { message } = await res.json();
  return { key: { id: message.wamid } }; // where your code read key.id
};

// Receiving: the messages.upsert fields, taken from a message.received body
const fromZapClaw = (body) => ({
  remoteJid: `${body.data.from}@s.whatsapp.net`,
  id: body.data.message_id,
  pushName: body.data.contact_name,
  messageTimestamp: Number(body.data.timestamp),
  conversation: body.data.text ? body.data.text.body : undefined,
});

The full version is on GitHub: zapclaw/migrate-to-whatsapp-official-api converts text, media, templates, statuses and webhooks and ships a small shim. A call it does not convert, such as a location, a contact card or a reaction, is refused with a clear error code: send those calls straight to ZapClaw's API. Point your flow's Evolution base URL at the shim: it forwards the calls it converts to ZapClaw and turns ZapClaw's signed webhooks back into messages.upsert, so you can move first and rewrite later. MIT license.

If you used Evolution's other features

What it costs

Meta bills its WhatsApp message fees to you directly, with no ZapClaw markup. Every plan and price.

Related

Sources

Checked on 15 October 2026. Evolution API changes between versions, so check its documentation for the version you run.

Move your Evolution flows to the official API

Start on the free plan: one number, no card. Move to the Business plan when you need more numbers or more messages.

Start for free Read the webhook docs