API Reference

Plain REST. One token per WhatsApp line. Every URL is fixed — the token tells us which line your request applies to.

Base URL
https://wappfly.com/api

Authentication

Every API call needs your session's API token in a request header. One token per WhatsApp line — you get it from the dashboard after pairing a number.

Required header on every request
Name Value
X-API-Token
YourAPIToken
Your per-session API token. You can reach it from your dashboard — click "Show token" next to a connected line. Treat it like a password: anyone with the token can send from that number.

Quick test with curl — replace YourAPIToken with the real value:

curl https://wappfly.com/api/me \
  -H "X-API-Token: YourAPIToken"

Rotating one session's token in the dashboard doesn't touch the others. If you suspect a leak, rotate immediately and update your automation tool's saved value.

Errors & quota

Every error response is JSON with an error field describing what went wrong. The HTTP status code tells you the category at a glance:

Status Meaning
400 Invalid request body — missing field, wrong type, or malformed JSON.
401 Missing or invalid X-API-Token header.
402 Quota exceeded. Upgrade your plan or wait for the period to reset.
403 Email not verified, or session is disconnected/banned.
404 Resource not found — wrong URL or the referenced message/JID doesn't exist.

Example error response:

{
  "error": "Email not verified — confirm your email at /verify-pending before sending."
}

Quota

Every outbound send and every incoming message counts as 1 request. Reads (/me, /status, /chats, /history, /messages/recent) and interactions (reactions, edits, deletes) are free. Free plan: 50 requests on a rolling 30-day window. Paid plans reset monthly.

HTTP POST https://wappfly.com/api/messages/send

Send a text message

Plain text. JID format: <digits>@s.whatsapp.net for users, <id>@g.us for groups.

Headers
Name Value
X-API-Token
YourAPIToken
Your per-session API token. You can reach it from your dashboard after you pair a WhatsApp number. Each session has its own token.
Content-Type
application/json
The request body must be JSON. This header tells the server how to read it.
Request body (JSON)
{
  "to":   "15551234567@s.whatsapp.net",
  "text": "Hello from Wappfly"
}
Response (JSON)
{
  "queued": true,
  "msg_id": "BD9043CF84A700B5"
}
HTTP POST https://wappfly.com/api/messages/image

Send an image

Base64-encoded image bytes + optional caption.

Headers
Name Value
X-API-Token
YourAPIToken
Your per-session API token. You can reach it from your dashboard after you pair a WhatsApp number. Each session has its own token.
Content-Type
application/json
The request body must be JSON. This header tells the server how to read it.
Request body (JSON)
{
  "to":       "15551234567@s.whatsapp.net",
  "file":     "<base64 image bytes>",
  "caption":  "Optional caption",
  "mimetype": "image/jpeg"
}
Response (JSON)
{
  "queued": true,
  "msg_id": "A85C9CADE68547F4"
}
HTTP POST https://wappfly.com/api/messages/document

Send a document

Any file (PDF, DOCX, ZIP, …). filename is what WhatsApp shows; mimetype determines the icon.

Headers
Name Value
X-API-Token
YourAPIToken
Your per-session API token. You can reach it from your dashboard after you pair a WhatsApp number. Each session has its own token.
Content-Type
application/json
The request body must be JSON. This header tells the server how to read it.
Request body (JSON)
{
  "to":       "15551234567@s.whatsapp.net",
  "file":     "<base64 file bytes>",
  "filename": "invoice.pdf",
  "mimetype": "application/pdf",
  "caption":  "Optional caption"
}
Response (JSON)
{
  "queued": true,
  "msg_id": "0D62C99DED30E849"
}
HTTP POST https://wappfly.com/api/messages/video

Send a video

MP4 / WebM. Optional caption.

Headers
Name Value
X-API-Token
YourAPIToken
Your per-session API token. You can reach it from your dashboard after you pair a WhatsApp number. Each session has its own token.
Content-Type
application/json
The request body must be JSON. This header tells the server how to read it.
Request body (JSON)
{
  "to":       "15551234567@s.whatsapp.net",
  "file":     "<base64 video bytes>",
  "caption":  "Optional caption",
  "mimetype": "video/mp4"
}
Response (JSON)
{
  "queued": true,
  "msg_id": "7F1A2BB3C4D5E6F7"
}
HTTP POST https://wappfly.com/api/messages/audio

Send a voice note

OGG Opus is the safest bet; other codecs may not show as a voice note.

