API v2 (beta)
Numbers
A number is a WhatsApp number or a Telegram account connected to your workspace. Its id is the from you send messages with. With API v2 you list them, see whether each one is connected, and connect a WhatsApp number from your own app, by QR code or pairing code.
| Operation | Endpoint | Scope |
|---|---|---|
| List numbers | GET /api/v2/numbers | numbers |
| Get a number | GET /api/v2/numbers/{id} | numbers |
| Connect a WhatsApp number | POST /api/v2/numbers | numbers |
A key limited to some numbers sees and reconnects only those, and can't add a number.
List numbers#
https://wbiztool.com/api/v2/numbersAll the workspace's numbers, oldest first, in one data list (no pages).
curl https://wbiztool.com/api/v2/numbers \
-H "Authorization: Bearer $WBIZTOOL_API_KEY"import os
import requests
response = requests.get(
"https://wbiztool.com/api/v2/numbers",
headers={"Authorization": f"Bearer {os.environ['WBIZTOOL_API_KEY']}"},
timeout=30,
)
for number in response.json()["data"]:
print(number["id"], number["phone"], number["label"], number["status"])// Node.js 18+ (built-in fetch). Save as .mjs to use top-level await.
const response = await fetch("https://wbiztool.com/api/v2/numbers", {
headers: { Authorization: `Bearer ${process.env.WBIZTOOL_API_KEY}` },
});
const { data } = await response.json();
for (const number of data) console.log(number.id, number.phone, number.label, number.status);<?php
$ch = curl_init('https://wbiztool.com/api/v2/numbers');
curl_setopt_array($ch, [
CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('WBIZTOOL_API_KEY')],
CURLOPT_RETURNTRANSFER => true,
]);
$numbers = json_decode(curl_exec($ch), true)['data'];
curl_close($ch);
foreach ($numbers as $number) {
echo $number['id'] . ' ' . $number['phone'] . ' ' . $number['status'] . "\n";
}{
"data": [
{
"id": 101,
"phone": "919800000000",
"label": "Shop",
"platform": "whatsapp",
"status": "connected",
"login_method": "qr",
"connect": null
},
{
"id": 102,
"phone": null,
"label": "",
"platform": "whatsapp",
"status": "disconnected",
"login_method": "qr",
"connect": null
}
]
}
connect is always null in the list. To follow a connection, get the number.
Get a number#
https://wbiztool.com/api/v2/numbers/{id}One number. While it's connecting, connect has the QR code to scan or the pairing code to type.
curl https://wbiztool.com/api/v2/numbers/102 \
-H "Authorization: Bearer $WBIZTOOL_API_KEY"
{
"id": 102,
"phone": null,
"label": "",
"platform": "whatsapp",
"status": "connecting",
"login_method": "qr",
"connect": {
"qr_code_url": "https://…/qr_codes/…png?X-Amz-Signature=…",
"pairing_code": null,
"pairing_code_expires_at": null,
"linking": false,
"requested_at": "2026-10-18T11:02:15.402Z"
}
}
A number that doesn't exist, or that the key may not use, answers 404 number_not_found.
The Number object#
| Field | Type | Description |
|---|---|---|
id | integer | The number's id: the from of a message or reminder. |
phone | string or null | Its digits with the country code, no +, such as 919800000000. null for a new number connected by QR until the QR code is scanned. |
label | string | Its name in the dashboard; "" when it has none. |
platform | string | whatsapp or telegram. |
status | string | connected, connecting (a connection was asked for in the last 10 minutes and is still going) or disconnected. |
login_method | string | How it connects: qr or phone_code (a pairing code). |
connect | object or null | While status is connecting, and only from Get a number; null otherwise. |
connect has:
| Field | Type | Description |
|---|---|---|
qr_code_url | string or null | A link to the QR code image to scan. Each call gives a new link, valid for 10 minutes; null until the server has the QR code. |
pairing_code | string or null | For phone_code: the code to type on the phone. null until it's ready. |
pairing_code_expires_at | string or null | When the pairing code stops working. |
linking | boolean | true once the QR code was scanned or the code accepted, while WhatsApp finishes linking. |
requested_at | string or null | When the connection was asked for. |
Messages sent with a disconnected number as from are still accepted: they wait and go out when it's connected again. Webhook events for numbers come later; until then, poll GET /numbers to notice a number that was logged out.
Connect a WhatsApp number#
https://wbiztool.com/api/v2/numbersBody: JSON (application/json)
Asks a WbizTool server to open WhatsApp for a number, so you can link it from your own app or website, as you would on WhatsApp numbers. The answer is 202 with the Number, in status connecting. Then poll it until it's connected.
It needs a plan that includes the QR code API; otherwise it answers 403 plan_required. Telegram accounts are connected in the dashboard, not here.
Body
login_methodstringoptionalqr(default): scan a QR code.phone_code: type a pairing code on the phone instead, handy when the phone is the only screen.phonestringRequired for phone_codeThe WhatsApp number to link, in international format with
+, such as+919876543210. Not used withqr: the number is read from WhatsApp after the scan.number_idintegeroptionalReconnect this existing number instead of adding a new one, for example after it was logged out.
# By QR code
curl -X POST https://wbiztool.com/api/v2/numbers \
-H "Authorization: Bearer $WBIZTOOL_API_KEY" \
-H "Content-Type: application/json" \
-d '{"login_method": "qr"}'
# By pairing code, reconnecting number 101
curl -X POST https://wbiztool.com/api/v2/numbers \
-H "Authorization: Bearer $WBIZTOOL_API_KEY" \
-H "Content-Type: application/json" \
-d '{"login_method": "phone_code", "phone": "+919876543210", "number_id": 101}'import os
import time
import requests
API = "https://wbiztool.com/api/v2"
headers = {"Authorization": f"Bearer {os.environ['WBIZTOOL_API_KEY']}"}
number = requests.post(f"{API}/numbers", headers=headers,
json={"login_method": "phone_code", "phone": "+919876543210"}, timeout=30).json()
shown = None
while number["status"] == "connecting":
time.sleep(3)
number = requests.get(f"{API}/numbers/{number['id']}", headers=headers, timeout=30).json()
code = (number["connect"] or {}).get("pairing_code")
if code and code != shown:
print("On the phone: WhatsApp → Linked devices → Link with phone number, then type", code)
shown = code
print("Number", number["id"], "is", number["status"])// Node.js 18+ (built-in fetch). Save as .mjs to use top-level await.
const API = "https://wbiztool.com/api/v2";
const headers = { Authorization: `Bearer ${process.env.WBIZTOOL_API_KEY}`, "Content-Type": "application/json" };
let number = await (await fetch(`${API}/numbers`, {
method: "POST", headers, body: JSON.stringify({ login_method: "qr" }),
})).json();
let shown = null;
while (number.status === "connecting") {
await new Promise((r) => setTimeout(r, 3000));
number = await (await fetch(`${API}/numbers/${number.id}`, { headers })).json();
const qr = number.connect?.qr_code_url;
if (qr && qr !== shown) {
console.log("Show this QR code to scan:", qr); // e.g. in an <img> on your page
shown = qr;
}
}
console.log(`Number ${number.id} is ${number.status}`);<?php
$ch = curl_init('https://wbiztool.com/api/v2/numbers');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('WBIZTOOL_API_KEY'), 'Content-Type: application/json'],
CURLOPT_POSTFIELDS => json_encode(['login_method' => 'qr']),
CURLOPT_RETURNTRANSFER => true,
]);
$number = json_decode(curl_exec($ch), true);
curl_close($ch);
// Save $number['id'], then poll GET /api/v2/numbers/{id} every few seconds (see The connect flow).
echo $number['id'] . ' ' . $number['status'];The connect flow#
Ask for the connection
POST /numberswithlogin_method(andphonefor a pairing code). Keep theidfrom the answer. Send anIdempotency-Keyso a retry doesn't ask twice.Poll the number every few seconds
GET /numbers/{id}every 2 to 5 seconds whilestatusisconnecting. The QR code or pairing code appears inconnectwithin moments; until then its fields arenull.Show the QR code or the pairing code
QR: show the image at
connect.qr_code_url; on the phone, open WhatsApp → Linked devices → Link a device and scan it. Each link works for 10 minutes and a new one comes with every poll, so show the newest each time. Pairing code: on the phone, open WhatsApp → Linked devices → Link a device → Link with phone number instead, and type the 8-characterconnect.pairing_codebeforeconnect.pairing_code_expires_at(about 3 minutes).Wait for connected
After the scan or the code,
connect.linkingistruewhile WhatsApp finishes linking. Thenstatusbecomesconnectedandphoneshows the number. Stop polling.
If nothing happens for 10 minutes, the attempt ends and status goes back to disconnected. Ask again with POST /numbers and its number_id.
While a number is being connected, another request for it answers 409 connect_in_progress with its number_id: keep polling that one instead.
Errors when connecting#
| HTTP | Code | When |
|---|---|---|
400 | validation_failed | login_method isn't qr or phone_code, or phone_code without phone |
403 | plan_required | The plan doesn't include the QR code API |
403 | number_limit_reached | The plan has no room for another number |
403 | number_not_allowed | The key is limited to some numbers, and number_id isn't one of them (or is missing) |
409 | already_connected | That number is connected already |
409 | connect_in_progress | That number is being connected right now; number_id says which |
422 | invalid_phone | phone isn't a valid number in international format with + |
422 | number_not_found | number_id isn't a number of this workspace |
Related#
- Connect your WhatsApp number in the dashboard
- Connect a Telegram account
- Messages: send from a number with
from - Errors
