Wchat API v1
Create WhatsApp click-to-chat links and short links from your own software, and read their click statistics, like with Bitly.
- Available on the Pro plan. Same quota as the dashboard: up to 100 links.
- REST over HTTPS, JSON in and out, UTF-8. Base URL:
https://wchat.info/api/v1 - A key only reaches the links of its own account.
Authentication
Create a key in Settings → API keys (up to 5 keys, each one can be revoked at any time). The key is shown only once: store it safely, on your server. Never put it in a web page or a mobile app.
Send it in every request:
Authorization: Bearer wchat_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Endpoints
GET | /me | Your account, plan and link quota. |
GET | /links | List your links (paginated). |
POST | /links | Create a WhatsApp link or a short link. |
GET | /links/{slug} | One link. |
PATCH | /links/{slug} | Change a link (only the fields you send). |
DELETE | /links/{slug} | Delete a link and its statistics. |
GET | /links/{slug}/stats | Clicks of one link by day, country, region, city, referrer, device, platform and browser. |
GET | /stats | The same statistics for all your links together. |
{slug} is the code at the end of the short link (e.g. MYSHOP for https://wchat.info/MYSHOP), not case-sensitive.
Create a link
POST /links with these fields:
type | whatsapp (default) or shortlink |
phone_code | WhatsApp: country calling code, digits only (e.g. 39) |
phone_number | WhatsApp: number without the country code (e.g. 3331234567) |
message | WhatsApp: pre-filled message, up to 4000 characters |
url | Short link: destination, http or https |
slug | Optional custom code (letters, numbers, - and _). Random if omitted. |
curl
curl -X POST https://wchat.info/api/v1/links \
-H "Authorization: Bearer $WCHAT_API_KEY" \
-H "Content-Type: application/json" \
-d '{"type":"whatsapp","phone_code":"39","phone_number":"3331234567","message":"Hello, I would like some information"}'
PHP
$ch = curl_init('https://wchat.info/api/v1/links');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('WCHAT_API_KEY'),
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode([
'type' => 'shortlink',
'url' => 'https://example.com/offer',
]),
]);
$link = json_decode(curl_exec($ch), true)['data'];
echo $link['short_url'];
JavaScript (Node.js 18+)
const res = await fetch('https://wchat.info/api/v1/links', {
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.WCHAT_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({ type: 'whatsapp', phone_code: '39', phone_number: '3331234567', message: 'Hi!' }),
});
const { data } = await res.json();
console.log(data.short_url, data.qr_code_url);
Response 201 Created
{
"data": {
"id": 1234,
"slug": "MYSHOP",
"short_url": "https://wchat.info/MYSHOP",
"type": "whatsapp",
"phone_code": "39",
"phone_number": "3331234567",
"message": "Hello, I would like some information",
"url": null,
"destination": "https://api.whatsapp.com/send?phone=393331234567&text=Hello%2C%20I%20would%20like%20some%20information",
"clicks": 42,
"qr_code_url": "https://wchat.info/qrcode/MYSHOP",
"qr_code_download_url": "https://wchat.info/qrcode/MYSHOP/save",
"created_at": "2026-10-25T10:30:00+02:00",
"updated_at": "2026-10-25T10:30:00+02:00"
}
}
qr_code_url is a PNG image of the QR code, ready to print or show.
List links
GET /links?page=1&per_page=25&type=whatsapp&q=shop
All parameters are optional. per_page is at most 100, q searches in slug, phone number and URL. Newest links first.
{
"data": [
"…"
],
"meta": {
"page": 1,
"per_page": 25,
"total": 57,
"total_pages": 3
}
}
Change or delete a link
curl -X PATCH https://wchat.info/api/v1/links/MYSHOP \
-H "Authorization: Bearer $WCHAT_API_KEY" -H "Content-Type: application/json" \
-d '{"message":"New pre-filled message"}'
curl -X DELETE https://wchat.info/api/v1/links/MYSHOP -H "Authorization: Bearer $WCHAT_API_KEY"
The type of a link cannot be changed. DELETE answers 204 No Content; the link and its statistics are deleted forever, printed QR codes stop working.
Statistics
GET /links/MYSHOP/stats?days=30
GET /links/MYSHOP/stats?from=2026-01-01&to=2026-03-31
GET /stats?days=7
Default: last 30 days. History up to 3 years. Dates use the server time zone (UTC).
{
"data": {
"slug": "MYSHOP",
"from": "2026-09-26",
"to": "2026-10-25",
"total_clicks": 128,
"days": [
{
"date": "2026-09-26",
"clicks": 3
},
"…"
],
"countries": [
{
"country": "IT",
"clicks": 97
},
{
"country": "ES",
"clicks": 21
}
],
"regions": [
{
"country": "IT",
"region": "Lombardy",
"clicks": 40
}
],
"cities": [
{
"country": "IT",
"city": "Milan",
"clicks": 31
}
],
"referrers": [
{
"referrer": "https://www.instagram.com/",
"clicks": 60
},
{
"referrer": null,
"clicks": 41
}
],
"devices": [
{
"device": "mobile",
"clicks": 110
}
],
"platforms": [
{
"platform": "AndroidOS",
"clicks": 70
}
],
"browsers": [
{
"browser": "Chrome",
"clicks": 80
}
]
}
}
null means unknown (for referrers: direct visit). Countries are ISO 3166-1 alpha-2 codes. IP geolocation by DB-IP.
Errors and limits
{
"error": {
"code": "validation_failed",
"message": "The phone number field is required.",
"fields": {
"phone_number": "The phone number field is required."
}
}
}
401 unauthorized | Missing, invalid or revoked key |
403 forbidden | Plan not active, link quota reached, or feature not in your plan |
404 not_found | The link does not exist or belongs to another account |
422 validation_failed | Invalid fields, listed in fields |
429 rate_limited | Too many requests: wait for Retry-After seconds |
Up to 60 requests per minute per key. Every response carries X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset (Unix time).
If the Pro plan ends, the keys stop working (403) but are kept: they work again when the plan is renewed. Your links keep redirecting in any case.
Terms of use
Using the API means accepting the Terms and Conditions, including the rules on acceptable use. Keys that are abused (spam, phishing, malware, attempts to get around the limits) are revoked.