Dev

Validate a WhatsApp number via API: how to know if a number has WhatsApp

To find out whether a number has WhatsApp through an API, call the instance verification endpoint with the list of numbers: for each one it returns whether it is registered on WhatsApp and its identifier (JID). This is different from validating the format, which only checks country code, area code and digit count. The two steps together stop you from sending to numbers that do not exist, which causes errors, wastes time and worsens your sending history.

Published on · 3 min read

This article is also available in: Português · Español

Two different validations: format and existence

Format: does the number have a country code, a valid area code and the right digit count? It is a text rule that runs in your browser or server without asking anyone. The free WhatsApp number validator and the bulk formatter do this, including the ninth digit of Brazilian mobiles.

Existence: is that number, even if well formed, registered on WhatsApp right now? Only a query to WhatsApp answers it. That is why the format tool warns that it does not confirm the account exists, and the check comes through the API.

The verification endpoint

In the ZapZap API, the endpoint is POST /api/v1/{instanceId}/chat/check, with the numbers field as a list. The answer carries, for each queried number, the query field (what you sent), isInWhatsapp (true or false) and jid (the conversation identifier). The full description is in the endpoint reference.

Send the number in the same format as sending: country code and digits only. Check the answer format with two numbers of your own before wiring this into your flow.

curl: verificar números

# Does this number have WhatsApp?
curl -X POST "https://api.zapzapapi.com/api/v1/$ZAPZAP_INSTANCE/chat/check" \
  -H "Content-Type: application/json" \
  -H "x-api-key: $ZAPZAP_API_KEY" -H "x-api-secret: $ZAPZAP_API_SECRET" \
  -d '{"numbers":["5511999999999","5521888888888"]}'
# Each item of the answer carries: query, isInWhatsapp (true/false) and jid

A Node filter for lists

The example normalizes the format (digits only, country code 55 when missing, dropping what cannot be a Brazilian number), removes duplicates, queries in small batches with a pause and returns only those with WhatsApp. The result feeds the next send and reduces errors.

The normalization rule is simple on purpose. For edge cases, such as the ninth digit on older numbers, use the site formatter as a reference.

Node.js: filtrar lista

// Validate a small batch before sending, keep only numbers that exist
const API = "https://api.zapzapapi.com/api/v1/" + process.env.ZAPZAP_INSTANCE;
const headers = {
  "Content-Type": "application/json",
  "x-api-key": process.env.ZAPZAP_API_KEY,
  "x-api-secret": process.env.ZAPZAP_API_SECRET,
};

export function normalizeBr(raw) {
  // 1) digits only, 2) add country code 55 when missing, 3) reject what cannot be a Brazilian number
  let d = String(raw).replace(/\D/g, "");
  if (d.length === 10 || d.length === 11) d = "55" + d;
  return /^55\d{10,11}$/.test(d) ? d : null;
}

export async function filterWhatsApp(rawNumbers) {
  const numbers = [...new Set(rawNumbers.map(normalizeBr).filter(Boolean))];
  const ok = [];
  for (let i = 0; i < numbers.length; i += 20) {           // small batches
    const batch = numbers.slice(i, i + 20);
    const r = await fetch(API + "/chat/check", { method: "POST", headers, body: JSON.stringify({ numbers: batch }) });
    if (!r.ok) throw new Error("check failed: HTTP " + r.status);
    const items = await r.json();
    for (const it of items) if (it.isInWhatsapp) ok.push({ number: it.query, jid: it.jid });
    await new Promise((res) => setTimeout(res, 3000 + Math.random() * 4000)); // pause between batches
  }
  return ok;
}

Care: treat the check as if it were a send

Querying thousands of numbers at once, in a burst, is an unusual behavior pattern. We have no published limit for this endpoint, so the prudent advice is the same as for sending: small batches, a pause between them and nothing in parallel. If your list is large, validate the format first (free, local) and only query existence for those that passed.

Store the result with the query date. A number that had WhatsApp today may not tomorrow, and a number without WhatsApp may be created later. And remember that having WhatsApp does not mean consenting to receive your message: see LGPD on WhatsApp.

Where to fit it in your flow

The most useful point is sign-up: validate when the lead types the phone and warn right away if the number has no WhatsApp, instead of finding out at send time. The second is cleaning an old list before reactivating it. In both, combine it with warm-up and gradual volume.

If you use n8n, the endpoint fits in an HTTP Request node before the send node. The guide to WhatsApp in n8n shows the flow design.

Quick summary

  • A valid format does not prove the number has WhatsApp: they are two validations.
  • POST /chat/check with the numbers list returns isInWhatsapp and jid for each number.
  • Validate the format locally first and query existence in small batches, with a pause.
  • Having WhatsApp is not consent: respect LGPD and opt-in.

Also read

Frequently asked questions

How do I check whether a number has WhatsApp via API?

POST to /api/v1/{instanceId}/chat/check with the numbers field (a list). Each item in the answer carries query, isInWhatsapp and jid.

What is the difference between validating the format and checking the number?

Validating the format checks country code, area code and digits, and runs locally. Checking the number queries WhatsApp to see whether an account is registered. A correct format does not guarantee the account exists.

Does the free tool on the site confirm the number has WhatsApp?

No. It validates and formats the number (E.164, ninth digit, wa.me link) in the browser and warns that it does not confirm the account exists. For that, use the verification API.

Can I check a whole list at once?

We do not recommend it. Burst queries are unusual behavior and there is no published limit for the endpoint. Use small batches, a pause between them and validate the format first.

Does checking a number use a message or cost per query?

ZapZap pricing is per active number per month, with no per-message fee, and the pricing page lists no per-query rate. Check the current price before building a large volume.

Validate before you send

Use the free tool for the format and the API for existence. R$15 per active number per month, no per-message fee.