WAJIVAN
WhatsApp API
Send WhatsApp messages from your own software and receive replies and delivery updates, through your own WhatsApp Business number.तुमच्या स्वतःच्या WhatsApp Business नंबरवरून तुमच्या software मधून संदेश पाठवा आणि उत्तरं व delivery स्थिती मिळवा.
Quick start
- Connect your WhatsApp number in the WAJIVAN panel (Settings → Connect WhatsApp).
- Open the API tab and create a key. It is shown once.
- Call the API:
curl https://crm.rajeshchavan.org/api/public/v1/account \
-H "Authorization: Bearer wj_live_…"
curl -X POST https://crm.rajeshchavan.org/api/public/v1/messages \
-H "Authorization: Bearer wj_live_…" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: order-1042-confirmation" \
-d '{"to":"919800000001","type":"template","template":{"name":"hello_world","language":"en_US"}}'Success returns 202 with the WhatsApp message id: {"id":"wamid.…","to":"919800000001","type":"template","status":"accepted","client_ref":null}. Add "dry_run": true to check a request without sending anything.
Authentication
Send your key in every request: Authorization: Bearer wj_live_…. API access is part of the Sanjivani 999 and 1999 plans. Keys can be revoked any time in the panel; a revoked key stops working immediately. Never put a key in a web page or mobile app — call the API from your server.
Each key has a rate limit (default 60 requests per minute). Over the limit you get 429 with a Retry-After header.
Endpoints
Base URL: https://crm.rajeshchavan.org/api/public/v1
GET/account
Your workspace, plan and the connected WhatsApp number (quality, status).
Scope: account:read
POST/messages
Send a text, template, image or document. Free-form types need the customer to have written in the last 24 hours; otherwise send a template. Add Idempotency-Key to make retries safe; add dry_run:true to validate without sending.
Scope: messages:send
{
"to": "919800000001",
"type": "template",
"template": {
"name": "hello_world",
"language": "en_US"
},
"client_ref": "order-1042"
}GET/messages
List stored messages, newest first. Page with next_before.
Scope: messages:read
contact— Only this phone numberdirection— in or outsince— ISO time, inclusivebefore— ISO time, exclusive (use next_before from the last page)limit— 1–100, default 50
GET/messages/{id}
One message by its WhatsApp message id, with its delivery status.
Scope: messages:read
GET/templates
List your WhatsApp templates and their approval status.
Scope: templates:read
status— APPROVED, PENDING, REJECTED, PAUSED or DISABLEDname— Exact template namelimit— 1–100, default 50
POST/templates
Create a template. It is sent to WhatsApp for approval (status PENDING).
Scope: templates:write
{
"name": "order_update",
"language": "en_US",
"category": "UTILITY",
"components": [
{
"type": "BODY",
"text": "Hi {{1}}, your order {{2}} has shipped.",
"example": {
"body_text": [
[
"Asha",
"1042"
]
]
}
}
]
}GET/templates/{name}
Every language/version of one template.
Scope: templates:read
Message types for POST /messages: text (text), template (template.name, template.language, optional template.components), image and document (link https URL, optional caption, filename). client_ref (up to 64 characters) is echoed back in webhooks so you can match your own records. Phone numbers: digits with country code; a 10-digit Indian mobile gets 91 added; Devanagari digits are converted.
Webhooks
Set a webhook URL (https, a domain name) in the API tab. We send a POST with a JSON body for each event. Reply with any 2xx within 8 seconds. Otherwise we retry after 1 min, 5 min, 30 min, 2 h and 6 h, then mark it failed (you can retry it from the panel).
Events: message.received (a customer wrote to you), message.status (sent, delivered, read, failed for messages you sent), ping (the test button).
{
"id": "5b1c…", // delivery id (also in X-Wajivan-Delivery)
"type": "message.received",
"created": "2026-10-10T12:00:00.000Z",
"data": {
"id": "wamid.HBgM…", "contact": "919800000001", "name": "Asha",
"type": "text", "text": "नमस्कार", "media": null,
"timestamp": "2026-10-10T11:59:58.000Z"
}
}{
"id": "9e2a…", "type": "message.status", "created": "2026-10-10T12:00:03.000Z",
"data": { "id": "wamid.HBgM…", "contact": "919800000001", "status": "delivered",
"error": null, "client_ref": "order-1042", "timestamp": "2026-10-10T12:00:02.000Z" }
}Headers: X-Wajivan-Event, X-Wajivan-Delivery (use it to ignore duplicates) and X-Wajivan-Signature: t=<unix>,v1=<hex> — the HMAC-SHA256 of t + "." + raw body with your webhook secret. Always verify it and reject timestamps older than 5 minutes:
import crypto from "node:crypto";
// rawBody must be the exact bytes you received (before JSON.parse).
function verify(secret, header, rawBody, toleranceSec = 300) {
const m = /^t=(\d+),v1=([a-f0-9]{64})$/.exec(header || "");
if (!m) return false;
if (Math.abs(Date.now() / 1000 - Number(m[1])) > toleranceSec) return false; // replay protection
const expected = crypto.createHmac("sha256", secret).update(m[1] + "." + rawBody).digest("hex");
return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(m[2]));
}import hmac, hashlib, re, time
def verify(secret: str, header: str, raw_body: bytes, tolerance=300) -> bool:
m = re.fullmatch(r"t=(\d+),v1=([a-f0-9]{64})", header or "")
if not m or abs(time.time() - int(m[1])) > tolerance:
return False
expected = hmac.new(secret.encode(), m[1].encode() + b"." + raw_body, hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, m[2])Errors
Errors share one shape: {"error":{"code":"template_required","message":"…"}}.
| HTTP | code | Meaning |
|---|---|---|
| 400 | invalid_request / invalid_json / invalid_phone | The request is malformed. `details` lists the fields. |
| 401 | unauthorized | Missing, malformed, unknown or revoked key. |
| 403 | plan_required / forbidden / subscription_inactive | Your plan has no API, the key lacks the scope, or the subscription lapsed. |
| 404 | not_found | No such message or template in your workspace. |
| 409 | whatsapp_not_connected | Connect a WhatsApp number in the CRM first. |
| 413 | payload_too_large | Body larger than 64 KB. |
| 422 | opted_out / template_required / undeliverable / template_error / idempotency_conflict | The contact opted out, the 24-hour window is closed, the number is not on WhatsApp, a template problem, or a reused Idempotency-Key with a different body. |
| 429 | rate_limited / meta_rate_limited | Slow down. Honour the Retry-After header. |
| 502 | upstream_error / whatsapp_auth_error | WhatsApp did not accept the call or the connection must be re-authorised. |
WhatsApp rules you must follow
- 24-hour window. You may send free-form messages only within 24 hours of the customer's last message. Otherwise use an approved template.
- Opt-in. Message only people who agreed to hear from you on WhatsApp. You are responsible for consent.
- Quality. Many blocks or reports lower your number's quality rating and your sending limit. If quality turns red, sending may be paused.
- Billing. WhatsApp conversation charges are billed to you directly by Meta, not by WAJIVAN.
- Idempotency. Reuse the same
Idempotency-Keywhen retrying a send; you get the original result back withIdempotent-Replay: true.