Account
Sign up, and who this key belongs to.
POST /api/v1/signup
Start creating an account. Sends a 6-digit code to the WhatsApp number given (or the email, if WhatsApp cannot be used). Nothing is created until the code is confirmed with `POST /api/v1/signup/verify`, so a person must take part. No key needed
| Body | Type | |
|---|
email required | string | |
phone required | string | The owner's WhatsApp number, with country code. The code is sent here. |
name required | string | The owner's name. |
company | string | |
plan_id | string | One of the public plans; the default plan if left out. |
curl -X POST "https://whatsapp.nergaa.cloud/api/v1/signup" \
-H "Content-Type: application/json" \
-d '{"email":"owner@shop.co.ke","phone":"254712345678","company":"Shop Ltd","name":"Jane Wanjiku"}'
POST /api/v1/signup/verify
Confirm the code and get an API key. No key needed
| Body | Type | |
|---|
email required | string | |
code required | string | |
curl -X POST "https://whatsapp.nergaa.cloud/api/v1/signup/verify"
GET /api/v1/me
The account this key belongs to, its plan and usage.
curl -X GET "https://whatsapp.nergaa.cloud/api/v1/me" \
-H "Authorization: Bearer $API_KEY"
Billing
Plans, the subscription, and paying for it.
GET /api/v1/plans
List the plans on offer. No key needed
curl -X GET "https://whatsapp.nergaa.cloud/api/v1/plans"
GET /api/v1/billing
The subscription, plan, available plans and recent payments.
curl -X GET "https://whatsapp.nergaa.cloud/api/v1/billing" \
-H "Authorization: Bearer $API_KEY"
POST /api/v1/billing/pay
Start paying for a plan. `paypal` returns a `checkout_url` on PayPal, where the person pays with PayPal or any card. `mpesa` sends a payment prompt to the phone; the person enters their PIN. `checkout` returns a `checkout_url` to give the person (card, Apple Pay, Google Pay or M-Pesa). Follow the result with `GET /api/v1/billing/payments/{id}`.
| Body | Type | |
|---|
plan_id | string | Leave out to renew the current plan. |
method required | string (paypal, mpesa, checkout) | |
phone | string | For `mpesa`: the number that gets the payment prompt. |
curl -X POST "https://whatsapp.nergaa.cloud/api/v1/billing/pay" \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{"plan_id":"pln_3f9a…","method":"mpesa","phone":"254712345678"}'
GET /api/v1/billing/payments/{id}
A payment's current status.
curl -X GET "https://whatsapp.nergaa.cloud/api/v1/billing/payments/sales-desk" \
-H "Authorization: Bearer $API_KEY"
Numbers
WhatsApp numbers linked to the account, and linking new ones.
GET /api/v1/instances
List the account's WhatsApp numbers.
curl -X GET "https://whatsapp.nergaa.cloud/api/v1/instances" \
-H "Authorization: Bearer $API_KEY"
POST /api/v1/instances
Add a number (then link a phone to it).
| Body | Type | |
|---|
name | string | |
slug | string | Optional id; made from the name if left out. |
curl -X POST "https://whatsapp.nergaa.cloud/api/v1/instances" \
-H "Authorization: Bearer $API_KEY"
GET /api/v1/instances/{id}
One number's state.
curl -X GET "https://whatsapp.nergaa.cloud/api/v1/instances/sales-desk" \
-H "Authorization: Bearer $API_KEY"
DELETE /api/v1/instances/{id}
Unlink and delete a number.
curl -X DELETE "https://whatsapp.nergaa.cloud/api/v1/instances/sales-desk" \
-H "Authorization: Bearer $API_KEY"
POST /api/v1/instances/{id}/start
Start linking: returns a QR code to scan. The person opens WhatsApp → Linked devices → Link a device and scans `qr` (a PNG data URL). It changes about every 20 seconds; fetch it again with `GET …/qr`.
curl -X POST "https://whatsapp.nergaa.cloud/api/v1/instances/sales-desk/start" \
-H "Authorization: Bearer $API_KEY"
POST /api/v1/instances/{id}/pair
Start linking with a code typed on the phone.
| Body | Type | |
|---|
phone required | string | |
curl -X POST "https://whatsapp.nergaa.cloud/api/v1/instances/sales-desk/pair" \
-H "Authorization: Bearer $API_KEY"
GET /api/v1/instances/{id}/qr
The current QR or pairing code.
curl -X GET "https://whatsapp.nergaa.cloud/api/v1/instances/sales-desk/qr" \
-H "Authorization: Bearer $API_KEY"
POST /api/v1/instances/{id}/logout
Unlink the phone.
curl -X POST "https://whatsapp.nergaa.cloud/api/v1/instances/sales-desk/logout" \
-H "Authorization: Bearer $API_KEY"
Messages
Sending messages, and the message log.
POST /api/v1/instances/{id}/send
Send a text, image, video, audio, document, location or poll.
| Body | Type | |
|---|
to required | string | Phone with country code (`254712345678`), or a group id. |
text | string | |
media | object | |
location | object | |
poll | object | |
curl -X POST "https://whatsapp.nergaa.cloud/api/v1/instances/sales-desk/send" \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{"to":"254712345678","text":"Your order #1042 has shipped."}'
POST /api/v1/instances/{id}/check
Is this phone number on WhatsApp?.
| Body | Type | |
|---|
number | string | |
numbers | array | Several at once; the answer is then `results`. |
curl -X POST "https://whatsapp.nergaa.cloud/api/v1/instances/sales-desk/check" \
-H "Authorization: Bearer $API_KEY"
GET /api/v1/messages
The message log, newest first.
| Query | Type | |
|---|
instance | string | Only this number. |
direction | string | |
q | string | Search phone, name or text. |
before | integer | For paging: messages older than this id. |
limit | integer | |
curl -X GET "https://whatsapp.nergaa.cloud/api/v1/messages" \
-H "Authorization: Bearer $API_KEY"
Webhooks
Where incoming messages and status changes are posted.
GET /api/v1/webhooks
List webhooks.
curl -X GET "https://whatsapp.nergaa.cloud/api/v1/webhooks" \
-H "Authorization: Bearer $API_KEY"
POST /api/v1/webhooks
Receive events at a URL. Each POST is signed: `X-Webhook-Signature: sha256=<HMAC-SHA256 of the raw body with the secret>`.
| Body | Type | |
|---|
url required | string | |
events | array | |
instance | string | Only this number. |
format | string (flat, waclient) | |
curl -X POST "https://whatsapp.nergaa.cloud/api/v1/webhooks" \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{"url":"https://example.com/whatsapp","events":["message"]}'
DELETE /api/v1/webhooks/{id}
Stop a webhook.
curl -X DELETE "https://whatsapp.nergaa.cloud/api/v1/webhooks/sales-desk" \
-H "Authorization: Bearer $API_KEY"
Chats
Acting on messages already in a chat, groups, and the conversations on a number.
POST /api/v1/instances/{id}/messages/react
React to a message with an emoji (empty emoji removes it).
| Body | Type | |
|---|
chat_id required | string | The chat: a phone number or JID. |
message_id required | string | |
message_ids | array | For read: several at once. |
from_me | boolean | Whether this number sent it. |
participant | string | In a group: who sent it. |
emoji | string | |
text | string | |
to | string | |
curl -X POST "https://whatsapp.nergaa.cloud/api/v1/instances/sales-desk/messages/react" \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{"chat_id":"254712345678@s.whatsapp.net","message_id":"3EB0C1A2…","emoji":"👍"}'
POST /api/v1/instances/{id}/messages/delete
Delete a message for everyone.
| Body | Type | |
|---|
chat_id required | string | The chat: a phone number or JID. |
message_id required | string | |
message_ids | array | For read: several at once. |
from_me | boolean | Whether this number sent it. |
participant | string | In a group: who sent it. |
emoji | string | |
text | string | |
to | string | |
curl -X POST "https://whatsapp.nergaa.cloud/api/v1/instances/sales-desk/messages/delete" \
-H "Authorization: Bearer $API_KEY"
POST /api/v1/instances/{id}/messages/edit
Edit the text of a message you sent.
| Body | Type | |
|---|
chat_id required | string | The chat: a phone number or JID. |
message_id required | string | |
message_ids | array | For read: several at once. |
from_me | boolean | Whether this number sent it. |
participant | string | In a group: who sent it. |
emoji | string | |
text | string | |
to | string | |
curl -X POST "https://whatsapp.nergaa.cloud/api/v1/instances/sales-desk/messages/edit" \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{"chat_id":"254712345678","message_id":"3EB0C1A2…","text":"Corrected text"}'
POST /api/v1/instances/{id}/messages/read
Mark messages read (blue ticks).
| Body | Type | |
|---|
chat_id required | string | The chat: a phone number or JID. |
message_id required | string | |
message_ids | array | For read: several at once. |
from_me | boolean | Whether this number sent it. |
participant | string | In a group: who sent it. |
emoji | string | |
text | string | |
to | string | |
curl -X POST "https://whatsapp.nergaa.cloud/api/v1/instances/sales-desk/messages/read" \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{"chat_id":"254712345678","message_ids":["3EB0C1A2…"]}'
POST /api/v1/instances/{id}/messages/forward
Forward a recent message to another chat. Only messages sent or received since the number last connected can be forwarded. Counts as a message sent.
| Body | Type | |
|---|
chat_id required | string | The chat: a phone number or JID. |
message_id required | string | |
message_ids | array | For read: several at once. |
from_me | boolean | Whether this number sent it. |
participant | string | In a group: who sent it. |
emoji | string | |
text | string | |
to | string | |
curl -X POST "https://whatsapp.nergaa.cloud/api/v1/instances/sales-desk/messages/forward" \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{"to":"254700111222","chat_id":"254712345678","message_id":"3EB0C1A2…"}'
POST /api/v1/instances/{id}/presence
Show typing… or recording… in a chat.
| Body | Type | |
|---|
to required | string | |
presence | string (composing, recording, paused, available, unavailable) | |
curl -X POST "https://whatsapp.nergaa.cloud/api/v1/instances/sales-desk/presence" \
-H "Authorization: Bearer $API_KEY"
GET /api/v1/instances/{id}/groups
Groups this number is in, with participants.
curl -X GET "https://whatsapp.nergaa.cloud/api/v1/instances/sales-desk/groups" \
-H "Authorization: Bearer $API_KEY"
GET /api/v1/instances/{id}/chats
Conversations on this number, latest first. From the message log, so only messages that passed through this gateway.
curl -X GET "https://whatsapp.nergaa.cloud/api/v1/instances/sales-desk/chats" \
-H "Authorization: Bearer $API_KEY"
GET /api/v1/instances/{id}/chats/{chat}/messages
One conversation's messages, newest first.
| Query | Type | |
|---|
chat | string | A phone number or chat id (JID). |
limit | integer | |
before | integer | For paging: messages older than this id. |
curl -X GET "https://whatsapp.nergaa.cloud/api/v1/instances/sales-desk/chats/{chat}/messages" \
-H "Authorization: Bearer $API_KEY"
Catalog
The WhatsApp Business catalog of a linked business number, and syncing it from your item list.
GET /api/v1/instances/{id}/catalog
Products in a catalog, a page at a time.
| Query | Type | |
|---|
jid | string | Another business's catalog; this number's own if left out. |
limit | integer | |
cursor | string | |
curl -X GET "https://whatsapp.nergaa.cloud/api/v1/instances/sales-desk/catalog" \
-H "Authorization: Bearer $API_KEY"
POST /api/v1/instances/{id}/catalog/sync
Make the catalog match your item list. Products are matched by `retailer_id` (your item code). New ones are created, changed ones updated, and with `delete_missing` any product with a retailer_id not in the list is removed. Products without a retailer_id are never touched. `dry_run` reports what would change without changing anything.
| Body | Type | |
|---|
products required | array | |
delete_missing | boolean | |
update_images | boolean | Replace images on existing products too. |
dry_run | boolean | |
curl -X POST "https://whatsapp.nergaa.cloud/api/v1/instances/sales-desk/catalog/sync" \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{"products":[{"retailer_id":"ITEM-0001","name":"Blue mug","description":"350 ml","price":650,"currency":"KES","images":["https://example.com/mug.jpg"]}],"delete_missing":false}'
GET /api/v1/instances/{id}/collections
Catalog collections.
curl -X GET "https://whatsapp.nergaa.cloud/api/v1/instances/sales-desk/collections" \
-H "Authorization: Bearer $API_KEY"
POST /api/v1/instances/{id}/products
Add one product.
| Body | Type | |
|---|
name | string | |
description | string | |
price | number | |
currency | string | |
retailerId | string | Your item code. |
url | string | |
isHidden | boolean | |
images | array | |
curl -X POST "https://whatsapp.nergaa.cloud/api/v1/instances/sales-desk/products" \
-H "Authorization: Bearer $API_KEY"
DELETE /api/v1/instances/{id}/products
Delete products.
| Body | Type | |
|---|
productIds required | array | |
curl -X DELETE "https://whatsapp.nergaa.cloud/api/v1/instances/sales-desk/products" \
-H "Authorization: Bearer $API_KEY"
PATCH /api/v1/instances/{id}/products/{productId}
Change one product.
| Body | Type | |
|---|
name | string | |
description | string | |
price | number | |
currency | string | |
retailerId | string | Your item code. |
url | string | |
isHidden | boolean | |
images | array | |
curl -X PATCH "https://whatsapp.nergaa.cloud/api/v1/instances/sales-desk/products/{productId}" \
-H "Authorization: Bearer $API_KEY"
GET /api/v1/instances/{id}/orders/{orderId}
An order a customer sent from the catalog.
| Query | Type | |
|---|
orderId | string | |
token | string | The order's token, from the incoming order message. |
curl -X GET "https://whatsapp.nergaa.cloud/api/v1/instances/sales-desk/orders/{orderId}" \
-H "Authorization: Bearer $API_KEY"
Webhook payloads
Each event is POSTed as JSON. Answer with any 2xx within 15 seconds; server errors are retried with back-off.
{
"event": "message",
"session": "sales-desk",
"message": {
"message_id": "3EB0C767D26A1D4B",
"chat_id": "254712345678@s.whatsapp.net",
"from_me": false,
"wa_id": "254712345678",
"push_name": "Jane",
"message_type": "text",
"text": "Is my order ready?",
"timestamp": 1760000000
},
"at": "2026-10-07T09:30:00.000Z"
}
Verify the signature
X-Webhook-Signature: sha256=<hex> is the HMAC-SHA256 of the raw body with your webhook's secret.
const expected = "sha256=" + crypto.createHmac("sha256", secret).update(rawBody).digest("hex");
const valid = crypto.timingSafeEqual(Buffer.from(header), Buffer.from(expected));