REST API · v1

WATI Pro Developer Documentation

Integrate WhatsApp into any website, CRM or backend in minutes. Send text + media, run campaigns, manage contacts, build auto-reply bots, and receive inbound messages via signed webhooks.

Introduction

The WATI Pro API is a JSON HTTPS REST API. All requests use:

Base URL:   https://wati.pro
Content:    application/json
Auth:       Authorization: Bearer wati_xxxxxxxx...

Every endpoint listed here is reachable from any backend (Node, PHP, Python, Ruby, .NET, Go, Java, n8n, Zapier, Make, etc.) or directly from a server-side handler on your website. Do not call these endpoints from a browser — your API key must never be exposed to end users.

Quotas: message and device caps come from your plan.
CORS: all endpoints respond to OPTIONS preflight.

Authentication

Create an API key in Settings → API Keys. The key is shown only once and looks like wati_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.

Send it as a Bearer token on every request:

curl https://wati.pro/api/public/v1/send \
  -H "Authorization: Bearer wati_YOUR_KEY_HERE" \
  -H "Content-Type: application/json" \
  -d '{"to":"+923001234567","message":"Hi from API"}'

Failed auth returns 401 Unauthorized. Revoke or disable a key any time from the dashboard.

Plan limits & quotas

Every API call is checked against your active plan. When you hit a cap the request returns 409 Conflict with a clear error message and the dashboard shows an upgrade prompt. Counters reset on your billing cycle (messages), daily at 00:00 UTC (AI replies), or never (devices, seats, rules).

ResourceFreeStarterProAgency
Connected devices11310
Outbound messages / day505002,00010,000
Keyword auto-reply rules320UnlimitedUnlimited
Team Inbox seats12525
AI Smart Replies / day01001,00010,000
REST API access
Signed inbound webhooks

Soft-rate limit per API key defaults to 60 req/min. Admins can tune per-key limits atAdmin → Rate Limits.

Send a text message

POST
/api/public/v1/send

Sends a WhatsApp text message from one of your connected devices.

Request body

{
  "to": "+923001234567",          // required — E.164 or local digits
  "message": "Hello from WATI",   // required — up to 4096 chars
  "deviceId": "uuid-optional"     // optional — uses first connected device if omitted
}

curl

curl -X POST https://wati.pro/api/public/v1/send \
  -H "Authorization: Bearer wati_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "to": "+923001234567",
    "message": "Your OTP is 123456"
  }'

200 response

{
  "ok": true,
  "id": "9b7c...uuid",
  "messageId": "3EB0F5C8...",
  "status": "sent",
  "to": "923001234567"
}

Send media — image, document, video, audio

POST
/api/public/v1/send-media

Pass a public HTTPS URL pointing at your file. The gateway downloads it once and forwards it as a real WhatsApp media message.

Request body

{
  "to":       "+923001234567",                                 // required
  "type":     "image" | "video" | "audio" | "document",        // required
  "url":      "https://your-cdn.com/invoice.pdf",              // required, public URL
  "caption":  "Optional caption",                              // optional (image/video/document)
  "fileName": "invoice.pdf",                                   // recommended for document
  "mimetype": "application/pdf",                               // optional, auto-detected
  "deviceId": "uuid-optional"
}

Send an image

curl -X POST https://wati.pro/api/public/v1/send-media \
  -H "Authorization: Bearer wati_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "to": "+923001234567",
    "type": "image",
    "url": "https://picsum.photos/800/600.jpg",
    "caption": "Check out our new product"
  }'

Send a PDF document

curl -X POST https://wati.pro/api/public/v1/send-media \
  -H "Authorization: Bearer wati_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "to": "+923001234567",
    "type": "document",
    "url": "https://example.com/files/invoice-2026-001.pdf",
    "fileName": "invoice-2026-001.pdf",
    "mimetype": "application/pdf",
    "caption": "Your invoice for January"
  }'

Send a video

curl -X POST https://wati.pro/api/public/v1/send-media \
  -H "Authorization: Bearer wati_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "to": "+923001234567",
    "type": "video",
    "url": "https://example.com/demo.mp4",
    "caption": "60-second product demo"
  }'

Send a voice note / audio

