Developer Documentation

WhatsApp API Reference

Complete reference for the WhatsApp Messaging REST API. Covers authentication, all endpoints, code examples in cURL, Python, and JavaScript, error handling, and rate limits.

Getting Started

From zero to your first WhatsApp message in under 5 minutes.

  1. 1
    Subscribe on RapidAPI
    Head to the RapidAPI listing and subscribe to the free Basic plan (no credit card required). You'll receive an x-rapidapi-key header value.
  2. 2
    Create a Session
    Call POST /v1/sessions with a name for your session. A session represents one WhatsApp account.
  3. 3
    Authenticate via QR Code or Pairing Code
    Fetch 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).
  4. 4
    Send Your First Message
    Call POST /v1/sendText with a chatId (phone number), text, and session name.
πŸ’‘Pro-tip: Verify Numbers Before Messaging β€” Use the /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.

HeaderValueRequired
x-rapidapi-keyYour RapidAPI keyYes
x-rapidapi-hostwhatsapp-messaging-bot.p.rapidapi.comYes
Content-Typeapplication/jsonFor POST/PUT/PATCH
πŸ’‘Your API key is available on the RapidAPI dashboard after subscribing. Never expose it in client-side code β€” always call the API from your server.

Base URL & Versioning

https://whatsapp-messaging-bot.p.rapidapi.com/v1

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.

MethodPathDescription
GET/v1/sessionsList all sessions
POST/v1/sessionsCreate a new session
GET/v1/sessions/{session}Get session details
DELETE/v1/sessions/{session}Delete a session
POST/v1/sessions/startStart a session
POST/v1/sessions/stopStop a session
GET/v1/{session}/auth/qrGet QR code image for authentication
GET/v1/{session}/auth/pairing-codeRequest pairing code (phone number auth)
POST/v1/sessions/logoutLog out the session

Create Session

create_session.sh
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

get_qr.sh
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 scanning

Session 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.

πŸ’‘You rarely need to rescan the QR. A full re-scan is only required when WhatsApp has logged the account out at their end β€” typically after an anti-spam flag. For most failures, just call the QR/start endpoint and the session recovers automatically. Prevent flag-driven logouts by following the Safe Messaging Guide.

Webhooks

Receive real-time events from a WhatsApp session via HTTP POST to your server.

MethodPathDescription
POST/v1/sessions/{session}/webhooksRegister a webhook URL for a session
DELETE/v1/sessions/{session}/webhooksRemove a registered webhook URL

Register a Webhook

add_webhook.sh
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 an X-Webhook-Hmac signature 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

EventDescription
session.statusSession state changes: STARTING, SCAN_QR_CODE, AUTHENTICATED, STOPPED, FAILED
messageNew incoming messages only
message.anyAll messages β€” both incoming and outgoing
message.reactionReactions added to messages
message.ackMessage delivery and read acknowledgements
message.waitingWaiting for message delivery confirmation
message.revokedMessages that were deleted or recalled
message.editedMessages that were edited after sending
chat.archiveChat archived or unarchived
group.v2.joinJoined a group (new API)
group.v2.leaveLeft a group (new API)
group.v2.updateGroup settings updated (new API)
group.v2.participantsParticipant added or removed (new API)
group.joinJoined a group (legacy)
group.leaveLeft a group (legacy)
presence.updateContact's online/offline/typing status changed
poll.voteA vote was cast on a poll
poll.vote.failedA poll vote attempt failed
call.receivedIncoming call received
call.acceptedCall was accepted
call.rejectedCall was rejected
label.upsertLabel created or updated
label.deletedLabel deleted
label.chat.addedLabel applied to a chat
label.chat.deletedLabel removed from a chat
event.responseEvent response received
event.response.failedEvent response failed
engine.eventInternal 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.

