The Personal WhatsApp Gateway exposes a single-domain HTTP API.
Everything is served from one host:
https://example.com/ ← admin dashboard
https://example.com/api/v1/* ← REST API
https://example.com/api/openapi.json ← OpenAPI 3.0 spec
https://example.com/api/doc ← documentation landing
https://example.com/api/reference ← interactive Scalar reference
https://example.com/socket.io/ ← realtime QR/status (WebSocket)
You can also install the project under a subdomain — the rules are identical, just replace example.com with e.g. wa.example.com. No separate subdomains for API/docs/panel are ever needed.
| Use case | Scheme | Header |
|---|---|---|
| Admin / dashboard | JWT | Authorization: Bearer |
| Per-account WHAPI-style endpoints | Account token | Authorization: Bearer wapi_... |
See authentication.
The current and only major version is v1, mounted at /api/v1.
All list endpoints take limit (default 50, max 200) and a cursor (opaque id of the last returned item). The response is:
{
"items": [ /* ... */ ],
"next_cursor": "id-or-null"
}
Standard error shape:
{
"error": "ERROR_CODE",
"message": "Human-readable explanation",
"details": {},
"request_id": "req_abc123"
}
| HTTP | Code | Meaning |
|---|---|---|
| 400 | VALIDATION_ERROR | request body failed Zod validation |
| 400 | AI_NOT_CONFIGURED | no API key set for AI |
| 400 | NOT_CONNECTED | account WhatsApp session not active |
| 401 | UNAUTHORIZED | missing/invalid token |
| 404 | NOT_FOUND | resource doesn't exist |
| 409 | CONFLICT | duplicate resource |
| 429 | RATE_LIMIT | per-token rate limit hit |
| 500 | INTERNAL | server-side error |
Every response carries a request_id in the JSON body and the request-id header — useful when reporting bugs.
The frontend uses relative paths (/api/v1/...), so the same build works on:
http://localhosthttps://example.comhttps://wa.example.comNo rebuild is needed when moving domains.