curl -X POST https://wati.pro/api/public/v1/send-media \
  -H "Authorization: Bearer wati_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "to": "+923001234567",
    "type": "audio",
    "url": "https://example.com/welcome.mp3",
    "mimetype": "audio/mpeg"
  }'
Important: the url must be publicly reachable over HTTPS so the gateway can fetch the file. Common WhatsApp size limits apply (image 5 MB, video 16 MB, audio 16 MB, document 100 MB).

Look up a sent message

GET
/api/public/v1/messages/{id}

id can be either the internal UUID returned by /sendor the WhatsApp messageId.

curl https://wati.pro/api/public/v1/messages/9b7c...uuid \
  -H "Authorization: Bearer wati_YOUR_KEY"
{
  "message": {
    "id": "9b7c...",
    "message_id": "3EB0F5C8...",
    "direction": "out",
    "peer": "923001234567",
    "text": "Hello from WATI",
    "status": "sent",
    "created_at": "2026-06-10T12:34:56Z"
  }
}

Bulk campaigns

POST
/api/public/v1/campaigns

Create a campaign that delivers in batches. Returns immediately with a campaign id; use the run endpoint or our cron to process batches. Variables {{name}} and {{phone}} are replaced per-recipient.

Request body

{
  "name":          "January promo",
  "message":       "Hi {{name}}, today only — 20% off!",
  "deviceId":      "uuid-optional",
  "delaySeconds":  3,                       // 1-60 between messages
  "scheduledAt":   "2026-07-01T10:00:00Z",  // optional ISO-8601, future date for scheduled campaign
  "tag":           "vip",                   // optional — send only to contacts with this tag
  "recipients": [                           // recipients[] OR contactListId OR tag
    { "name": "Ali",  "phone": "+923001234567" },
    { "name": "Sara", "phone": "+923009876543" }
  ],
  "contactListId": "uuid-of-saved-list"
}

Provide exactly one of recipients, contactListId, or tag. When tag is used the campaign auto-resolves every contact in your CRM carrying that tag at run time.

curl

curl -X POST https://wati.pro/api/public/v1/campaigns \
  -H "Authorization: Bearer wati_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Welcome blast",
    "message": "Hi {{name}}, thanks for joining!",
    "delaySeconds": 5,
    "recipients": [
      {"name":"Ali","phone":"+923001111111"},
      {"name":"Sara","phone":"+923002222222"}
    ]
  }'

Trigger the next batch

POST
/api/public/v1/campaigns/{id}/run
curl -X POST https://wati.pro/api/public/v1/campaigns/<campaignId>/run \
  -H "Authorization: Bearer wati_YOUR_KEY"

Contacts

Contacts use Supabase-issued user JWT (same key style — wati_ keys also work here).

GET
/api/contacts
curl https://wati.pro/api/contacts \
  -H "Authorization: Bearer wati_YOUR_KEY"
POST
/api/contacts
curl -X POST https://wati.pro/api/contacts \
  -H "Authorization: Bearer wati_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "contacts": [
      { "name": "Ali",  "phone": "+923001234567", "tags": ["lead","jan26"] },
      { "name": "Sara", "phone": "+923009876543", "tags": ["customer"] }
    ]
  }'
DELETE
/api/contacts
curl -X DELETE https://wati.pro/api/contacts \
  -H "Authorization: Bearer wati_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "ids": ["uuid-1","uuid-2"] }'

Auto-reply rules

GET
/api/auto-replies
curl https://wati.pro/api/auto-replies -H "Authorization: Bearer wati_YOUR_KEY"
POST
/api/auto-replies
curl -X POST https://wati.pro/api/auto-replies \
  -H "Authorization: Bearer wati_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "keyword": "price",
    "match_type": "contains",            // contains | exact | starts_with
    "response": "Our pricing: https://wati.pro/pricing",
    "responses": [
      "Our pricing: https://wati.pro/pricing",
      "Need a custom quote? Reply YES."
    ],
    "step_delay_seconds": 2,
    "active": true
  }'
DELETE
/api/auto-replies
curl -X DELETE https://wati.pro/api/auto-replies \
  -H "Authorization: Bearer wati_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "id": "rule-uuid" }'

AI Smart Reply (multi-language)

