Documentation

Everything you need to ship on WA-B.

Start with the 5-minute quickstart. Then dig into webhooks, the WhatsApp command language, MoMo billing, and the admin API.

Quickstart

Get a working WA-B install talking to the WhatsApp Cloud API in five minutes. Prerequisites: Node 18+, PostgreSQL 14+, ngrok, and a Meta WhatsApp Cloud API app.

# 1. Install
npm install

# 2. Create the database
createdb whatsapp_saas

# 3. Configure environment
cp .env.example .env

# 4. Run the migration
npm run migrate

# 5. Seed the SaaS plans + sample products
npm run seed

# 6. Issue an admin API key
npm run issue-key admin "my dashboard"

# 7. Start the dev server
npm run dev

Server boots on http://localhost:3000. Health check: GET /health.

Tip. Run ngrok http 3000 in a second terminal and paste the HTTPS URL into PUBLIC_BASE_URL so Meta, Paystack, and Hubtel can reach your webhooks.

Webhook setup

WA-B persists every inbound webhook event to a durable queue before returning 200 OK. A background processor drains the queue and retries failed events with exponential backoff (up to 8 attempts).

Meta (WhatsApp Cloud API)

In Meta for Developers → your app → WhatsApp → Configuration:

  • Callback URL: https://your-host/api/webhooks/whatsapp
  • Verify token: same value as WA_VERIFY_TOKEN in .env
  • Subscribe to the messages field

Tenant routing

Each business must have wa_phone_number_id set. This is how inbound webhooks are routed:

UPDATE businesses
   SET wa_phone_number_id = '<Phone Number ID from Meta>'
 WHERE id = '<your-business-uuid>';

Without this, inbound messages for that tenant are silently dropped (fail-safe: never leak between tenants).

WhatsApp command language

Customers and merchants drive WA-B by sending plain-text commands. They're case-insensitive and forgiving of punctuation.

CommandAudienceWhat it does
MENU / HICustomerWelcome message + Order Now button
ORDERCustomerOpen the product list
CANCELCustomerClear current cart
PAY / RENEWMerchantInitiate MoMo charge
STATUSMerchantPlan, period end, message quota
UPGRADEMerchantSwitch plans

API authentication

All mutating routes require an API key:

Authorization: Bearer sk_admin_xxxx
# or
X-Api-Key: sk_admin_xxxx

Two scopes are supported:

ScopeAccess
adminAll routes
tenantOwn business's orders & subscriptions only

Issue a tenant key:

npm run issue-key tenant <business-uuid> "POS station 1"

The plaintext key is printed once. Only a SHA-256 hash is stored. Revoke any time:

UPDATE api_keys SET revoked_at = NOW() WHERE id = '<key-uuid>';

Orders API

MethodPathAuth
GET/api/orders?business_id=...admin / tenant
GET/api/orders/:idadmin / tenant
POST/api/ordersadmin / tenant
PATCH/api/orders/:id/statusadmin / tenant
Looking for the full schema? The auto-generated OpenAPI spec is at /api/openapi.json on every WA-B install.