Getting Started
From zero to your first WhatsApp message in under 5 minutes.
- 1Subscribe on RapidAPIHead to the RapidAPI listing and subscribe to the free Basic plan (no credit card required). You'll receive an
x-rapidapi-keyheader value. - 2Create a SessionCall POST /v1/sessions with a name for your session. A session represents one WhatsApp account.
- 3Authenticate via QR Code or Pairing CodeFetch the QR code image from GET /v1/{session}/auth/qr and scan it with WhatsApp on your phone. Or use GET /v1/{session}/auth/pairing-code to get an 8-digit pairing code (no camera needed).
- 4Send Your First MessageCall POST /v1/sendText with a chatId (phone number), text, and session name.
/v1/contacts/check-exists endpoint to verify that a phone number is registered on WhatsApp before sending a message. This helps you avoid wasting monthly quota on inactive or invalid numbers.Authentication
All requests require two headers provided by RapidAPI.
| Header | Value | Required |
|---|---|---|
| x-rapidapi-key | Your RapidAPI key | Yes |
| x-rapidapi-host | whatsapp-messaging-bot.p.rapidapi.com | Yes |
| Content-Type | application/json | For POST/PUT/PATCH |
Base URL & Versioning
All endpoints are prefixed with /v1. The current stable API version is v1. Breaking changes will result in a new version prefix (/v2).
Sessions
A session = one authenticated WhatsApp account. You must create and authenticate a session before sending messages.
| Method | Path | Description |
|---|---|---|
| GET | /v1/sessions | List all sessions |
| POST | /v1/sessions | Create a new session |
| GET | /v1/sessions/{session} | Get session details |
| DELETE | /v1/sessions/{session} | Delete a session |
| POST | /v1/sessions/start | Start a session |
| POST | /v1/sessions/stop | Stop a session |
| GET | /v1/{session}/auth/qr | Get QR code image for authentication |
| GET | /v1/{session}/auth/pairing-code | Request pairing code (phone number auth) |
| POST | /v1/sessions/logout | Log out the session |
Create Session
curl -X POST "https://whatsapp-messaging-bot.p.rapidapi.com/v1/sessions" \ -H "x-rapidapi-key: YOUR_API_KEY" \ -H "x-rapidapi-host: whatsapp-messaging-bot.p.rapidapi.com" \ -H "Content-Type: application/json"
Get QR Code
curl -G "https://whatsapp-messaging-bot.p.rapidapi.com/v1/{session}/auth/qr" \
-H "x-rapidapi-key: YOUR_API_KEY" \
-H "x-rapidapi-host: whatsapp-messaging-bot.p.rapidapi.com" \
--data-urlencode "format=binary"
# Returns a PNG image you can display for scanningSession lifecycle & automatic recovery
A session moves through these states (delivered live via the session.status webhook):STARTING β SCAN_QR_CODE β AUTHENTICATED, with STOPPED and FAILED as recoverable states.
Calling GET /v1/{session}/auth/qr, the pairing-code endpoint, or POST /v1/sessions/start auto-recovers a FAILED or STOPPED session β it restarts internally, no manual step needed.
Webhooks
Receive real-time events from a WhatsApp session via HTTP POST to your server.
| Method | Path | Description |
|---|---|---|
| POST | /v1/sessions/{session}/webhooks | Register a webhook URL for a session |
| DELETE | /v1/sessions/{session}/webhooks | Remove a registered webhook URL |
Register a Webhook
curl -X POST "https://whatsapp-messaging-bot.p.rapidapi.com/v1/sessions/{session}/webhooks" -H "x-rapidapi-key: YOUR_API_KEY" -H "x-rapidapi-host: whatsapp-messaging-bot.p.rapidapi.com" -H "Content-Type: application/json" -d '{
"webhookUrl": "https://your-server.com/webhook",
"events": ["message", "session.status"]
}'Request body fields
webhookUrl(required) β The HTTPS URL that will receive POST requests for each event.eventsβ Array of event names to subscribe to. Defaults to["message"]if omitted.hmacKeyβ Optional secret key. When set, each request includes anX-Webhook-Hmacsignature header for verification.retriesβ Optional retry config:{ policy: "exponential", delaySeconds: 2, attempts: 5 }customHeadersβ Optional array of{ name, value }headers added to every webhook request (e.g. for token auth).
Supported events values
| Event | Description |
|---|---|
| session.status | Session state changes: STARTING, SCAN_QR_CODE, AUTHENTICATED, STOPPED, FAILED |
| message | New incoming messages only |
| message.any | All messages β both incoming and outgoing |
| message.reaction | Reactions added to messages |
| message.ack | Message delivery and read acknowledgements |
| message.waiting | Waiting for message delivery confirmation |
| message.revoked | Messages that were deleted or recalled |
| message.edited | Messages that were edited after sending |
| chat.archive | Chat archived or unarchived |
| group.v2.join | Joined a group (new API) |
| group.v2.leave | Left a group (new API) |
| group.v2.update | Group settings updated (new API) |
| group.v2.participants | Participant added or removed (new API) |
| group.join | Joined a group (legacy) |
| group.leave | Left a group (legacy) |
| presence.update | Contact's online/offline/typing status changed |
| poll.vote | A vote was cast on a poll |
| poll.vote.failed | A poll vote attempt failed |
| call.received | Incoming call received |
| call.accepted | Call was accepted |
| call.rejected | Call was rejected |
| label.upsert | Label created or updated |
| label.deleted | Label deleted |
| label.chat.added | Label applied to a chat |
| label.chat.deleted | Label removed from a chat |
| event.response | Event response received |
| event.response.failed | Event response failed |
| engine.event | Internal engine-level event |
What your server receives
Every event is an HTTP POST to your webhookUrl with the same envelope β event, session, and a payload whose shape depends on the event.
{
"event": "message",
"session": "my-session",
"payload": {
"id": "false_11111111111@c.us_AAABBBCCC",
"timestamp": 1667561485,
"from": "11111111111@c.us",
"fromMe": false,
"body": "Hello!",
"hasMedia": false,
"ack": 1,
"ackName": "SERVER"
}
}Delivery status: the ack value
On message.ack events, payload.ack is the source of truth for whether a message you sent actually landed.
| ack | ackName | Meaning |
|---|---|---|
| -1 | ERROR | Failed to send |
| 0 | PENDING | Queued, not yet sent |
| 1 | SERVER | Reached WhatsApp servers (one grey tick) |
| 2 | DEVICE | Delivered to recipient's device (two grey ticks) |
| 3 | READ | Read by recipient (two blue ticks) |
| 4 | PLAYED | Voice/video note played |
event, session, and payload.ack / ackName are stable β build against those.Recipe: send with delivery confirmation
The reliable path from a raw phone number to a confirmed delivery β check-exists, then send, then confirm with the message.ack webhook.
import requests
BASE = "https://whatsapp-messaging-bot.p.rapidapi.com"
HEADERS = {
"x-rapidapi-key": "YOUR_API_KEY",
"x-rapidapi-host": "whatsapp-messaging-bot.p.rapidapi.com",
"Content-Type": "application/json",
}
# 1. Confirm the number is on WhatsApp and get the real chatId
check = requests.get(
f"{BASE}/v1/contacts/check-exists",
params={"phone": "11111111111", "session": "my-session"},
headers=HEADERS,
).json()
if not check["numberExists"]:
raise SystemExit("Not on WhatsApp β don't send")
# 2. Send using the chatId the API returned (never build it by hand)
requests.post(
f"{BASE}/v1/sessions/my-session/messages/text",
json={"chatId": check["chatId"], "text": "Hello! π"},
headers=HEADERS,
)
# A 200 here means "accepted for sending" β NOT delivered yet.
# 3. Delivery is confirmed asynchronously on your webhook endpoint:
# subscribe to "message.ack" and watch for
# payload.ackName == "DEVICE" (delivered) or "READ" (read).Messages
Send any WhatsApp message type to contacts, groups, or channels.
| Method | Path | Description |
|---|---|---|
| POST | /v1/sendText | Send a text message |
| POST | /v1/sendImage | Send an image with optional caption |
| POST | /v1/sendFile | Send any file (PDF, DOCX, etc.) |
| POST | /v1/sendVideo | Send a video message |
| POST | /v1/sendVoice | Send a voice note |
| POST | /v1/sendLocation | Send a location pin |
| POST | /v1/sendContactVcard | Share a contact card |
| POST | /v1/sendPoll | Send a poll |
| POST | /v1/reply | Reply to a message |
| POST | /v1/sendSeen | Mark message as read |
| POST | /v1/startTyping | Start typing indicator |
| POST | /v1/stopTyping | Stop typing indicator |
Send Text Message
curl -X POST "https://whatsapp-messaging-bot.p.rapidapi.com/v1/sendText" \
-H "x-rapidapi-key: YOUR_API_KEY" \
-H "x-rapidapi-host: whatsapp-messaging-bot.p.rapidapi.com" \
-H "Content-Type: application/json" \
-d '{
"chatId": "1234567890",
"text": "Check this out: https://example.com",
"session": "default",
"linkPreview": true,
"linkPreviewHighQuality": true
}'Send Image
curl -X POST "https://whatsapp-messaging-bot.p.rapidapi.com/v1/sendImage" \
-H "x-rapidapi-key: YOUR_API_KEY" \
-H "x-rapidapi-host: whatsapp-messaging-bot.p.rapidapi.com" \
-H "Content-Type: application/json" \
-d '{
"chatId": "1234567890",
"session": "default",
"file": {
"url": "https://example.com/photo.jpg",
"mimetype": "image/jpeg"
},
"caption": "Check this out!"
}'chatId Formats
| Type | chatId Example | Notes |
|---|---|---|
| Individual | 1234567890 | Phone number only β country code auto-detected |
| Group | 120363024802736123@g.us | Obtain from GET /v1/sessions/{session}/groups |
| Channel | 120363024802736123@s.whatsapp.net | Obtain from channel search endpoint |
Link Preview Support (sendText)
The /v1/sendText endpoint supports automatic link preview generation:
- linkPreview (boolean, optional): Set to
trueto enable link preview for any URLs in your message text. - linkPreviewHighQuality (boolean, optional): Set to
trueto enable high-quality link previews (requires additional upload to WhatsApp servers).
Example: Sending a message with URL "Check this: https://example.com" with linkPreview: true will generate and display a preview card in WhatsApp.
message.ack for delivery and read acknowledgements. Best practice: call check-exists before sending, then confirm with message.ack.Groups
Create, manage, and configure WhatsApp Groups via API.
| Method | Path | Description |
|---|---|---|
| GET | /v1/sessions/{session}/groups | List all groups |
| POST | /v1/sessions/{session}/groups | Create a new group |
| GET | /v1/sessions/{session}/groups/{groupId} | Get group details |
| DELETE | /v1/sessions/{session}/groups/{groupId} | Delete a group |
| POST | /v1/sessions/{session}/groups/{groupId}/leave | Leave a group |
| PUT | /v1/sessions/{session}/groups/{groupId}/subject | Update group name |
| PUT | /v1/sessions/{session}/groups/{groupId}/description | Update group description |
| POST | /v1/sessions/{session}/groups/{groupId}/participants/add | Add participants |
| POST | /v1/sessions/{session}/groups/{groupId}/participants/remove | Remove participants |
| POST | /v1/sessions/{session}/groups/{groupId}/admin/promote | Promote to admin |
| POST | /v1/sessions/{session}/groups/{groupId}/admin/demote | Demote from admin |
Create Group
curl -X POST "https://whatsapp-messaging-bot.p.rapidapi.com/v1/sessions/{session}/groups" \
-H "x-rapidapi-key: YOUR_API_KEY" \
-H "x-rapidapi-host: whatsapp-messaging-bot.p.rapidapi.com" \
-H "Content-Type: application/json" \
-d '{
"name": "My Team",
"participants": [
{"id": "1234567890@c.us"},
{"id": "9876543210@c.us"}
]
}'404 and does not harm the session.Channels
Broadcast to unlimited subscribers with WhatsApp Channels (broadcast-only).
| Method | Path | Description |
|---|---|---|
| GET | /v1/sessions/{session}/channels | List subscribed channels |
| POST | /v1/sessions/{session}/channels | Create a channel |
| GET | /v1/sessions/{session}/channels/{channelId} | Get channel details |
| DELETE | /v1/sessions/{session}/channels/{channelId} | Delete a channel |
| GET | /v1/sessions/{session}/channels/{channelId}/messages/preview | Get channel preview messages |
Contacts
Check WhatsApp registration status.
| Method | Path | Description |
|---|---|---|
| GET | /v1/contacts/check-exists?phone={phone}&session={session} | Check if phone number is on WhatsApp |
check-exists reports whether a number is registered and reachable on WhatsApp β independent of whether itβs in your contact list. It returns numberExists (boolean) and, when found, a chatId. Always call it before messaging or adding a new number: it saves quota, avoids anti-spam flags from touching invalid numbers, and gives you the correct chatId to send to.chatId because of the 9-digit migration. Use the chatId returned by check-exists rather than building it yourself.Presence
Set typing indicators, read receipts, and online status.
| Method | Path | Description |
|---|---|---|
| POST | /v1/sessions/{session}/presence | Set session presence (online/offline/typing/recording/paused) |
| GET | /v1/sessions/{session}/presence | Get all chats presence |
| POST | /v1/startTyping | Start typing indicator in a chat |
| POST | /v1/stopTyping | Stop typing indicator in a chat |
| POST | /v1/sendSeen | Mark messages as read |
Error Handling
All errors return a consistent JSON body.
// All errors follow this shape:
{
"statusCode": 400,
"error": "Bad Request",
"message": "chatId is required"
}
// HTTP status codes used:
// 400 Bad Request β invalid or missing parameters
// 401 Unauthorized β missing or invalid API key
// 404 Not Found β session or resource not found
// 409 Conflict β session already exists
// 429 Too Many Reqs β rate limit exceeded
// 500 Internal Error β server-side error (retry)| HTTP Code | Meaning | Recommendation |
|---|---|---|
| 400 | Bad Request | Fix request body / query params |
| 401 | Unauthorized | Check your x-rapidapi-key |
| 404 | Not Found | Verify session name / resource ID |
| 409 | Conflict | Session name already exists β use a different name |
| 429 | Too Many Requests | Implement exponential backoff; upgrade plan |
| 500 | Internal Server Error | Retry with backoff; contact support if persistent |
Rate Limits
Limits apply per API key per plan.
| Plan | Requests / Month | Req / Second | Sessions |
|---|---|---|---|
| Basic (Free) | 100 | 10 | 1 |
| Pro | 1,000 | 10 | 3 |
| Ultra | 10,000 | 20 | 10 |
| Mega | 50,000 | 25 | Unlimited |
Safe Messaging Guide
Best practices to avoid account flags and keep your WhatsApp account healthy.
1. Only Reply to Messages
Never initiate conversations. Your bot should only reply to messages it receives. This prevents WhatsApp's algorithms from flagging you as spam.
Tip: Use WhatsApp links (https://wa.me/1234567890?text=Hi) to let users start the conversation with your bot first.
2. Mimic Human Behavior with Typing & Seen Indicators
Real humans don't send messages instantly. Use the typing and seen endpoints to create a natural feel:
POST /v1/sendSeen
POST /v1/startTyping
await delay(Math.random() * 3000 + 1000)
POST /v1/stopTyping
POST /v1/sendText
3. Use Random Delays Between Messages
Fixed timing looks robotic. Vary delays between messages:
- Wait 30-60 seconds between the first message to a new contact
- For bulk messaging, send max 4 messages per contact per hour that has replied
- If sending multiple messages, introduce 1-3 hour gaps between batches
- Never send messages 24/7 β rotate sending windows throughout the day
4. Respect User Context & Consent
Send only relevant, requested content:
- Send one short message when initiating; don't bombard with multiple texts
- Use messaging for appointments, reminders, OTPs, order updates β not marketing spam
- Vary message content; don't send identical templates
- Include contact name and personalization when possible
5. Group Contacts by Area Code
WhatsApp expects regular users to primarily message people in their geographic region. Group contacts by area code and send messages to similar regions in the same timeframe.
6. Build Account Strength
WhatsApp uses a reputation system:
- Add a profile picture, name, and status to your account (not just a bot number)
- Engage in conversations β the more back-and-forth exchanges, the stronger your account
- Only links marked as HTTPS and not previously flagged as spam work in messages
- Use URL shorteners carefully; avoid suspicious-looking links
- Enable "send seen" to show the account is actively used
7. Use Safe URLs
Avoid links that have been flagged as spam. Use HTTPS-only URLs. URL shorteners are recommended to avoid suspicion. WhatsApp checks URLs against known spam databases.
8. Dos and Don'ts Summary
β Do
- β’ Wait for user to initiate first
- β’ Use human-like typing delays
- β’ Send varying message content
- β’ Space out bulk messages by time
- β’ Engage in natural conversations
- β’ Check for user reports
β Don't
- β’ Initiate unsolicited conversations
- β’ Send instant rapid-fire messages
- β’ Copy-paste identical templates
- β’ Send 24/7 without breaks
- β’ Message unknown numbers randomly
- β’ Ignore user blocks or reports
9. Understanding Ban Risk
WhatsApp uses a points-based reputation system:
Points increase when: Users add you to contacts, engage in back-and-forth conversations
Points decrease when: Users report you as spam (5-10 reports = account ban), you're blocked, or you exhibit spam behavior
Ban happens when: Points drop below zero. Each report can cost multiple points.
β οΈ Critical: User Reports are Your Greatest Risk
As long as users don't report you as spam, your account will remain mostly safe. However, just 5-10 spam reports can result in permanent account restrictions. Content legitimacy matters β a survey the user agreed to is different from unsolicited marketing. Focus on opt-in, transactional, and notification-based messaging only.
OpenAPI / Swagger
Full OpenAPI 3.0 specification β browse, search, and test every endpoint interactively.
Interactive API Reference
Browse every endpoint, view request/response schemas, and use the live Try-it-out panel β all powered by the bundled OpenAPI 3.0 spec.
The raw spec file is also available for download or import into Postman, Insomnia, or any OpenAPI-compatible toolchain:
FAQ
Do I need a WhatsApp Business account?
No. You just need a regular WhatsApp account on a phone number. Authenticate via QR code or pairing code through the API.
Can I run multiple WhatsApp numbers simultaneously?
Yes. Create one session per number. Basic allows 1 session, Pro allows 3, Ultra allows 10, and Mega is unlimited.
What happens if I exceed my monthly quota?
On the Basic plan, requests are hard-blocked once you hit 100/month. On Pro, Ultra, and Mega, overage billing kicks in automatically at the per-request rate shown in your plan.
Is there an SDK?
The API is a standard REST API β any HTTP library works. RapidAPI auto-generates code snippets for 30+ languages including Python, JavaScript, PHP, Ruby, Go, and more.
Does the API support webhooks / incoming messages?
Yes. POST to /v1/sessions/{session}/webhooks with a webhookUrl and an events array. The events field defaults to ["message"] if omitted. You can subscribe to 29 event types including message, message.any, message.reaction, session.status, presence.update, group.v2.join, call.received, and more. See the Webhooks section above for the full list.
How do I know a message was actually delivered?
The send endpoints return success once a message is accepted for sending β that is not a delivery guarantee, and a message to a non-WhatsApp number can still return success. For real delivery/read status, register a webhook and subscribe to the message.ack event. Best practice: call check-exists before sending, then confirm with message.ack.
My session failed β do I need to rescan the QR code?
Usually not. Calling the QR, pairing-code, or start endpoint auto-recovers a FAILED or STOPPED session by restarting it internally. A full QR rescan is only needed when WhatsApp has logged the account out at their end, typically after an anti-spam flag. Follow the Safe Messaging Guide to avoid those logouts.
Why do group participant adds sometimes fail?
That's WhatsApp's anti-spam protection, not an API limit β adding numbers too quickly, re-adding existing members, or adding numbers that aren't on WhatsApp can trigger it, and a triggered flag can drop the session. Space out your adds, run check-exists first, and avoid re-adding. Adding a non-existent number returns a harmless 404.
Still have questions?
Contact Support