Integrator reference

WhatsApp Gateway API

Consent-based single-recipient sends with hard quotas, pacing, and fan-out limits. Pair identities in the admin UI, then send with a scoped API token.

Getting started

Introduction

REST API under /v1. Integrators authenticate with an opaque API token. Identities are created and paired in the admin dashboard; tokens send only within their scope.

Base URL (local default): https://whatsapp.tag.mw/v1

Consent & risk

Only message people who expect contact. Linked unofficial sessions can be restricted without notice — keep daily limits low. This API reduces abuse risk; it does not ban-proof a line. Prefer the official Cloud API for high volume.

Getting started

Authentication

Request header
Authorization: Bearer <api_token_or_admin_jwt>
PrincipalBehavior
ALL_IDENTITIESToken may send using any identity (pass identity_id when required).
SINGLE_IDENTITYBound to one identity; identity_id may be omitted on send.
Admin JWTKeycloak admin role — full dashboard + identity/token management.

What a typical send token can call

POST /v1/messages, GET /v1/messages, GET /v1/messages/{id}, and (when scoped) pair/status/qr on its identity. Token create/revoke and identity CRUD are admin-only.

Getting started

Rate limiting

Global and per-token RPM apply. Per-identity velocity, min send spacing, warm-up daily ceilings, and identical-body fan-out caps also reject at create.

CodeMeaning
QUOTADaily/monthly/warm-up ceiling exhausted — nothing enqueued.
BROADCAST_LIMITSame body to too many distinct recipients this hour.
RATE_LIMITPer-identity velocity or send spacing.
DUPLICATEIdentical (identity, to, text) too recently.
SEND_DISABLEDIdentity send_enabled is false or paused.

Conventions

Lists & pagination

Response shape
{
  "data": [ /* … */ ],
  "pagination": {
    "total": 0,
    "page": 1,
    "page_size": 50,
    "has_more": false
  }
}

Conventions

Errors

Example
{
  "code": "QUOTA",
  "message": "Daily send limit exceeded"
}

Permanent transport rejects return 400 SEND_REJECTED with no outbox row. Transient transport failures may return 202 with status QUEUED.

Conventions

Idempotency

Pass Idempotency-Key on POST /v1/messages. Same key + same body → original response; different body → 409 IDEMPOTENCY_CONFLICT.

Endpoints

Health

GET/v1/healthPublic
GET/v1/readyPublic

/ready checks database and Redis connectivity.

Endpoints

Identities

Admin manages lines in the dashboard. Pairing and status are also available to scoped tokens.

GET/v1/identitiesAdmin
POST/v1/identitiesAdmin
GET/v1/identities/{id}Admin
PATCH/v1/identities/{id}Admin
POST /v1/identities
curl -X POST https://whatsapp.tag.mw/v1/identities \
  -H "Authorization: Bearer $ADMIN_JWT" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "OTP line",
    "phone_number": "265991234567",
    "daily_limit": 50
  }'

Pair / QR / status

POST/v1/identities/{id}/pairAdmin or token
GET/v1/identities/{id}/qrAdmin or token
GET/v1/identities/{id}/statusAdmin or token

Pair cooldown

Pair starts are limited per identity per hour. Prefer reconnect over repeated re-pair. When status becomes CONNECTED, send_enabled is turned on automatically (unless the line is blocked). Linked sessions stay offline by default; set mark_online if contacts should see the line as online. LOGGED_OUT means the device was unlinked — scan QR again.

Block / unblock

POST/v1/identities/{id}/blockAdmin
POST/v1/identities/{id}/unblockAdmin

Endpoints

Messages

POST/v1/messagesAPI token or admin

Single recipient only. to must be digits-only E.164 (8–15 digits). text max length ~4096.

POST /v1/messages
curl -X POST https://whatsapp.tag.mw/v1/messages \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
    "to": "265997654321",
    "text": "Your code is 123456",
    "origin": "api"
  }'
HTTPMeaning
201Sent immediately (status SENT).
202Queued for retry or scheduled (transient transport / send_at) — never over-quota.
429QUOTA / BROADCAST_LIMIT / RATE_LIMIT — no row created.

List, detail, queued

GET/v1/messagesAPI token or admin
GET/v1/messages/{id}API token or admin
GET/v1/messages/queuedAdmin

Tokens only see messages they created. Queued outbox listing is admin-only.

Endpoints

Tokens

GET/v1/tokensAdmin
POST/v1/tokensAdmin
POST/v1/tokens/{id}/revokeAdmin
POST /v1/tokens
curl -X POST https://whatsapp.tag.mw/v1/tokens \
  -H "Authorization: Bearer $ADMIN_JWT" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "otp-service",
    "scope": "SINGLE_IDENTITY",
    "identity_id": 1
  }'

Secret shown once

The plaintext token is returned only on create. Store it securely; revoke and mint a new one if lost.

Endpoints

Workspace settings

Admin-only workspace config: email-gateway integration, ops alert toggles, and production knobs (retention, circuit, pair cap, default limits). The API token is write-only and stored encrypted.

GET/v1/workspace/settingsAdmin
PATCH/v1/workspace/settingsAdmin
POST/v1/workspace/settings/test-emailAdmin

Ops alerts

Logout, bans, kill switch, circuit pause, pair cooldown, quota, abuse, send failure, and connector-down alerts are emailed through the email gateway using the stored token — not Keycloak users. Each toggle can be disabled; a Redis cooldown prevents flapping spam.