Docs / API reference
API reference
Send WhatsApp messages from your own software, and receive every inbound message and delivery update on your own server. No dashboard required once you have a key.
Authentication
Every request needs your API key, as a header:
Authorization: Bearer <your API key>
or
X-API-Key: <your API key>
Create and revoke keys from your eSampark dashboard (Developer Access panel, under the API tab). A key is shown once, at creation — copy it then, because it can't be shown again.
A new key can be scoped to send (sending messages, running broadcasts) or manage (templates, business profile, media, bots), or left with both — the dashboard calls that “full access.” Scope a key to just what your integration actually does; a leaked send-only key can't touch your templates or profile.
Endpoints
POST /api/messages/send | Send a text, template, media, or interactive (buttons/list) message. |
GET /api/messages/status?id=… | Look up what happened to a message you sent. |
POST /api/campaigns | Create a broadcast campaign. |
POST /api/campaigns/[id]/run | Start sending a campaign. |
GET/POST /api/templates | List or create WhatsApp templates. |
GET/POST /api/bots | List or manage bot flow definitions. |
GET/PUT /api/business-profile | Read or update your WhatsApp business profile. |
POST /api/business-profile/picture | Set the profile picture. |
POST /api/media/upload | Upload media to attach to a send. |
GET/POST /api/conversational-components | Manage WhatsApp Flows components. |
Sending a message
POST /api/messages/send
{
"wabaId": "<your WABA id>",
"to": "919876543210",
"kind": "template",
"templateName": "order_confirmation",
"templateParams": ["Asha", "#1234"],
"consentConfirmed": true
}kindis"text"(default),"template","media", or"interactive".- Outside WhatsApp's 24-hour customer-service window, only a template send succeeds — WhatsApp enforces this, not eSampark.
consentConfirmed: trueis required the first time you message a recipient with no consent record. Remembered after that.- A template that's rejected or paused is refused with a plain reason, before anything is sent.
The response hands back WhatsApp's own message id:
{ "ok": true, "result": { "messages": [{ "id": "wamid.HBgL..." }] } }Reply buttons and lists
Up to 3 reply buttons, or a list of up to 10 rows across one or more sections. Both only deliver inside the 24-hour window, same as a text message.
{
"wabaId": "<your WABA id>",
"to": "919876543210",
"kind": "interactive",
"consentConfirmed": true,
"interactive": {
"kind": "buttons",
"bodyText": "Would you like to confirm your order?",
"buttons": [
{ "id": "confirm", "title": "Yes, confirm" },
{ "id": "cancel", "title": "No, cancel" }
]
}
}Limits: a button title is 20 characters, its id 256; a list row title is 24 characters, its description 72, its id 200, the list's button label 20; at most 10 rows total. The reply a customer taps arrives on your webhook as an ordinary "message" event, with choice: { id, title } carrying which one.
Checking what happened to a message
GET /api/messages/status?id=<waMessageId>
<waMessageId> is the id sending a message handed back, above. A pull, not a replacement for the webhook — use this to check a specific message right now; use the webhook if you need to know the moment something changes.
{
"ok": true,
"waMessageId": "wamid.HBgL...",
"to": "919876543210",
"status": "delivered",
"errorCode": null,
"friendlyStatus": { "label": "Delivered" },
"sentAt": "2026-10-12T10:00:00.000Z",
"updatedAt": "2026-10-12T10:00:05.000Z"
}status is WhatsApp's own word — sent, delivered, read, or failed — absent until the first status event arrives, usually seconds after the send. A 404 means eSampark has no record of that id for your account.
Webhooks — events sent to your server
Set your endpoint in the dashboard's Developer Access panel. eSampark POSTs to it for an inbound message ("message"), a delivery status update ("status"), or a copy of your own outbound send ("message_echo").
{
"type": "message",
"from": "919876543210",
"contactName": "Asha",
"messageId": "wamid.HBgL...",
"messageType": "text",
"text": "Yes, confirm my order",
"timestamp": "1757620800",
"wabaId": "<your WABA id>",
"phoneNumberId": "<the sending number's id>"
}Verifying the signature
Every request carries X-eSampark-Signature-256: sha256=<hex hmac>, computed over the raw request body with your signing secret (shown once, same place as your API key).
import crypto from "node:crypto";
function fromESampark(rawBody, header, secret) {
const expected =
"sha256=" + crypto.createHmac("sha256", secret).update(rawBody, "utf8").digest("hex");
return header.length === expected.length &&
crypto.timingSafeEqual(Buffer.from(header), Buffer.from(expected));
}Use the exact raw bytes of the body — re-serializing a parsed object can reorder keys and break the check.
Prove it reaches you, before you build on it
Point your webhook target at https://esampark.lifesecret.co/api/dev/webhook-echo and press “Send a test event” in the dashboard first. It's a real endpoint that only logs what arrives and answers 200 — a successful test confirms delivery actually works over a real network hop, before you point the same target at your own, more complex receiver.
Not reachable with an API key
Dashboard login only, for now: reading contacts, browsing full inbox/message history, pausing or cancelling a campaign, changing your webhook target, managing API keys themselves. If your integration needs one of these, ask — this is current behavior, not a finalized design.
Rate limits
Per account, not per key: a requests-per-minute cap and a daily message cap, both set by eSampark. No per-key breakdown yet if you're using more than one key.
Known gaps, stated directly
- Webhook delivery gets one retry on a timeout, network error, or 5xx — never on a 4xx. Beyond that, a still-down endpoint means that event isn't redelivered; there's no queue behind it.
- No per-key usage attribution — a tenant's rate limits are shared across all of that tenant's keys.
- No machine-readable spec yet (no OpenAPI/Swagger JSON, no Postman collection).
Questions, or something looks wrong?
Contact whoever gave you access to eSampark. Don't guess at an undocumented field — ask, and this page gets corrected.