Headers
Name Value
X-API-Token
YourAPIToken
Your per-session API token. You can reach it from your dashboard after you pair a WhatsApp number. Each session has its own token.
Content-Type
application/json
The request body must be JSON. This header tells the server how to read it.
Request body (JSON)
{
  "to":       "15551234567@s.whatsapp.net",
  "file":     "<base64 audio bytes>",
  "mimetype": "audio/ogg; codecs=opus"
}
Response (JSON)
{
  "queued": true,
  "msg_id": "2C8D9E0F1A2B3C4D"
}
HTTP POST https://wappfly.com/api/messages/reply

Reply to a message

Quotes the target message above your reply. quoted_msg_id is the id from the message you're replying to (find it in messageBody webhook or /api/messages/recent).

Headers
Name Value
X-API-Token
YourAPIToken
Your per-session API token. You can reach it from your dashboard after you pair a WhatsApp number. Each session has its own token.
Content-Type
application/json
The request body must be JSON. This header tells the server how to read it.
Request body (JSON)
{
  "to":            "15551234567@s.whatsapp.net",
  "text":          "Got it!",
  "quoted_msg_id": "3EB06A40C80DF456A1B2"
}
Response (JSON)
{
  "queued": true,
  "msg_id": "7863E1D57F991481"
}
HTTP POST https://wappfly.com/api/messages/reaction

React to a message

Pass an emoji as emoji. Send an empty string to remove your reaction. Does not count against your quota.

Headers
Name Value
X-API-Token
YourAPIToken
Your per-session API token. You can reach it from your dashboard after you pair a WhatsApp number. Each session has its own token.
Content-Type
application/json
The request body must be JSON. This header tells the server how to read it.
Request body (JSON)
{
  "to":            "15551234567@s.whatsapp.net",
  "emoji":         "👍",
  "target_msg_id": "3EB06A40C80DF456A1B2"
}
Response (JSON)
{
  "queued": true,
  "msg_id": "112CD0C5AE906886"
}
HTTP POST https://wappfly.com/api/messages/edit

Edit your message

WhatsApp allows editing for ~15 minutes after sending. Does not count against your quota.

Headers
Name Value
X-API-Token
YourAPIToken
Your per-session API token. You can reach it from your dashboard after you pair a WhatsApp number. Each session has its own token.
Content-Type
application/json
The request body must be JSON. This header tells the server how to read it.
Request body (JSON)
{
  "to":            "15551234567@s.whatsapp.net",
  "text":          "Fixed typo",
  "target_msg_id": "BD9043CF84A700B5"
}
Response (JSON)
{
  "queued": true,
  "msg_id": "9810D9D042E25594"
}
HTTP POST https://wappfly.com/api/messages/delete

Delete for everyone

Removes the message from both ends. Does not count against your quota.

Headers
Name Value
X-API-Token
YourAPIToken
Your per-session API token. You can reach it from your dashboard after you pair a WhatsApp number. Each session has its own token.
Content-Type
application/json
The request body must be JSON. This header tells the server how to read it.
Request body (JSON)
{
  "to":            "15551234567@s.whatsapp.net",
  "target_msg_id": "BD9043CF84A700B5"
}
Response (JSON)
{
  "queued": true,
  "msg_id": "AFB6C87B7BE45D18"
}
HTTP GET https://wappfly.com/api/me

Who am I + quota

Returns the session this token belongs to and how much quota the owner has used. Free, no quota cost.

Headers
Name Value
X-API-Token
YourAPIToken
Your per-session API token. You can reach it from your dashboard after you pair a WhatsApp number. Each session has its own token.
Response (JSON)
{
  "session": {
    "id": 8,
    "name": "sales",
    "status": "connected",
    "phone_jid": "15551234567:33@s.whatsapp.net",
    "me": {
      "id":   "15551234567:33@s.whatsapp.net",
      "name": "Your Business",
      "lid":  "265777475281011:33@lid"
    }
  },
  "user": {
    "id":                  1,
    "email":               "you@example.com",
    "plan":                { "code": "starter", "name": "Starter" },
    "quota":               5000,
    "requests_used":       127,
    "requests_left":       4873,
    "quota_period_start":  "2026-04-20 17:10:58",
    "quota_period_resets": "2026-05-20T17:10:58+00:00"
  }
}
HTTP GET https://wappfly.com/api/status

Connection status

Quick check that this line is still connected. Use it before sending if you're not sure.

Headers
Name Value
X-API-Token
YourAPIToken
Your per-session API token. You can reach it from your dashboard after you pair a WhatsApp number. Each session has its own token.
Response (JSON)
{
  "id":        8,
  "name":      "sales",
  "status":    "connected",
  "phone_jid": "15551234567:33@s.whatsapp.net",
  "me": {
    "id":   "15551234567:33@s.whatsapp.net",
    "name": "Your Business"
  }
}
HTTP GET https://wappfly.com/api/chats

List chats

