API Documentation
Send and receive WhatsApp messages from your application via a single REST API. SAGE-API handles instance lifecycle, message routing, and webhook delivery — you authenticate with one key and call simple HTTP endpoints.
https://sageai.kavachbrowser.comGetting started
Three steps to send your first message:
- Create an account and verify your email.
- Provision an instance, scan the QR code with WhatsApp on your phone to pair it.
- Mint an API key. Plaintext is shown once — store it in your secrets manager.
Then use that key in the Authorization header on every API call.
Authentication
All API calls under /api/v1/instance/{name}/* require a SAGE-API key in theAuthorization header as a Bearer token.
Authorization: Bearer sage_kf3hJ2...XYzKeys are scoped to your account but can call any of your instances. They are not scoped per-instance in v1. Revoke a key from the API keys page at any time.
Send a text message
Send media
Send a location
Send a contact card
Rate limits
Every authed call against /api/v1/instance/{name}/* goes through a per-key sliding-window rate limit. The default cap is 60 requests / minute / API key. You can lower it when minting a key (Advanced → Rate limit) or edit it later.
Every response carries the current limit state in headers, so you don't have to guess:
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 47
Retry-After: 24 # only on 429 responsesWhen the bucket empties you get a 429:
HTTP/1.1 429 Too Many Requests
Retry-After: 24
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 0
{ "error": "rate_limited" }Need a higher cap or per-instance scope? Edit the key on the API keys page — you can pin a key to specific instances, raise / lower its rate limit, and / or restrict it to a CIDR allowlist of source IPs (only requests from those IPs validate).
Webhooks (receive events)
Configure a webhook URL on the Webhooks page and SAGE-API will POST events to it as JSON. Events include incoming messages, message-status updates, connection state, and group changes.
Example payload (incoming message)
{
"event": "MESSAGES_UPSERT",
"instance": "acme-prod",
"data": {
"key": { "remoteJid": "919999999999@s.whatsapp.net", "fromMe": false, "id": "..." },
"pushName": "Alice",
"messageType": "conversation",
"message": { "conversation": "Hello!" },
"messageTimestamp": 1735689600
}
}You can subscribe to a subset of event types. The most common ones are MESSAGES_UPSERT, CONNECTION_UPDATE, and SEND_MESSAGE_UPDATE.
Verifying webhook signatures
Every outbound delivery from SAGE-API carries an HMAC signature so you can confirm the request came from us and wasn't replayed. Headers on every POST:
X-Sage-Signature: sha256=<hex>
X-Sage-Timestamp: 1715234567
X-Sage-Instance: acme-prodThe signature is HMAC-SHA256(secret, "{timestamp}.{raw_body}"). Including the timestamp prevents replay; we recommend a 5-minute drift window.
Node 18+
import crypto from 'node:crypto';
export function verifySageWebhook(req, secret) {
const ts = req.headers['x-sage-timestamp'];
const sig = req.headers['x-sage-signature'];
if (!ts || !sig?.startsWith('sha256=')) return false;
if (Math.abs(Date.now() / 1000 - Number(ts)) > 300) return false; // 5-min replay window
const expected = crypto
.createHmac('sha256', secret)
.update(`${ts}.${req.rawBody}`) // raw body — NOT a JSON.parse round-trip
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(sig.slice(7), 'hex'),
Buffer.from(expected, 'hex'),
);
}Python 3.10+
import hmac, hashlib, time
def verify_sage_webhook(headers, raw_body, secret) -> bool:
ts = headers.get("x-sage-timestamp")
sig = headers.get("x-sage-signature", "")
if not ts or not sig.startswith("sha256="):
return False
if abs(time.time() - int(ts)) > 300:
return False
mac = hmac.new(
secret.encode(),
f"{ts}.{raw_body.decode() if isinstance(raw_body, bytes) else raw_body}".encode(),
hashlib.sha256,
).hexdigest()
return hmac.compare_digest(mac, sig[7:])Instance management (account-plane)
These endpoints use your session cookie from the dashboard, not a SAGE-API key. They're meant for dashboard automation; from your servers, prefer the data-plane endpoints above. List + create instances live under /api/v1/me/instances.
System status
Public health endpoint for uptime monitors. Always responds 200 — trigger your alert on the body's status field, not the HTTP code (a non-200 here would page the marketing site too).
Errors
All errors come back as JSON with an error field and an HTTP status code.
Need help? Contact support · Credits