When an inbound message does NOT match any keyword rule and AI Smart Reply is enabled, WATI Pro calls the Lovable AI Gateway (google/gemini-3-flash-preview) with the last 5 messages from that conversation, auto-detects the customer's language, and replies in the same language. Replies are logged in Auto-Reply → Logand count against your daily AI quota.

Configure via dashboard

Go to Auto-Reply → AI Smart Reply to toggle it on, set a custom system prompt (your business voice), and pick a preferred fallback language.

Decision flow

incoming message
  ├─ matches a keyword rule?  → send keyword response, STOP
  ├─ AI Smart Reply enabled?  → call Lovable AI Gateway
  │      ├─ over daily AI quota?  → silent skip, log "quota_exceeded"
  │      └─ ok → reply in customer's language, log "ai"
  └─ neither → no reply (manual handling in Team Inbox)

Supported languages (auto-detected)

English, Urdu, Hindi, Arabic, Spanish, French, Portuguese, Bengali, Indonesian, Turkish, Russian, German, Italian, Dutch and 80+ more — anything Gemini understands.

Shared Team Inbox

The Team Inbox is currently a dashboard feature — multiple agents share one WhatsApp number, conversations can be assigned to a teammate, and statuses are open, pending or resolved. Outbound replies sent from the inbox go through the same gateway as the REST API, so they appear in /api/public/v1/messages/{id} like any other message.

Conversation object (server-function response)

{
  "id":            "uuid",
  "device_id":     "uuid",
  "peer":          "923001234567",
  "assigned_to":   "user-uuid | null",
  "status":        "open | pending | resolved",
  "unread_count":  3,
  "last_message_at": "2026-06-11T09:12:33Z"
}

Roles & permissions

  • Agent — sees & replies to assigned conversations; cannot reassign or change billing.
  • Manager — sees ALL conversations on the account, can assign/resolve, view analytics.
  • Admin — full project access incl. devices, API keys, team roles.
  • Super Admin — platform-wide (multi-tenant).
REST endpoints for the inbox (list / assign / reply) will land in API v2. For now, integrate via webhooks (new messages) + /send (replies).

Analytics

The Analytics dashboard aggregates the last 30 days: outbound vs inbound message volume per day, campaign success/failure rates, AI vs keyword reply share, and top-performing templates.

Programmatic access

For now derive your own counters from /api/public/v1/messages and campaign listings. A dedicated /api/public/v1/analytics/summaryendpoint is on the v2 roadmap.

Incoming-message webhooks

Configure a webhook URL in Settings → Gateway. Every inbound WhatsApp message is POSTed to your URL with an HMAC signature you should verify.

Headers we send

POST https://your-app.com/wati-hook
Content-Type:    application/json
X-Wati-Signature: sha256=<hex hmac>           # HMAC-SHA256 of the raw body
X-Wati-Timestamp: 1733832000

Body

{
  "event":     "message.received",
  "deviceId":  "uuid",
  "from":      "923001234567",
  "to":        "923009999999",
  "text":      "hello",
  "messageId": "3EB0...",
  "type":      "text" | "image" | "video" | "audio" | "document",
  "mediaUrl":  "https://...",                  // when type != text
  "timestamp": 1733832000
}

Verify the signature (Node.js)

import crypto from "crypto";

function verify(rawBody, signatureHeader, secret) {
  const expected = "sha256=" + crypto
    .createHmac("sha256", secret)
    .update(rawBody)
    .digest("hex");
  return crypto.timingSafeEqual(
    Buffer.from(signatureHeader),
    Buffer.from(expected)
  );
}

Event types

  • message.received — inbound WhatsApp message (text or media)
  • message.status — sent / delivered / read / failed
  • conversation.assigned — Team Inbox assignment changed
  • campaign.completed — bulk campaign finished, includes sent/failed counts

Delivery & retries

Your endpoint must respond 2xx within 10s. Non-2xx or timeout triggers exponential-backoff retries (1m, 5m, 30m, 2h, 12h — then dropped). The same messageId may arrive more than once — make your handler idempotent.

Meta WhatsApp Cloud API setup

Use Meta's official WhatsApp Cloud API instead of the local Baileys gateway. Required for verified businesses, green-tick, and high-volume sending. WATI Pro handles webhook routing per tenant, signature verification, and provider switching — you only paste credentials.

