Number verification API
WhatsApp number verification results (API)
Read number verification results page by page, filtered by task or by status. Use it to export the numbers that are on WhatsApp, clean invalid numbers out of your contact list or sync results into your CRM.
https://wbiztool.com/api/v1/verification/results/Without filters, it returns every verification in your workspace, newest first. That includes tasks created from the Number verification dashboard page, not only those created through the API.
Quick example#
curl "https://wbiztool.com/api/v1/verification/results/?campaign_id=4521&status=verified&limit=100&offset=0" \
-H "Authorization: Bearer YOUR_API_KEY"import requests
response = requests.get(
"https://wbiztool.com/api/v1/verification/results/",
headers={"Authorization": "Bearer YOUR_API_KEY"},
params={"campaign_id": 4521, "status": "verified", "limit": 100, "offset": 0},
timeout=60,
)
result = response.json() # read the body even when the HTTP code is 4xx or 5xx
if result["status"] == "success":
print(f"{result['returned_count']} of {result['total_count']} results")
for item in result["results"]:
print(item["number"], item["status"])
else:
print(f"Failed ({response.status_code}):", result["message"])// Node.js 18+ (built-in fetch). Save as .mjs to use top-level await.
const url = new URL("https://wbiztool.com/api/v1/verification/results/");
url.search = new URLSearchParams({ campaign_id: "4521", status: "verified", limit: "100", offset: "0" });
const response = await fetch(url, {
headers: { Authorization: "Bearer YOUR_API_KEY" },
});
const result = await response.json(); // read the body even when the HTTP code is 4xx or 5xx
if (result.status === "success") {
console.log(`${result.returned_count} of ${result.total_count} results`);
for (const item of result.results) {
console.log(item.number, item.status);
}
} else {
console.error(`Failed (${response.status}):`, result.message);
}<?php
$query = http_build_query([
'campaign_id' => 4521,
'status' => 'verified',
'limit' => 100,
'offset' => 0,
]);
$ch = curl_init('https://wbiztool.com/api/v1/verification/results/?' . $query);
curl_setopt_array($ch, [
CURLOPT_HTTPHEADER => ['Authorization: Bearer YOUR_API_KEY'],
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 60,
]);
$result = json_decode(curl_exec($ch), true);
curl_close($ch);
if (($result['status'] ?? '') === 'success') {
echo $result['returned_count'] . ' of ' . $result['total_count'] . " results\n";
foreach ($result['results'] as $item) {
echo $item['number'] . ': ' . $item['status'] . "\n";
}
} else {
echo 'Failed: ' . ($result['message'] ?? 'no response');
}Request parameters#
All parameters go in the query string.
Authentication
AuthorizationheaderrequiredBearer YOUR_API_KEY, using a key from Settings → API keys. You can pass the key as anapi_keyquery parameter instead, but the header keeps it out of server and proxy logs.
Filters and pagination
campaign_idintegeroptionalOnly return numbers from this verification task. It must be a verification task in the same workspace as the API key. Leave it out to get results from all tasks.
statusstringoptionalOnly return numbers with this status:
pending,verifiedorinvalid. Any other value is ignored and no status filter is applied, includingunknown, sostatus=unknownreturns every status. Values are case-sensitive:Verifiedis ignored and returns every status.limitintegeroptionalResults per page. Default
100. Use a value of 1 or more.offsetintegeroptionalHow many results to skip. Default
0. Must be 0 or more.
Response#
A successful request returns HTTP 200:
{
"status": "success",
"total_count": 2,
"returned_count": 2,
"limit": 100,
"offset": 0,
"has_more": false,
"results": [
{
"id": 88215,
"campaign_id": 4521,
"campaign_name": "Website leads - September",
"number": "14155550123",
"status": "verified",
"checked_at": "2026-09-16T10:16:26.730114+00:00",
"created_at": "2026-09-16T10:15:00.483101+00:00"
},
{
"id": 88213,
"campaign_id": 4521,
"campaign_name": "Website leads - September",
"number": "919876543210",
"status": "verified",
"checked_at": "2026-09-16T10:16:12.204551+00:00",
"created_at": "2026-09-16T10:15:00.482913+00:00"
}
]
}
| Field | Type | Description |
|---|---|---|
status | string | "success". Errors return "error". |
total_count | integer | Results matching your filters, across all pages. |
returned_count | integer | Results in this response. |
limit | integer | The limit used. |
offset | integer | The offset used. |
has_more | boolean | true if offset + limit is less than total_count, so there's another page. |
results | array | The results, newest first. |
results[].id | integer | ID of this verification record. |
results[].campaign_id | integer or null | ID of the task the number belongs to. |
results[].campaign_name | string or null | Name of that task. |
results[].number | string | The cleaned phone number. |
results[].status | string | pending, verified, invalid, or unknown for a cancelled check. |
results[].checked_at | string or null | When the number was checked, or null while it's pending. |
results[].created_at | string | When the number was added. |
Timestamps are ISO 8601 in UTC with a +00:00 offset. For what each status means, see Number status values.
Errors#
Errors return a JSON body with status set to "error" and an HTTP error code:
{ "status": "error", "message": "Campaign not found" }
| HTTP | Message | How to fix it |
|---|---|---|
405 | Only GET method allowed | Send a GET request. |
401 | API key required | Add the Authorization: Bearer YOUR_API_KEY header. |
401 | Invalid API key | Check the key exists and hasn't been deleted or disabled. |
404 | Campaign not found | The campaign_id doesn't exist, isn't a verification task, or belongs to another workspace. |
500 | Internal server error: … | Usually campaign_id, limit or offset isn't a whole number, offset is negative, or offset + limit is negative. |
Reading every page#
Increase offset by limit until has_more is false.
import requests
numbers, offset, limit = [], 0, 500
while True:
response = requests.get(
"https://wbiztool.com/api/v1/verification/results/",
headers={"Authorization": "Bearer YOUR_API_KEY"},
params={"campaign_id": 4521, "status": "verified", "limit": limit, "offset": offset},
timeout=60,
)
result = response.json()
if result["status"] != "success":
raise RuntimeError(result["message"])
numbers += [item["number"] for item in result["results"]]
if not result["has_more"]:
break
offset += limit
print(len(numbers), "numbers are on WhatsApp")// Node.js 18+ (built-in fetch). Save as .mjs to use top-level await.
const numbers = [];
const limit = 500;
let offset = 0;
while (true) {
const url = new URL("https://wbiztool.com/api/v1/verification/results/");
url.search = new URLSearchParams({ campaign_id: "4521", status: "verified", limit: String(limit), offset: String(offset) });
const response = await fetch(url, { headers: { Authorization: "Bearer YOUR_API_KEY" } });
const result = await response.json();
if (result.status !== "success") throw new Error(result.message);
numbers.push(...result.results.map((item) => item.number));
if (!result.has_more) break;
offset += limit;
}
console.log(numbers.length, "numbers are on WhatsApp");Tips#
- De-duplicate by
idwhen paging. Results are sorted by creation time, newest first. Numbers from the same task share almost the same timestamp and new verifications can be added while you page, so a row can appear on two pages or be skipped. Filtering bycampaign_idand waiting for the task to finish reduces this. - Wait for completion before exporting. Check Verification status until
overall_statusiscompleted, or handlependingresults in your code. - Clean your contact list by exporting
status=invalidand removing those numbers before your next campaign. - Page size: there's no maximum
limit, but a very large page makes a large, slow response.
