Authentication
Secure your Zavu API requests with Bearer tokens. Test and live keys, project scoping, key rotation and best practices for keeping production
API Keys
All API requests require authentication using a Bearer token in the Authorization header.
terminalAuthorization: Bearer zv_live_xxxxxxxxxxxxxxxxxxxxxxxx
Key Types
| Prefix | Environment | Usage |
|---|---|---|
zv_live_ | Production | Real messages, real costs |
zv_test_ | Sandbox | WhatsApp only, to your team's own phones, from Zavu's sandbox number |
Creating API Keys
Your account is created with a live key already in it. It is on the dashboard home, masked, with a button to show it and a button to copy it — there is nothing to create before your first call.
To create another (one per machine, or one per environment):
- Log in to your Zavu Dashboard
- Navigate to API Keys
- Click Create API Key
- Give it a descriptive name (e.g., "Production Server", "Development")
- Copy the key
Using API Keys
In HTTP Requests
Include the key in the Authorization header:
terminalcurl https://api.zavu.dev/v1/messages \ -H "Authorization: Bearer zv_live_xxxxxxxxxxxxxxxx" \ -H "Content-Type: application/json"
In SDKs
TypeScriptimport Zavudev from '@zavudev/sdk'; const zavu = new Zavudev({ apiKey: process.env['ZAVUDEV_API_KEY'], // This is the default and can be omitted });
Optional Headers
| Header | Description | Example |
|---|---|---|
Zavu-Sender | Override the default sender | snd_abc123 |
Idempotency is not a header: send idempotencyKey in the request body, as shown below.
Zavu-Sender Header
Override the default sender for a specific request:
terminalcurl -X POST https://api.zavu.dev/v1/messages \ -H "Authorization: Bearer zv_live_xxx" \ -H "Zavu-Sender: snd_abc123" \ -H "Content-Type: application/json" \ -d '{"to": "+56912345678", "text": "Hello!"}'
Idempotency Keys
Prevent duplicate message sends due to network retries:
terminalcurl -X POST https://api.zavu.dev/v1/messages \ -H "Authorization: Bearer zv_live_xxx" \ -H "Content-Type: application/json" \ -d '{ "to": "+56912345678", "text": "Your order #12345 has shipped!", "idempotencyKey": "order-12345-shipped" }'
If you retry this request with the same idempotencyKey, you'll receive a 409 Conflict whose body is the original message, in its current state, instead of sending a duplicate. The SDKs raise that 409 as a ConflictError without retrying it; the original message is on the error's error property.
Security Best Practices
Do's
- Store keys in environment variables
- Use different keys for development and production
- Rotate keys periodically (every 90 days recommended)
- Use the minimum permissions needed
- Monitor key usage in your dashboard
Don'ts
- Don't commit keys to version control
- Don't share keys via email or chat
- Don't use production keys in development
- Don't embed keys in mobile apps or frontends
Frontend Integration
The Zavu API uses secret API keys that must never be exposed in client-side code. If you include your key in a browser app, anyone can open DevTools and steal it.
Instead, use the Backend-for-Frontend (BFF) pattern: your frontend calls your own server endpoint, and your server calls the Zavu API.
Server-side proxy examples
// app/api/send-message/route.ts
import Zavudev from '@zavudev/sdk';
const zavu = new Zavudev(); // reads ZAVUDEV_API_KEY from env
export async function POST(request: Request) {
const { to, text } = await request.json();
const result = await zavu.messages.send({ to, text });
return Response.json(result);
}
Frontend example
Reactasync function sendMessage(to: string, text: string) { const res = await fetch('/api/send-message', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ to, text }), }); return res.json(); }
Key Access
Every API key has full access to the project it belongs to: it can send, read and change anything that project holds. Keys cannot be scoped to a subset of operations today.
To limit what a piece of code can reach, give it a key from its own project. A sub-account is a separate project with its own keys, its own senders and data, and an optional spending limit.
Revoking Keys
If a key is compromised:
- Go to Settings → API Keys
- Find the compromised key
- Click Revoke
- Create a new key
- Update your applications
Revoked keys are immediately invalidated and cannot be restored.
Error Responses
| Status | Error | Description |
|---|---|---|
401 | unauthorized | Missing or invalid API key |
403 | varies | The account is not allowed to do this, for example sending_suspended or plan_limit_reached. The code says which |
429 | rate_limit_exceeded | Too many requests |
JSON{ "error": { "code": "unauthorized", "message": "Invalid API key" } }