API overview

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.

Two authentication schemes

| Use case | Scheme | Header |
|---|---|---|
| Admin / dashboard | JWT | Authorization: Bearer |
| Per-account WHAPI-style endpoints | Account token | Authorization: Bearer wapi_... |

See authentication.

Versioning

The current and only major version is v1, mounted at /api/v1.

Pagination

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"
}

Errors

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 |

Request IDs

Every response carries a request_id in the JSON body and the request-id header — useful when reporting bugs.

Single-domain note

The frontend uses relative paths (/api/v1/...), so the same build works on:




No rebuild is needed when moving domains.