llm-ready-data / docs /whatsapp-gateway.md
validops-east-1's picture
sure
6cd5bf4
|
Raw
History Blame Contribute Delete
5.4 kB
# WhatsApp Service Gateway
The main FastAPI application (port **7860**) is the **public API gateway**. It
proxies every request under `/api/whatsapp/*` to the internal WhatsApp service
(a Go/whatsmeow application), which is not exposed publicly.
```text
Client
| HTTP
v
Main FastAPI :7860
| /api/whatsapp/...
v
WhatsApp Service (internal, e.g. http://localhost:8231)
|
v
Client
```
## Route mapping
The gateway forwards the **full path, query string, HTTP method and body**
unchanged. All routes require the main application's API key
(`Authorization: Bearer <API_KEY>`).
| Client request | WhatsApp service call |
|---|---|
| `GET /api/whatsapp/server/ok` | `GET /server/ok` (health) |
| `POST /api/whatsapp/instance/create` | `POST /instance/create` (admin) |
| `GET /api/whatsapp/instance/status` | `GET /instance/status` |
| `POST /api/whatsapp/send/text` | `POST /send/text` |
| `DELETE /api/whatsapp/instance/delete/:id` | `DELETE /instance/delete/:id` |
No path transformation is applied: after the `/api/whatsapp` prefix is stripped,
the rest of the path is appended to `WHATSAPP_SERVICE_URL`.
## Deployment model
Single Docker container (Hugging Face Spaces style): the Go binary is compiled
in a multi-stage `whatsapp-build` stage and embedded in the image at
`/app/whatsapp-service/server`. `start.sh` launches it as a sibling process and
`uvicorn` is the primary process. The gateway reaches it over loopback
(`http://127.0.0.1:8231`).
A crash of the WhatsApp service does **not** take the main app down: the gateway
returns sanitized `502`/`503` responses until it recovers (restart loop every
5s, degraded mode).
## Gateway behaviour
- **Auth:** the gateway requires the main app's Bearer API key. The WhatsApp
service's own `apikey` header is forwarded as-is when provided by the client
(per-instance token); otherwise the configured
`WHATSAPP_SERVICE_GLOBAL_API_KEY` is injected (admin routes).
- **Headers:** hop-by-hop headers and the gateway's `Authorization`/`Cookie` are
never forwarded. Response headers are whitelisted — internal
`Server`/`content-encoding`/hop-by-hop headers never reach the client.
- **Errors:** connection failures → `502`; timeouts → `504`; disabled service →
`503`. Upstream 4xx/5xx responses are passed through unchanged. Error bodies
never contain internal hostnames, URLs, exceptions or stack traces.
- **Payments/streaming:** responses are streamed back to the client (media/QR
downloads are not buffered).
## Configuration
| Variable | Default | Description |
|---|---|---|
| `WHATSAPP_SERVICE_ENABLED` | `false` | Enable the gateway routes. `start.sh` auto-enables it when the binary exists. |
| `WHATSAPP_SERVICE_URL` | `http://localhost:8231` | Base URL of the internal WhatsApp service. |
| `WHATSAPP_SERVICE_TIMEOUT` | `30` | Read/write/pool timeout for upstream calls (seconds). |
| `WHATSAPP_SERVICE_CONNECT_TIMEOUT` | `5` | Connect timeout for upstream calls (seconds). |
| `WHATSAPP_SERVICE_GLOBAL_API_KEY` | _(empty)_ | The WhatsApp service `GLOBAL_API_KEY`, injected as the default `apikey` header. |
| `WHATSAPP_SERVICE_PORT` | `8231` | Port `start.sh` uses to launch the embedded binary (`SERVER_PORT`). |
| `WHATSAPP_SERVICE_BINARY` | `/app/whatsapp-service/server` | Path to the embedded binary. |
### WhatsApp service env vars (centralized in the main app)
There is exactly **one** configuration source: the main application's `.env`
(or the deployment platform's environment). The Go service **never reads a
`.env` of its own**`start.sh` / the Docker image inject its variables as
process environment, and `--dev` only optionally loads a local `.env` if one
exists. Full reference: the WhatsApp section of `.env.example`.
Values shared with the main app use the same names (`SUPABASE_URL`,
`REDIS_URL`, ...). A few names are mapped automatically by `start.sh` so you
only configure one value:
| Centralized setting | Injected into Go service as |
|---|---|
| `SUPABASE_SERVICE_ROLE_KEY` | `SUPABASE_SERVICE_KEY` |
| `WHATSAPP_SERVICE_GLOBAL_API_KEY` | `GLOBAL_API_KEY` |
| `WHATSAPP_SERVICE_PORT` | `SERVER_PORT` |
Other Go-service settings configured centrally: `SUPABASE_DB_URL`,
`DATABASE_SAVE_MESSAGES`, `CLIENT_NAME`, `CONNECT_ON_STARTUP`, `DEBUG_ENABLED`,
`LOG_TYPE`, `WEBHOOK_FILES`, `OS_NAME`, `WHATSAPP_VERSION_*`, `MINIO_*`,
`AMQP_*`, `NATS_*`, `WEBHOOK_URL`, `PROXY_*`, `API_AUDIO_CONVERTER*`,
`EVENT_IGNORE_*`, `QRCODE_MAX_COUNT`, `CHECK_USER_EXISTS`, `LOG_*`.
> Configure `WHATSAPP_SERVICE_GLOBAL_API_KEY` (equivalently `GLOBAL_API_KEY`)
> once — it feeds both the gateway's default `apikey` header and the Go
> service's authentication.
## Health checks
The main app's `GET /health` now includes a non-fatal `whatsapp_service` block:
```json
{"configured": true, "reachable": true, "status": "ok"}
```
The WhatsApp service's own liveness endpoint is exposed through the gateway at
`GET /api/whatsapp/server/ok`.
## Testing
```bash
python -m pytest tests/test_whatsapp_gateway.py -v
```
Covers: gateway auth, forwarding (method/path/query/body/headers), apikey
injection vs pass-through, upstream 4xx/5xx passthrough, 502/503/504 handling,
response-header sanitization and the `/health` integration.
A full stack test:
```bash
docker build -t agentdeck-backend:test .
# run with the WhatsApp env vars above + WHATSAPP_SERVICE_ENABLED=true
```