Step 1 — Create a Meta app

  1. Go to developers.facebook.com/appsCreate App → choose Business.
  2. Add the WhatsApp product to your app.
  3. In WhatsApp → API Setup, copy the Phone Number ID and WhatsApp Business Account ID (WABA).

Step 2 — Generate a permanent access token

  1. Open Business Settings → Users → System UsersAdd (role: Admin).
  2. Assign the system user to your WhatsApp Account with Full control.
  3. Click Generate Token → select your app → grant whatsapp_business_messaging and whatsapp_business_managementnever expires.

Step 3 — Paste credentials in WATI Pro

Open Settings → Gateway, choose the Meta Cloud API card, and fill in:

  • Phone Number ID — from Meta API Setup
  • Business Account ID (WABA)
  • Permanent Access Token — from step 2
  • App Secret — Meta App → Settings → Basic
  • Webhook Verify Token — any random string you make up (e.g. my-tenant-7f3a)

Step 4 — Configure the webhook in Meta

In Meta App → WhatsApp → Configuration → Webhook, paste your per-tenant URL (shown in Settings → Gateway after saving credentials):

Callback URL:  https://wati.pro/api/public/cloud-api-webhook/<your-tenant-id>
Verify Token:  <the same string you saved in step 3>

Click Verify and Save. Then subscribe to the messages field. All inbound messages and delivery statuses will flow into your Team Inbox automatically — signed with HMAC-SHA256 using your App Secret.

Step 5 — Send your first message

Cloud API requires a pre-approved template for first contact (outside the 24-hour customer service window). Create a template in Meta Business Manager → WhatsApp Manager → Message Templates, then send from any of the WATI Pro endpoints below — the platform auto-routes to Meta when your provider is set to Cloud API.

curl -X POST https://wati.pro/api/public/v1/send \
  -H "Authorization: Bearer wati_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "to": "+923001234567", "message": "Hello from Cloud API" }'
Troubleshooting:
  • Invalid signature in webhook logs → App Secret mismatch.
  • (#131030) Recipient phone number not in allowed list → add test numbers in Meta API Setup, or graduate your number to production.
  • (#132000) Template does not exist → template not approved yet, or wrong language code.

Errors & rate limits

400
Invalid request body (Zod validation failed)
401
Missing or revoked API key
404
Resource not found / device not yours
409
Device not connected, or plan limit reached
429
Rate limit exceeded — back off and retry
500
Gateway or upstream failure

Per-key rate limits are configurable by admins in Admin → Rate Limits. Errors always return JSON: { "error": "message" }.

Code samples

Node.js (fetch)

await fetch("https://wati.pro/api/public/v1/send", {
  method: "POST",
  headers: {
    "Authorization": "Bearer " + process.env.WATI_KEY,
    "Content-Type":  "application/json",
  },
  body: JSON.stringify({
    to: "+923001234567",
    message: "Hi from Node",
  }),
});

PHP (cURL)

<?php
$ch = curl_init("https://wati.pro/api/public/v1/send");
curl_setopt_array($ch, [
  CURLOPT_POST => true,
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_HTTPHEADER => [
    "Authorization: Bearer " . getenv("WATI_KEY"),
    "Content-Type: application/json",
  ],
  CURLOPT_POSTFIELDS => json_encode([
    "to" => "+923001234567",
    "message" => "Hi from PHP",
  ]),
]);
echo curl_exec($ch);

Python (requests)

import os, requests

requests.post(
    "https://wati.pro/api/public/v1/send-media",
    headers={"Authorization": f"Bearer {os.environ['WATI_KEY']}"},
    json={
        "to": "+923001234567",
        "type": "document",
        "url": "https://example.com/file.pdf",
        "fileName": "file.pdf",
        "caption": "Your report",
    },
)

WordPress / WooCommerce

add_action("woocommerce_order_status_processing", function($order_id){
  $order = wc_get_order($order_id);
  wp_remote_post("https://wati.pro/api/public/v1/send", [
    "headers" => [
      "Authorization" => "Bearer " . WATI_KEY,
      "Content-Type"  => "application/json",
    ],
    "body" => wp_json_encode([
      "to"      => $order->get_billing_phone(),
      "message" => "Order #" . $order_id . " confirmed. Thank you!",
    ]),
  ]);
});

Ready to integrate?

Create your account, link a device, and grab an API key in under 5 minutes.