Developers · Coming soon
The PrasarOS API. Coming soon.
Connect your website, app or billing software to WhatsApp: send order and delivery updates, keep contacts in sync and get replies back. The API is not open yet. Everything below is a preview of how it will work and may change before launch.
What you will be able to do
Everything your software needs.
Send templates and messages
Send approved templates with variables, and text or media replies inside the 24-hour window. Calls are accepted at once and queued, so your app never waits on delivery.
Manage contacts
Create and update contacts by phone number, with tags, fields and opt-in records. Look a contact up by phone before you message them.
Signed webhooks
Get delivery, read, failure and reply events posted to your server, each one signed so you can prove it came from us.
API keys with scopes
Create keys in Settings and give each only what it needs, like sending messages or reading contacts. Keys are shown once.
Test mode
Test keys run against a simulated WhatsApp: no real messages, no charges, and webhooks still fire.
No-code toolsComing soon
The same API will power connectors for popular no-code automation tools.
How it will work
A preview of the API.
Base URL and authentication
Every request goes to https://api.prasaros.com/v1 over HTTPS. You create API keys in Settings and choose their scopes (for example messages:write or contacts:read). Live keys start with pk_live_, test keys with pk_test_. Send the key as Authorization: Bearer <key>. A key is shown once; keep it on your server, never in a browser or app.
Send a template
curl -X POST https://api.prasaros.com/v1/messages \
-H "Authorization: Bearer pk_test_..." \
-H "Content-Type: application/json" \
-H "Idempotency-Key: order-1042-shipped" \
-d '{
"to": "+919812345678",
"type": "template",
"template": {
"name": "order_shipped",
"language": "en",
"variables": ["Asha", "1042"]
}
}'HTTP/1.1 202 Accepted
X-Request-Id: req_8f2c...
{
"id": "msg_01J...",
"status": "queued",
"to": "+919812345678"
}Only contacts with a recorded opt-in can be sent templates, and anyone who replies STOP is opted out at once.
Signed webhooks
Events such as message.delivered, message.read, message.failed and message.received (a customer reply) are posted to the HTTPS endpoint you add in Settings. Each one carries an id, a timestamp and an HMAC-SHA256 signature of id.timestamp.body, made with your endpoint secret. Answer with a 2xx within 10 seconds; failed deliveries are retried with back-off.
webhook-id: evt_01J...
webhook-timestamp: 1767225600
webhook-signature: v1,K5o2...base64...=import { createHmac, timingSafeEqual } from 'node:crypto'
// secret: the "whsec_..." value shown when you add the endpoint in Settings.
export function verifyWebhook(rawBody, headers, secret) {
const id = headers['webhook-id']
const timestamp = headers['webhook-timestamp']
const signatures = String(headers['webhook-signature'] ?? '')
// Refuse old or future-dated events (5-minute tolerance) to stop replays.
const age = Math.abs(Date.now() / 1000 - Number(timestamp))
if (!id || !timestamp || !(age <= 300)) return false
const key = Buffer.from(secret.replace(/^whsec_/, ''), 'base64')
const expected = createHmac('sha256', key)
.update(`${id}.${timestamp}.${rawBody}`)
.digest()
// Several signatures may be sent while a secret is being rotated.
return signatures.split(' ').some((part) => {
const [version, sig] = part.split(',')
if (version !== 'v1' || !sig) return false
const given = Buffer.from(sig, 'base64')
return given.length === expected.length && timingSafeEqual(given, expected)
})
}Rate limits and idempotency
Each workspace has a request rate based on its plan. Every response carries X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset; a 429 also carries Retry-After. Sending speed on WhatsApp is separate: messages are accepted, queued and sent as fast as your number allows.
Send an Idempotency-Key header on every POST. If you retry with the same key within 24 hours, you get the first answer back (marked Idempotent-Replayed: true) and the customer never gets the message twice.
Errors
Errors use standard HTTP status codes and one JSON shape, with a stable code to branch on and a message for people. Quote the request_id when you contact support.
HTTP/1.1 422 Unprocessable Entity
{
"error": {
"type": "invalid_request",
"code": "template_not_approved",
"message": "Template order_shipped is not approved yet",
"param": "template.name",
"request_id": "req_8f2c..."
}
}Early access
Want in early?
Tell us what you want to connect and we will invite you as soon as the API opens.