Skip to content
PrasarOS

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

RequestPreview
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"]
    }
  }'
ResponsePreview
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.

HeadersPreview
webhook-id: evt_01J...
webhook-timestamp: 1767225600
webhook-signature: v1,K5o2...base64...=
Verify in Node.jsPreview
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.

ErrorPreview
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.