webhook_payload.json
{
  "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.

ackackNameMeaning
-1ERRORFailed to send
0PENDINGQueued, not yet sent
1SERVERReached WhatsApp servers (one grey tick)
2DEVICEDelivered to recipient's device (two grey ticks)
3READRead by recipient (two blue ticks)
4PLAYEDVoice/video note played
ℹ️Extra fields may appear depending on the engine, but 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.

reliable_send.py
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.

MethodPathDescription
POST/v1/sendTextSend a text message
POST/v1/sendImageSend an image with optional caption
POST/v1/sendFileSend any file (PDF, DOCX, etc.)
POST/v1/sendVideoSend a video message
POST/v1/sendVoiceSend a voice note
POST/v1/sendLocationSend a location pin
POST/v1/sendContactVcardShare a contact card
POST/v1/sendPollSend a poll
POST/v1/replyReply to a message
POST/v1/sendSeenMark message as read
POST/v1/startTypingStart typing indicator
POST/v1/stopTypingStop typing indicator

Send Text Message

send_text.py
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

send_image.sh
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

TypechatId ExampleNotes
Individual1234567890Phone number only β€” country code auto-detected
Group120363024802736123@g.usObtain from GET /v1/sessions/{session}/groups
Channel120363024802736123@s.whatsapp.netObtain from channel search endpoint

Link Preview Support (sendText)

The /v1/sendText endpoint supports automatic link preview generation:

  • linkPreview (boolean, optional): Set to true to enable link preview for any URLs in your message text.
  • linkPreviewHighQuality (boolean, optional): Set to true to 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.

⚠️A 200 success means β€œaccepted for sending” β€” not β€œdelivered.” WhatsApp confirms delivery asynchronously, so the HTTP response can’t tell you whether a message actually landed. A message sent to a number that isn’t on WhatsApp can still return success. To know the real status, register a webhook and subscribe to 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.

MethodPathDescription
GET/v1/sessions/{session}/groupsList all groups
POST/v1/sessions/{session}/groupsCreate 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}/leaveLeave a group
PUT/v1/sessions/{session}/groups/{groupId}/subjectUpdate group name
PUT/v1/sessions/{session}/groups/{groupId}/descriptionUpdate group description
POST/v1/sessions/{session}/groups/{groupId}/participants/addAdd participants
POST/v1/sessions/{session}/groups/{groupId}/participants/removeRemove participants
POST/v1/sessions/{session}/groups/{groupId}/admin/promotePromote to admin
POST/v1/sessions/{session}/groups/{groupId}/admin/demoteDemote from admin

Create Group

create_group.sh
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"}
    ]
  }'
⚠️Adding participants is rate-sensitive. Intermittent failures when adding members β€” including a number that succeeds several times then fails β€” are WhatsApp’s anti-spam protection, not an API limit, and a triggered flag can log the session out. To stay safe: space out adds instead of looping rapidly, call check-exists first (adding numbers not on WhatsApp is a common trigger), and don’t re-add numbers already in the group. Adding a non-existent number returns 404 and does not harm the session.

Channels

Broadcast to unlimited subscribers with WhatsApp Channels (broadcast-only).

MethodPathDescription
GET/v1/sessions/{session}/channelsList subscribed channels
POST/v1/sessions/{session}/channelsCreate 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/previewGet channel preview messages

Contacts

Check WhatsApp registration status.

MethodPathDescription
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.
πŸ’‘Brazilian numbers: older (pre-2012) numbers resolve to a different 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.

MethodPathDescription
POST/v1/sessions/{session}/presenceSet session presence (online/offline/typing/recording/paused)
GET/v1/sessions/{session}/presenceGet all chats presence
POST/v1/startTypingStart typing indicator in a chat
POST/v1/stopTypingStop typing indicator in a chat
POST/v1/sendSeenMark messages as read

Error Handling

All errors return a consistent JSON body.

errors.json
// 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 CodeMeaningRecommendation
400Bad RequestFix request body / query params
401UnauthorizedCheck your x-rapidapi-key
404Not FoundVerify session name / resource ID
409ConflictSession name already exists β€” use a different name
429Too Many RequestsImplement exponential backoff; upgrade plan
500Internal Server ErrorRetry with backoff; contact support if persistent

Rate Limits

Limits apply per API key per plan.

PlanRequests / MonthReq / SecondSessions
Basic (Free)100101
Pro1,000103
Ultra10,0002010
Mega50,00025Unlimited
⚠️When you hit the rate limit you receive a 429 Too Many Requests response. Implement exponential backoff starting at 1 second.

Safe Messaging Guide

Best practices to avoid account flags and keep your WhatsApp account healthy.

⚠️WhatsApp actively monitors for spam and abuse. Following these guidelines is critical to avoiding account restrictions or permanent bans. This API mimics natural user behavior when used correctly.

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:

// 1. Send seen confirmation
POST /v1/sendSeen
// 2. Start typing
POST /v1/startTyping
// 3. Wait (proportional to message length)
await delay(Math.random() * 3000 + 1000)
// 4. Stop typing & send message
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.

Bottom Line: Use this API to send notifications, transactional messages, and replies. Always wait for users to contact you first. Mimic natural behavior with delays and typing indicators. If you follow these guidelines, your account will remain healthy and your users happy.

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.

SessionsMessagesGroupsChannelsContactsPresence

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