# WhatsApp list hygiene for marketing agencies

> Agencies running WhatsApp campaigns for clients: remove invalid, duplicate and unregistered numbers from opted-in lists before paying for template messages.

Canonical: https://mobilevalidate.com/use-cases/whatsapp-marketing-agencies · Last updated: 2026-11-08

![A phone with chat bubbles; one messaging-app check says registered, another is unknown.](https://mobilevalidate.com/images/messaging-app-registration-check.svg)

*Messaging-app checks answer registered, not registered or unknown, with the time we checked.*


Agencies that run WhatsApp campaigns for clients check each opted-in list before paying for template messages. A bulk job removes invalid and duplicate numbers for free, then marks which numbers have a WhatsApp account and which are Business accounts. You budget, segment and choose fallback channels on numbers that can receive the campaign. The client's opt-in still decides who may be messaged.

## Why check a client's list before the campaign?

Client lists arrive in every shape: exports from a shop, a CRM, event sign-ups, a loyalty program. They mix national and international formats, contain the same person twice and include landlines and old numbers. On WhatsApp, Meta charges per delivered template message by category and recipient country ([WhatsApp Business pricing in 2026](/blog/whatsapp-business-api-pricing-2026) has the details). An unchecked list still costs the agency in other ways:

- **Budgets built on the wrong count.** A list of 80,000 rows may hold far fewer reachable WhatsApp contacts. Quoting a client on the raw count sets the wrong expectation.
- **Failed sends and skewed reports.** Messages to numbers without an account fail. Delivery and read rates then look worse than the campaign deserves.
- **Quality signals.** Sending to people who don't recognise the sender leads to blocks and reports, which can lower the sender number's quality rating and messaging limits.
- **Wasted creative and approval work** on segments that turn out to be tiny.

Two cleaning steps are free: invalid numbers and duplicates are flagged after [E.164](/glossary/e164) normalization and never charged. The [WhatsApp check](/services/whatsapp-number-check) then answers `registered` or not per number, and the [WhatsApp Business check](/services/whatsapp-business-check) adds a `business` flag.

## How does the workflow look?

1. **Confirm the basis.** Before you touch a list, get the client's written confirmation that the contacts opted in to WhatsApp messages from that brand and that its lawful basis covers checking their WhatsApp accounts (see the consent section below).
2. **Normalize for free.** Paste a sample into the free [phone list cleaner](/tools/phone-list-cleaner), which formats and de-duplicates numbers in your browser, or let the job do it with `default_country` for national formats.
3. **Estimate.** Run the free `POST /v1/jobs/estimate` with `checks: ["whatsapp.business"]` (or `["whatsapp"]`). It counts valid, invalid, duplicate, cached and suppressed rows and returns the maximum cost. Upload a CSV in the [dashboard](/docs/dashboard) instead if you don't use the API.
4. **Run the job** with `POST /v1/jobs`, the estimate as `max_cost`, the client's API key and a client reference in `metadata`.
5. **Download** CSV or NDJSON. Each line keeps its `row_no`, the input's position in your upload, so you join results back to the client's file by row number. Numbers are masked in the file (`+44770*****01`) with the normalized `e164` alongside.
6. **Segment.** Registered, opted-in contacts go to the WhatsApp send. Others stay on the channels they agreed to, such as SMS or e-mail. [Viber](/services/viber-number-check) is available as a bulk check where the client's audience uses it.
7. **Budget.** Put the registered count into the free [WhatsApp cost calculator](/tools/whatsapp-cost-calculator) with the recipient country and template category to quote the campaign.
8. **Delete.** Purge the job's results with `DELETE /v1/jobs/{id}` once the segments are built, or let the retention period (30 days by default) expire.

Repeat campaigns for the same client inside the freshness window are answered from your account's cache for free.

## Which checks should you use?

| Check | What it answers | When to use it | Link |
|---|---|---|---|
| Format and duplicates (free) | Is the number possible? Is it a repeat? | Every list | [Phone list cleaner](/tools/phone-list-cleaner) |
| `whatsapp` | Does the number have a WhatsApp account? | Before every template campaign | [WhatsApp check](/services/whatsapp-number-check) |
| `whatsapp.business` | Account, and is it a Business account? | Consumer campaigns where business numbers should be reviewed | [WhatsApp Business check](/services/whatsapp-business-check) |
| `viber`, `telegram` | Is the number on another app? | Fallback for contacts who opted in there | [Viber](/services/viber-number-check), [Telegram](/services/telegram-number-check) |
| `carrier` | Mobile, fixed line or VoIP? | Planning an SMS fallback | [Carrier lookup](/services/carrier-lookup) |

## What should you do with each result?

| Result | Suggested action |
|---|---|
| `number_status: invalid_number` | Return to the client for correction; not checked, not charged |
| `number_status: duplicate` | Keep one row per person; not charged |
| `registered: true`, `business: false`, opted in | Include in the WhatsApp send |
| `registered: true`, `business: true` | Review: often a shop or company phone in a consumer list |
| `registered: false` | Leave out of the WhatsApp send; use the channels the contact agreed to |
| `unknown` | Keep the contact as it was; unknown is free and says nothing bad |
| Suppressed (opt-out) | Skipped and never charged; don't re-add it |

## What does a request look like?

This bulk job uses the public sandbox key from the [test values](/docs/test-values) page, so you can run it as is. It holds four test numbers and the first one again without its `+`.

```bash
curl https://api.mobilevalidate.com/v1/jobs \
  -H "Authorization: Bearer mv_test_publicSandboxn9ZgneuhR1B9CRfKG3fulym" \
  -H "Content-Type: application/json" \
  -d '{"numbers": ["+447700900001", "+447700900002", "+447700900006", "+447700900003", "447700900001"], "checks": ["whatsapp", "whatsapp.business"], "metadata": {"client": "client-a"}}'
```

Response (excerpt, test mode):

```json
{"object": "job", "id": "job_0VaLWhF3ddVUBwzqBXr2", "status": "completed", "livemode": false,
 "checks": ["whatsapp.business"],
 "progress": {"total": 5, "checks_total": 5, "done": 5, "conclusive": 3, "non_billable": 5},
 "cost": {"breakdown": [
   {"check": "whatsapp.business", "price_mode": "batch", "reason": null, "checks": 0,
    "unit_price": {"amount": "0.0003", "currency": "USD"}, "max_cost": {"amount": "0", "currency": "USD"}},
   {"check": "whatsapp.business", "price_mode": "realtime", "reason": "small_batch", "checks": 4,
    "unit_price": {"amount": "0.004", "currency": "USD"}, "max_cost": {"amount": "0", "currency": "USD"},
    "countries": ["GB"], "batch_minimum": 132}]},
 "retention_days": 30, "metadata": {"client": "client-a"}}
```

Two things show here. The job ran only `whatsapp.business`, because the business check already answers whether an account exists, so you pay one check per number. And four UK numbers are fewer than 132 per country, so they sit on a `small_batch` line at the real-time price; a real campaign list gets the bulk price. Sandbox jobs are never billed.

The download (`GET /v1/jobs/{id}/download?format=csv`):

```text
row_no,input_masked,e164,country,number_status,service,status,registered,business,checked_at,cached,billed,kind,email,email_status,whatsapp.business.status,whatsapp.business.registered,whatsapp.business.business,whatsapp.business.billed
1,"'+44770*****01",+447700900001,GB,valid,whatsapp.business,completed,true,false,2026-11-08T02:49:40.848Z,false,false,phone,,,completed,true,false,false
2,"'+44770*****02",+447700900002,GB,valid,whatsapp.business,completed,false,false,2026-11-08T02:49:40.848Z,false,false,phone,,,completed,false,false,false
3,"'+44770*****06",+447700900006,GB,valid,whatsapp.business,completed,true,true,2026-11-08T02:49:40.848Z,false,false,phone,,,completed,true,true,false
4,"'+44770*****03",+447700900003,GB,valid,whatsapp.business,unknown,,,,false,false,phone,,,unknown,,,false
5,"'+44770*****01",+447700900001,GB,duplicate,,,,,,false,false,phone,,,,,,
```

Row 1 goes to the WhatsApp send, row 2 stays on the client's other channels, row 3 is a Business account to review, row 4 is unknown (free) and row 5 is a duplicate of row 1 (free). Join on `row_no` to put the segments back into the client's file.

## How much does it cost?

As of 8 November 2026, the live catalog lists these prices per conclusive answer:

| Check | Real time | Bulk |
|---|---|---|
| WhatsApp (`whatsapp`) | $0.004 | $0.00025 |
| WhatsApp Business (`whatsapp.business`) | $0.004 | $0.0003 |
| Telegram (`telegram`) | $0.001 | $0.0003 |
| Viber (`viber`) | bulk only | $0.00015 |
| Carrier lookup (`carrier`) | $0.003 | $0.0015 |

So a 50,000-number list of one country costs at most $12.50 for the WhatsApp check, or $15 with the business flag, before free invalid, duplicate, cached and unknown rows are taken off. Bulk prices for WhatsApp apply to groups of at least 132 numbers per country. Viber is bulk only, and bulk-only checks are billed at least the price of 500 checks for each country that returns an answer. Current prices are on the [pricing page](/pricing); top-ups get a bonus of +5% from $100, +8% from $500 and +10% from $2,000.

To test with real numbers first, every account can run 20 phone numbers and 10 e-mail addresses through the real-time checks for free on the dashboard's Try it page. [Request access](/request-access): approval is automatic, usually within 10–15 minutes.

## How do you run jobs for several clients?

Keep each client separate from the first request:

- **One key per client.** Create a live key for each client in the dashboard and name it after the client. An account can have up to 25 active keys, and live keys can be limited to your server IP addresses. Revoke a key when the engagement ends.
- **Client reference in `metadata`.** Every job echoes its `metadata` back, so the job object carries the client reference.
- **Logs by key.** Request logs filter by key, so you can see each client's jobs; the Usage page shows checks and cost by day and service.
- **Spend caps.** Pass `max_cost` on every job, set from the estimate, so a wrong file can't overspend.
- **Own account where the client pays.** If a client wants its own balance and invoices, it can open its own account with us, so its checks are billed to it directly.

## Can you give clients the results or sell list checks?

Checking a list so you can run the client's campaign is part of delivering your service. Handing the results themselves to clients, selling list cleaning as a product, or letting clients run checks through your account goes further. Section 18.2 of the [Terms](/legal/terms) says results and the service may not be resold or made available to third parties without our written agreement. There is no self-serve reseller program; e-mail [sales@mobilevalidate.com](mailto:sales@mobilevalidate.com) with your client volume to agree terms.

## What about consent and lawful basis?

The contacts belong to your client, and so does the lawful basis for messaging them and for checking them:

- **Opt-in for the brand.** WhatsApp's business messaging policy requires that people gave the business their number and opted in to its messages. A registered answer is not consent. Our guide to [WhatsApp number checks, consent and the law](/blog/whatsapp-number-checks-consent-and-law) covers the rules.
- **Specific authority to check.** Our [acceptable use policy](/legal/acceptable-use) requires that the lawful basis covers checking a person's account on a named app. A general marketing opt-in is not enough. Ask the client to confirm this in writing.
- **Your role.** The client usually decides the purpose; the agency processes on its instructions. Put that in your contract and data processing terms, and sign our [DPA](/legal/dpa) for your account.
- **No list building.** Don't check bought, scraped or generated lists, and don't use checks to find new people to message. Requests with 20 or more consecutive numbers are refused as enumeration.
- **Objections.** People can exclude their number through the [opt-out form](/opt-out); suppressed numbers are skipped and never charged.

## What are the common mistakes?

- **Treating `registered: true` as permission.** It says an account exists, nothing more.
- **Ordering `whatsapp` and `whatsapp.business` separately.** The business check covers both; you pay once.
- **Splitting a country into small jobs.** Below 132 numbers per country the real-time price applies. Send one job per client list.
- **Joining results by phone number in a spreadsheet.** Formats differ; join on `row_no`.
- **Deleting contacts without WhatsApp.** They may be reachable by SMS or e-mail on the channels they chose.
- **Keeping results forever.** Build the segments, then purge the job.
- **Mixing clients on one key.** Separate keys keep logs, revocation and disputes clean.

For template text, the free [WhatsApp text formatter](/tools/whatsapp-text-formatter) previews bold, italic and monospace before you submit a template for approval.

## Frequently asked questions

### Why check a client's list before a WhatsApp campaign?

WhatsApp charges per delivered template message, but an unclean list still costs you: failed sends, skewed reports and wasted setup work. A bulk check removes invalid and duplicate rows for free and flags numbers without a WhatsApp account, so you plan volume, budget and fallback channels on numbers that can actually receive the campaign.

### Does a WhatsApp account mean the contact agreed to messages?

No. A registered answer only says an account exists. WhatsApp's business messaging policy separately requires the person's opt-in for the business that sends. The opt-in, and the lawful basis for checking, belong to your client and must cover these contacts.

### Who is responsible for consent, the agency or the client?

The client collected the contacts, so it usually decides the purpose and holds the opt-in records. The agency acts on its instructions. Put that in your contract and data processing terms, and only check lists the client confirms were collected lawfully for this purpose.

### How do I keep each client's jobs and spend apart?

Create one API key per client and name it after the client, and add the client's reference in each job's metadata. The request logs filter by key, and results come back per job. An account can have up to 25 active keys.

### What is the WhatsApp Business check for?

It returns whether the number has WhatsApp and whether the account is a Business account. In consumer campaigns, business accounts are often shops or company phones, so many agencies review them before sending. You pay for one check per number even if you also ask for the plain WhatsApp check.

### Can I give my clients the cleaned list or a check report?

Handing results to third parties, or selling list checks as a service, needs a written agreement with us under section 18.2 of the Terms. E-mail sales@mobilevalidate.com before you offer it.

### How many numbers do I need per country for the bulk price?

WhatsApp checks get the bulk price for groups of at least 132 numbers from one country in one job. Smaller groups are priced at the real-time price. The free estimate shows this as a small_batch line before you start.

### Is a number without WhatsApp a bad contact?

Not necessarily. The person may prefer SMS or e-mail. Keep the contact for the channels they agreed to and leave it out of the WhatsApp send.