Recent conversations this session has seen (since it connected). Empty array until the first message in/out per chat.

Headers
Name Value
X-API-Token
YourAPIToken
Your per-session API token. You can reach it from your dashboard after you pair a WhatsApp number. Each session has its own token.
Response (JSON)
[
  {
    "jid":         "15551234567@s.whatsapp.net",
    "name":        "Alice",
    "is_group":    0,
    "last_msg_at": "2026-05-20 17:19:21",
    "unread":      0
  }
]
HTTP GET https://wappfly.com/api/history?jid=&limit=

Chat history

Messages with a specific JID. Query: jid (required), limit (default 50, max 500). status walks queued → sending → sent → server_ack → delivery_ack → read.

Headers
Name Value
X-API-Token
YourAPIToken
Your per-session API token. You can reach it from your dashboard after you pair a WhatsApp number. Each session has its own token.
Response (JSON)
[
  {
    "msg_id":     "BD9043CF84A700B5",
    "from_me":    1,
    "sender_jid": "15551234567@s.whatsapp.net",
    "type":       "text",
    "body":       "Hello from Wappfly",
    "media_path": null,
    "timestamp":  "2026-05-20 17:19:21",
    "status":     "delivery_ack"
  },
  {
    "msg_id":     "3EB06A40C80DF456A1B2",
    "from_me":    0,
    "sender_jid": "905451552424@s.whatsapp.net",
    "type":       "text",
    "body":       "merhaba",
    "media_path": null,
    "timestamp":  "2026-05-20 17:19:18",
    "status":     "received"
  }
]
HTTP GET https://wappfly.com/api/messages/recent?limit=20

Recent inbox

Latest messages across all chats — handy for a live feed. limit default 20, max 100.

Headers
Name Value
X-API-Token
YourAPIToken
Your per-session API token. You can reach it from your dashboard after you pair a WhatsApp number. Each session has its own token.
Response (JSON)
[
  {
    "id":         122,
    "chat_jid":   "15551234567@s.whatsapp.net",
    "msg_id":     "BD9043CF84A700B5",
    "from_me":    1,
    "sender_jid": null,
    "type":       "text",
    "body":       "Hello from Wappfly",
    "timestamp":  "2026-05-20 17:19:21",
    "status":     "delivery_ack"
  },
  {
    "id":         121,
    "chat_jid":   "15551234567@s.whatsapp.net",
    "msg_id":     "3EB06A40C80DF456A1B2",
    "from_me":    0,
    "sender_jid": "15551234567@s.whatsapp.net",
    "type":       "text",
    "body":       "merhaba",
    "timestamp":  "2026-05-20 17:19:18",
    "status":     "received"
  }
]

Webhooks

Set a per-session webhook URL from the dashboard. Wappfly POSTs inbound messages only there in real time — outbound echoes, delivery acks, and connection events are tracked internally but not forwarded (keeps automation flows quiet so they only fire when a real customer message arrives). Every payload uses the same envelope:

{
  "event":     "messages.received",
  "timestamp": 1779285900,
  "session":   { "id": 8 },
  "data":      { ... shape below }
}

Wappfly retries are not automatic — your endpoint should always 2xx. If you need durability, persist the payload first, then process.

EVENT messages.received inbound message

Fired the first time an inbound message arrives on this session (de-duplicated by key.id). cleanedSenderPn strips the device suffix and @s.whatsapp.net so you can match on the bare phone number.

{
  "event":     "messages.received",
  "timestamp": 1779285900,
  "session":   { "id": 8 },
  "data": {
    "messages": {
      "key": {
        "id":              "3EB06A40C80DF456A1B2",
        "fromMe":          false,
        "remoteJid":       "15551234567@s.whatsapp.net",
        "addressingMode":  "pn",
        "senderPn":        "15551234567@s.whatsapp.net",
        "cleanedSenderPn": "15551234567",
        "senderLid":       null
      },
      "messageBody":      "merhaba",
      "message":          { "conversation": "merhaba" },
      "messageTimestamp": 1779285895,
      "pushName":         "Alice"
    }
  }
}

For media (image / document / video / audio) messageBody holds the caption (or null), and message carries the full Baileys payload — imageMessage, documentMessage, etc. — with the original mimetype and a download URL you can re-fetch via the API.

n8n / Zapier / Make example

In an HTTP Request node, configure the call exactly like this:

  • Method: POST
  • URL: https://wappfly.com/api/messages/send
  • Headers: X-API-Token: YourAPIToken and Content-Type: application/json
  • Body (JSON): { "to": "15551234567@s.whatsapp.net", "text": "Hello" }

No SDK, no session name in the URL — the token already names the WhatsApp line. Grab the token from your dashboard.