Developer documentation
Connect a WhatsApp number, copy your API token, and start sending. Everything below
works against https://webwhatsapp.finocore.net.
API reference
Every endpoint lives under https://webwhatsapp.finocore.net and speaks JSON.
Sends are accepted asynchronously: the API returns 202 Accepted
with a message_id, and a background worker delivers the message.
Track the outcome by polling the message, or by subscribing a webhook.
Response envelope
Successful responses are { "success": true, "data": { ... } }.
Failures are { "success": false, "error": { "code", "message" } }.
The only exception is the compatibility GET /api/send_sms endpoint,
which returns a flat body for older integrations.
Authentication
Integrations authenticate with the account API token in the
X-API-Key header. The token identifies the
customer, and therefore which WhatsApp connections and message history the call can reach.
Dashboard endpoints (connecting WhatsApp, managing tokens and webhooks) use the
short-lived JWT from POST /api/v1/auth/login instead.
The two credentials are deliberately separate: a dashboard session can never send messages,
and a leaked API token can never change account settings.
- Send the token as a header, not a query parameter, wherever you can.
- The token is shown once. If it is lost, regenerate it from the panel.
- Regenerating or revoking a token stops the old one working immediately.
Send text
POST /api/v1/messages
Body
| Field | Type | Required | Notes |
|---|---|---|---|
| mobile | string | Yes | 10 digit Indian, or full international digits |
| message | string | Yes | Limited by your plan's maximum message length |
| session_id | string | No | Which connection sends it; defaults to your default connection |
Response 202
Idempotency
Send an Idempotency-Key header and a retry of the same
request returns the original message instead of sending twice. Keys are scoped to your account.
Send image
POST /api/v1/messages/image
The URL must be https and reachable. Content type and size are verified before the media is fetched, and private network addresses are refused.
Send document
POST /api/v1/messages/document
Send video
POST /api/v1/messages/video
Send audio
POST /api/v1/messages/audio
Message status
GET /api/v1/messages/{message_id}
Status moves forward only: QUEUED, PROCESSING, SENT, DELIVERED, READ, or FAILED.
Message history
GET /api/v1/messages
Filter with mobile, status,
type, direction,
sessionCode, from,
to and search.
Paginate with page and pageSize.
Compatibility GET API
GET /api/send_sms
Provided so an existing one-line integration keeps working. It runs through exactly the same validation, quota and queue as the POST API, and returns a flat body:
A token in a query string is recorded in server logs, proxy logs and browser history.
Prefer the X-API-Key header for anything new.
Webhooks
Configure one endpoint per account from the panel and subscribe to the events you care
about: message.sent,
message.delivered,
message.read,
message.failed,
message.received,
session.connected,
session.disconnected.
Payload
Verifying the signature
Each request carries X-WhatsApp-Timestamp and
X-WhatsApp-Signature. The signature is
sha256= followed by the hex HMAC-SHA256 of
{timestamp}.{raw body} using your webhook secret.
Reply with any 2xx status. A non-2xx response or a timeout is retried with backoff, and every attempt is recorded in the delivery log on the Webhooks page.
Errors
| Code | HTTP | Meaning |
|---|---|---|
| INVALID_API_TOKEN | 401 | The token is unknown or has been revoked |
| ACCOUNT_SUSPENDED | 403 | The account is suspended |
| IP_NOT_ALLOWED | 401 | The source address is not on your allow-list |
| WHATSAPP_NOT_CONNECTED | 409 | No connected WhatsApp session to send from |
| SESSION_NOT_FOUND | 404 | No such session on this account |
| INVALID_MOBILE | 422 | The number could not be normalised |
| MESSAGE_REQUIRED | 422 | The message body is missing |
| MESSAGE_TOO_LONG | 422 | Longer than the plan allows |
| MEDIA_URL_REQUIRED | 422 | The media URL is missing |
| INVALID_MEDIA_URL | 422 | Rejected by the media checks |
| MEDIA_NOT_ALLOWED | 403 | Media is not included in the plan |
| RATE_LIMIT_EXCEEDED | 429 | Too many requests this minute |
| PLAN_LIMIT_EXCEEDED | 429 | Monthly message allowance used up |
| MESSAGE_NOT_FOUND | 404 | No such message on this account |
| INTERNAL_ERROR | 500 | Quote request_id to support |
Rate limits
Limits come from your plan and apply per account per minute. Every response carries the current state:
On 429 a Retry-After header tells you how many
seconds to wait. Nothing is queued and nothing counts against your message allowance.
The full machine readable schema is at
/swagger/v1/swagger.json,
and you can try requests interactively in
Swagger UI.
A ready-to-import Postman collection ships in docs/postman.