Skip to content
WaveSenda
Start free
BlogTutorial · 10 min

Send your first WhatsApp message with the API

From nothing to a delivered message and a webhook carrying the reply. Copy-paste curl throughout, with the errors you will actually hit and what each one means.


From nothing to a delivered WhatsApp message, then a webhook carrying the reply. Curl throughout, so it works the same whatever you end up writing it in.

You need a WhatsApp account on a phone you can scan a QR code with. Use a second number rather than your personal one if you have the choice — not because anything here is risky, but because a number you experiment with should not be the number your family uses.

Step 1

Connect a number

In the console, create a session and scan the QR code with WhatsApp → Linked devices. This is the same mechanism as WhatsApp Web: your account stays on your phone, and the session is another linked device.

Wait for the status to reach connected before going further. A session that is still pairing will accept API calls and deliver nothing, which is a confusing first ten minutes.

Step 2

Get an API key

Console → API keys → create one. You see the value once. It looks like ws_live_…, and it carries the same authority as your login, so it belongs in an environment variable and never in a repository.

set up your shell
export WAVESENDA_URL="https://api.wavesenda.com/api/v1"
export WAVESENDA_API_KEY="ws_live_..."
Step 3

Find your session id

list sessions
curl -s "$WAVESENDA_URL/sessions/" \
  -H "Authorization: Bearer $WAVESENDA_API_KEY"

Take the id of the connected session. Everything you send is sent from a session, so most calls need it.

keep it handy
export SESSION="00000000-0000-0000-0000-000000000000"
Step 4

Send a message to yourself

Your own second number is the right first recipient: if it does not arrive, you know immediately, and you have not bothered anybody.

send
curl -s -X POST "$WAVESENDA_URL/messages/send/" \
  -H "Authorization: Bearer $WAVESENDA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "session": "'"$SESSION"'",
    "to": "+237670000000",
    "type": "text",
    "text": "First message from the API."
  }'

The number goes in international format. The response carries a message id and a status — and that status is worth understanding before you build anything on it.

Step 5

Understand what came back

StatusMeansDoes not mean
queuedWe have it, WhatsApp does not yetAnything about delivery
sentWhatsApp accepted itThat a phone received it
deliveredIt reached a deviceThat anybody read it
readThe chat was opened—
failedIt will not be delivered—

sent is not delivered. A message to a number with no WhatsApp account is accepted and goes nowhere. If you are building anything that depends on a person receiving something, wait for delivered — this is the single most common mistake made in the first week, and we wrote a whole post about it.

Step 6

Check a number before you trust it

Plenty of valid phone numbers have no WhatsApp account. Checking costs nothing and removes a whole class of mystery.

does this number have WhatsApp?
curl -s -X POST "$WAVESENDA_URL/messages/check/" \
  -H "Authorization: Bearer $WAVESENDA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"session": "'"$SESSION"'", "numbers": ["+237670000000"]}'

Do this over a list before a campaign rather than afterwards, when you are trying to explain a poor response rate.

Step 7

Receive the reply

Sending is half of it. Register a webhook and inbound messages arrive at your endpoint as they happen.

register a webhook
curl -s -X POST "$WAVESENDA_URL/webhooks/" \
  -H "Authorization: Bearer $WAVESENDA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://example.com/hooks/wavesenda",
    "events": ["message.received", "message.status"]
  }'

Two rules for the endpoint, both learned the hard way by everybody:

  • Answer 200 quickly and do the work afterwards. A handler that takes eight seconds will be retried, and you will process the same message twice.
  • Verify the signature before trusting the body. The URL is guessable; the signature is not.

Use a request-inspection service while developing so you can see the payload shape before you write any parsing.

Step 8

Send something that is not text

upload, then send
# 1. upload
curl -s -X POST "$WAVESENDA_URL/messages/media/" \
  -H "Authorization: Bearer $WAVESENDA_API_KEY" \
  -F "file=@invoice.pdf"

# 2. send it, using the id that came back
curl -s -X POST "$WAVESENDA_URL/messages/send/" \
  -H "Authorization: Bearer $WAVESENDA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "session": "'"$SESSION"'",
    "to": "+237670000000",
    "type": "document",
    "media": "MEDIA_ID",
    "caption": "Invoice #1847"
  }'

Errors you will actually hit

What you seeWhat it means
401Key missing, wrong, or revoked. Check the Bearer prefix
session_not_connectedThe session is pairing or has dropped. Re-scan
Accepted, never deliveredUsually no WhatsApp account on that number
sending_pausedDeliberate. The number is being protected — check its health
429You are going too fast. Back off rather than retrying in a loop

Before you send to real people

  • Only message people who contacted you first. This is the whole ballgame.
  • Pace it. A new number sending hundreds of messages looks like what it looks like.
  • Watch the delivered-versus-accepted gap as an early warning.
  • Read what gets numbers banned before your first campaign, not after.

Next: build an agent to answer some of the replies, or the full quickstart for SDKs.

Common questions

Do I need a Meta developer account or business verification?

Not for this route. You are connecting an existing WhatsApp account as a linked device, the same way WhatsApp Web does, so there is no application process. The official Cloud API is a different product with different requirements.

Can I use my personal WhatsApp number?

Technically yes. Use a second number instead — a number you are testing automation against should not be the one your family messages, and the separation costs almost nothing.

Why did my message say sent but never arrive?

Most often the number has no WhatsApp account. Check it explicitly. Other causes are a block by the recipient, a phone that is off, or a number whose WhatsApp address differs from the number as typed, which happens in markets that have renumbered.

How fast can I send?

Slower than you want to. There is no single published number because it depends on the account’s age, history and reply rate. A new number should send a handful of messages a day and build up; anything that lets you send hundreds immediately is not protecting you.

What happens if my session disconnects?

Sending fails with a clear error rather than queueing silently, and the console shows the session as disconnected. Re-scanning the QR restores it. Phones that are off for long periods, or a logout from Linked Devices, are the usual causes.


Read next
The promises you made in WhatsApp and nobody wrote down
Follow-through · 7 min
Getting paid without leaving the chat
Payments · 7 min
Surviving a WhatsApp ban with a standby number
Continuity · 8 min
Send your first WhatsApp message with the API · WaveSenda