Vatli REST API — overview and authentication
Base URL, API keys, scopes, the response envelope, error codes, rate limits and pagination.
The Vatli API lets your own systems send WhatsApp messages, manage contacts, read conversations and launch broadcasts — the same things you do in the dashboard.
Base URL
https://app.vatli.co/api/v1
All requests and responses are JSON over HTTPS.
Authentication
Every request carries an API key as a bearer token:
Authorization: Bearer vatli_live_xxxxxxxxxxxxxxxxxxxxxxxx
Keys are workspace-scoped: a key acts on the one workspace it was created in. Create keys in Settings → API keys — see Create and manage API keys.
Scopes
A key can do only what its scopes allow. Grant the minimum.
| Scope | Allows |
|---|---|
messages:send | Send WhatsApp messages |
messages:read | Read messages and delivery status |
contacts:read | List and read contacts |
contacts:write | Create and update contacts |
conversations:read | List and read conversations |
broadcasts:send | Launch broadcast campaigns and read their status |
webhooks:manage | Register and manage outbound webhooks |
A key with no scopes can still call GET /api/v1/me — useful to check a key works.
Response envelope
// success
{ "data": { /* ... */ } }
// failure
{ "error": { "code": "forbidden", "message": "This API key is missing the 'messages:send' scope" } }
Branch on error.code — it’s stable. error.message is for humans and may change.
| HTTP status | code | Meaning |
|---|---|---|
| 400 | bad_request | Malformed input |
| 401 | unauthorized | Missing, malformed, unknown, revoked or expired key |
| 403 | forbidden | Valid key, missing the required scope |
| 404 | not_found | No such resource (or it belongs to another workspace) |
| 429 | rate_limited | Rate limit exceeded |
| 500 | internal | Server error |
Rate limits
120 requests per minute per key. A 429 response includes:
Retry-After— seconds until you can retryX-RateLimit-Limit,X-RateLimit-Remaining,X-RateLimit-Reset
Pagination
List endpoints return up to limit items (default 50, max 100) and a cursor:
GET /api/v1/contacts?limit=50
→ { "data": [ … ], "meta": { "next_cursor": "eyJ…" } }
GET /api/v1/contacts?limit=50&cursor=eyJ…
→ { "data": [ … ], "meta": { "next_cursor": null } } // last page
Pass the cursor back exactly as you got it. next_cursor: null means there are no more pages.
Check your key
curl https://app.vatli.co/api/v1/me \
-H "Authorization: Bearer vatli_live_xxx"
{
"data": {
"account": { "id": "…", "name": "Acme Inc" },
"key": { "id": "…", "scopes": ["messages:send"] }
}
}
Endpoints
| Method & path | Scope | Guide |
|---|---|---|
GET /me | — | Above |
POST /messages | messages:send | Send messages |
GET /contacts, POST /contacts, GET/PATCH /contacts/{id} | contacts:read / contacts:write | Contacts API |
GET /conversations, GET /conversations/{id}, GET /conversations/{id}/messages | conversations:read, messages:read | Conversations API |
POST /broadcasts, GET /broadcasts/{id} | broadcasts:send | Broadcasts API |
POST/GET /webhooks, GET/PATCH/DELETE /webhooks/{id} | webhooks:manage | Webhooks |