# WA Gateway > WA Gateway connects your WhatsApp number to your website, shop, ERP and AI agents: send order updates, invoices and reminders, receive replies by webhook, and pay by M-Pesa or card. WA Gateway is a WhatsApp gateway: an account links WhatsApp numbers (as linked devices, like WhatsApp Web), then sends and receives messages through a REST API, signed webhooks or an MCP server. Billing is by plan, paid by M-Pesa or card through IntaSend. ## Rules for agents - Sign-up needs the owner: a 6-digit code goes to their WhatsApp and must be confirmed. Ask them for it. - Payments need the owner: you can start one, they approve it with their M-Pesa PIN or on the checkout page. - Only message people who expect it. Unsolicited bulk messages get numbers banned by WhatsApp. - Keep API keys secret; send them only as `Authorization: Bearer `. ## Quick start 1. List plans: `GET https://whatsapp.nergaa.cloud/api/v1/plans` 2. Start sign-up: `POST https://whatsapp.nergaa.cloud/api/v1/signup` with {email, phone, name}. The owner receives a code. 3. Confirm: `POST https://whatsapp.nergaa.cloud/api/v1/signup/verify` with {email, code}. Returns `api_key` and the first number's `instance_id`. 4. Link the number: `POST https://whatsapp.nergaa.cloud/api/v1/instances/{id}/start` returns a QR code (PNG data URL) for the owner to scan in WhatsApp → Linked devices. Or `POST …/pair` with {phone} for a code to type. 5. Send: `POST https://whatsapp.nergaa.cloud/api/v1/instances/{id}/send` with {to: "254712345678", text: "…"}. 6. Receive: `POST https://whatsapp.nergaa.cloud/api/v1/webhooks` with {url, events: ["message"]}. 7. Pay: `GET https://whatsapp.nergaa.cloud/api/v1/billing`, then `POST https://whatsapp.nergaa.cloud/api/v1/billing/pay` with {plan_id, method: "mpesa", phone} or {method: "checkout"} (gives a checkout_url for the owner). Follow `GET …/billing/payments/{id}`. ## Links - [API reference](https://whatsapp.nergaa.cloud/docs): every endpoint with examples - [OpenAPI 3.1](https://whatsapp.nergaa.cloud/openapi.json): machine-readable - [MCP server](https://whatsapp.nergaa.cloud/mcp): Streamable HTTP; tools for sign-up, numbers, messages, webhooks, billing - [Pricing](https://whatsapp.nergaa.cloud/pricing) - [Integrations](https://whatsapp.nergaa.cloud/integrations): WooCommerce, Shopify, ERPNext, n8n, Zapier, Make ## Plans - Starter (id `pln_c3813edb4c05d108bd22`): Free, 1 number(s), 5000 messages/month, 5-day trial - Test (id `pln_df0211fccbb2294ae016`): USD 1 per month, 1 number(s), 1000 messages/month, 1-day trial - Basic (id `pln_e85873bf89715ee1c1df`): USD 2 per month, 1 number(s), 1000 messages/month, 5-day trial - Basic Fremium (id `pln_a78f4d2f4d4c52a5af81`): USD 5 per month, 3 number(s), unlimited messages, 5-day trial - Premium (id `pln_c989131a9c4f8a118886`): USD 20 per month, 10 number(s), unlimited messages, 5-day trial ## Endpoints ### GET /api/v1/plans List the plans on offer. No API key needed. ### 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 API key needed. Body: - `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. Example: ```json {"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 API key needed. Body: - `email` (required): string - `code` (required): string ### GET /api/v1/me The account this key belongs to, its plan and usage. ### GET /api/v1/billing The subscription, plan, available plans and recent payments. ### 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: - `plan_id`: string. Leave out to renew the current plan. - `method` (required): string one of paypal, mpesa, checkout - `phone`: string. For `mpesa`: the number that gets the payment prompt. Example: ```json {"plan_id":"pln_3f9a…","method":"mpesa","phone":"254712345678"} ``` ### GET /api/v1/billing/payments/{id} A payment's current status. ### GET /api/v1/instances List the account's WhatsApp numbers. ### POST /api/v1/instances Add a number (then link a phone to it). Body: - `name`: string - `slug`: string. Optional id; made from the name if left out. ### GET /api/v1/instances/{id} One number's state. ### DELETE /api/v1/instances/{id} Unlink and delete a number. ### 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`. ### POST /api/v1/instances/{id}/pair Start linking with a code typed on the phone. Body: - `phone` (required): string ### GET /api/v1/instances/{id}/qr The current QR or pairing code. ### POST /api/v1/instances/{id}/logout Unlink the phone. ### POST /api/v1/instances/{id}/send Send a text, image, video, audio, document, location or poll. Body: - `to` (required): string. Phone with country code (`254712345678`), or a group id. - `text`: string - `media`: object - `location`: object - `poll`: object Example: ```json {"to":"254712345678","text":"Your order #1042 has shipped."} ``` ### POST /api/v1/instances/{id}/check Is this phone number on WhatsApp?. Body: - `number`: string - `numbers`: array. Several at once; the answer is then `results`. ### POST /api/v1/instances/{id}/messages/react React to a message with an emoji (empty emoji removes it). Body: - `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 Example: ```json {"chat_id":"254712345678@s.whatsapp.net","message_id":"3EB0C1A2…","emoji":"👍"} ``` ### POST /api/v1/instances/{id}/messages/delete Delete a message for everyone. Body: - `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 ### POST /api/v1/instances/{id}/messages/edit Edit the text of a message you sent. Body: - `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 Example: ```json {"chat_id":"254712345678","message_id":"3EB0C1A2…","text":"Corrected text"} ``` ### POST /api/v1/instances/{id}/messages/read Mark messages read (blue ticks). Body: - `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 Example: ```json {"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: - `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 Example: ```json {"to":"254700111222","chat_id":"254712345678","message_id":"3EB0C1A2…"} ``` ### POST /api/v1/instances/{id}/presence Show typing… or recording… in a chat. Body: - `to` (required): string - `presence`: string one of composing, recording, paused, available, unavailable ### GET /api/v1/instances/{id}/groups Groups this number is in, with participants. ### GET /api/v1/instances/{id}/chats Conversations on this number, latest first. From the message log, so only messages that passed through this gateway. ### GET /api/v1/instances/{id}/chats/{chat}/messages One conversation's messages, newest first. ### GET /api/v1/instances/{id}/catalog Products in a catalog, a page at a time. ### 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: - `products` (required): array - `delete_missing`: boolean - `update_images`: boolean. Replace images on existing products too. - `dry_run`: boolean Example: ```json {"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. ### POST /api/v1/instances/{id}/products Add one product. Body: - `name`: string - `description`: string - `price`: number - `currency`: string - `retailerId`: string. Your item code. - `url`: string - `isHidden`: boolean - `images`: array ### DELETE /api/v1/instances/{id}/products Delete products. Body: - `productIds` (required): array ### PATCH /api/v1/instances/{id}/products/{productId} Change one product. Body: - `name`: string - `description`: string - `price`: number - `currency`: string - `retailerId`: string. Your item code. - `url`: string - `isHidden`: boolean - `images`: array ### GET /api/v1/instances/{id}/orders/{orderId} An order a customer sent from the catalog. ### GET /api/v1/messages The message log, newest first. ### GET /api/v1/webhooks List webhooks. ### POST /api/v1/webhooks Receive events at a URL. Each POST is signed: `X-Webhook-Signature: sha256=`. Body: - `url` (required): string - `events`: array - `instance`: string. Only this number. - `format`: string one of flat, waclient Example: ```json {"url":"https://example.com/whatsapp","events":["message"]} ``` ### DELETE /api/v1/webhooks/{id} Stop a webhook. ## Webhooks Each event is POSTed as JSON with `X-Webhook-Signature: sha256=`. Events: message, message.sent, receipt (status 2 sent, 3 delivered, 4 read), connected, disconnected, logged_out, qr, pairing_code. ```json {"event":"message","session":"sales-desk","message":{"wa_id":"254712345678","push_name":"Jane","message_type":"text","text":"Is my order ready?"},"at":"2026-10-07T09:30:00Z"} ``` ## Errors 401 bad key · 402 subscription ended (pay first) · 403 suspended or plan limit · 404 not found · 409 number not connected · 429 too many requests or monthly limit.