WABridges

Send a message

POST a body and a chat id to a connected bridge - plus how to address a person or a group, and how to make a retry safe.

The call

One POST with two fields: who, and what. chat is the recipient, body is the text.

The response is the message id WhatsApp assigned. Hold on to it: delivery and read receipts arrive later on your webhook keyed by that same id, and it is what you quote if you need us to trace a send.

curl
curl -X POST https://wabridges.com/api/instances/user-123/proxy/send/text \
  -H "Authorization: Bearer $WA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "chat": "15550001234",
    "body": "hello"
  }'
← 200
{
  "message_id": "ACE41E988162AB19A4A7BB7A9E663693",
  "timestamp": 1777180605
}

Addressing a person or a group

A plain international number without punctuation is enough for a one-to-one chat - 15550001234. It is expanded to the full WhatsApp address for you.

Groups have no phone number, so they can only be addressed by their full id, which ends in @g.us. You get that id from the chat_id of any message the group sends you, which is the practical reason to store chat_id on every inbound event rather than just the sender's phone.

a person
{"chat": "15550001234", "body": "hello"}
the same person, written out
{"chat": "15550001234@s.whatsapp.net", "body": "hello"}
a group
{"chat": "120363000000000001@g.us", "body": "hi team"}

Making a retry safe

A timed-out send is genuinely ambiguous - the request may have reached WhatsApp before the connection died. Send an Idempotency-Key and it stops being ambiguous.

The first use performs the send and stores the response for 24 hours. A repeat of the same key replays that stored response, marked X-Idempotency-Replayed: true, without sending anything. A duplicate that arrives while the first is still in flight gets 409 idempotency_conflict. Only successful responses consume a key, so a failed send can be retried with the same one.

Use one key per logical action - an order id, a UUID you generate before the first attempt - and reuse it for every retry of that action.

curl
curl -X POST https://wabridges.com/api/instances/user-123/proxy/send/text \
  -H "Authorization: Bearer $WA_API_KEY" \
  -H "Idempotency-Key: order-4417-confirmation" \
  -H "Content-Type: application/json" \
  -d '{"chat": "15550001234", "body": "Your order shipped"}'

When a send fails

Errors come back as {"error": "...", "code": "..."}. Branch on code - it is stable and machine-readable, where the message is prose that may be reworded.

  • 503 - the session is not connected. Re-pair, or wait out the Retry-After. See check it is connected.
  • 400 - a missing or malformed field, usually a chat that is not a number or a full id.
  • 502 - WhatsApp itself rejected or failed the request.
  • 429 - you are over 120 requests per minute. The Retry-After header says how long to wait.

The full list, and how to make a retry safe, is on errors and retries.

Every response carries an X-Request-Id. If a send goes wrong in a way this page does not explain, that id lets us find the exact request instead of guessing.

Beyond text

The same shape sends everything else: /send/media for images, audio, documents and voice notes, /send/reaction to react to a message id, /send/typing to show the typing indicator before a slow reply. Fields and payloads for each are in the API reference.

Something here not matching what you see? Write to us - a person answers.