HTTP API

Send WhatsApp messages from your CRM

Use the Send API from CRMs, automations, backend jobs, and support tools. v1 supports direct text, image, and document messages from the connected WhatsApp account.

Authentication

Send a Send API bearer token with every request. Send API tokens are separate from MCP tokens and only grant message-send access. Personal API usage sends from the WhatsApp account attached to the token owner. Owners and admins can also use workspace sender mode by passing a from number that belongs to the same workspace.

Authorization header
Authorization: Bearer YOUR_SEND_API_TOKEN

Endpoint

Send message endpoint
POST https://whatan.app/api/v1/messages/send

Sender Rules

Request shapeWho can use itSender behavior
from + toWorkspace owners and adminsSends from the connected workspace number in from.
to onlyOwners, admins, and membersSends from the WhatsApp account attached to that token.

Workspace Sender Mode

Use this mode for Attio workflows and other workspace-level automations that need to choose the sender at runtime. Include both from and to. The from number must be one of the connected WhatsApp numbers in this workspace. This mode is available to owner/admin tokens.

curl workspace sender message
curl -X POST "https://whatan.app/api/v1/messages/send" \
  -H "Authorization: Bearer YOUR_SEND_API_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: attio-workflow-123" \
  -d '{
    "from": "+917000000001",
    "to": "+917999709798",
    "type": "text",
    "text": "Following up from Attio."
  }'

The API normalizes from, finds the matching connected WhatsApp account in the workspace, and queues the send against that account. If the number is not part of the workspace, the request is rejected before sending.

Personal Sender Mode

This is the original Send API behavior and remains supported for backwards compatibility. Omit from; the bearer token determines the sender. Owners and members using this mode send only from their own connected WhatsApp account.

curl personal text message
curl -X POST "https://whatan.app/api/v1/messages/send" \
  -H "Authorization: Bearer YOUR_SEND_API_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: invoice-123-reminder" \
  -d '{
    "to": "+917999709798",
    "type": "text",
    "text": "Your invoice is ready."
  }'

Send Text

Text messages support both sender modes. Use from for workspace automation, or omit it for personal-token sending.

curl text message with from
curl -X POST "https://whatan.app/api/v1/messages/send" \
  -H "Authorization: Bearer YOUR_SEND_API_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: attio-workflow-123" \
  -d '{
    "from": "+917000000001",
    "to": "+917999709798",
    "type": "text",
    "text": "Following up from Attio."
  }'

Send Image

Image URLs must be public HTTPS URLs. Localhost and private network URLs are rejected.

curl image message
curl -X POST "https://whatan.app/api/v1/messages/send" \
  -H "Authorization: Bearer YOUR_SEND_API_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: promo-image-456" \
  -d '{
    "to": "+917999709798",
    "type": "image",
    "image": {
      "url": "https://example.com/promo.png",
      "caption": "New arrivals are live."
    }
  }'

Send Document

Documents use public HTTPS URLs. Provide a file name and MIME type when your CRM knows them.

curl document message
curl -X POST "https://whatan.app/api/v1/messages/send" \
  -H "Authorization: Bearer YOUR_SEND_API_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: quote-789" \
  -d '{
    "to": "+917999709798",
    "type": "document",
    "document": {
      "url": "https://example.com/quote.pdf",
      "fileName": "quote.pdf",
      "mimetype": "application/pdf",
      "caption": "Attached quote for review."
    }
  }'

Node Example

Node fetch
const response = await fetch("https://whatan.app/api/v1/messages/send", {
  method: "POST",
  headers: {
    Authorization: "Bearer YOUR_SEND_API_TOKEN",
    "Content-Type": "application/json",
    "Idempotency-Key": "attio-record-1001",
  },
  body: JSON.stringify({
    from: "+917000000001",
    to: "+917999709798",
    type: "text",
    text: "Thanks for contacting support. We are checking this now.",
  }),
});

const result = await response.json();

Idempotency

Include an Idempotency-Key header for every CRM event or automation run. If the CRM retries the same request with the same key, CRM returns the original send result instead of sending a duplicate WhatsApp message.

Queue, Pacing, and Rate Limits

The Send API stores every accepted request in the database with a queued status. In production, the worker checks the queue about every 10 seconds and examines up to 25 of the oldest queued requests during each check.

Pacing is calculated separately for each connected WhatsApp account. After the worker sends one message from an account, the next message from that same account must wait at least 3-8 seconds. Because the production worker checks every 10 seconds, one busy account normally sends about one message every 10 seconds, or about 6 messages per minute. The 3-8 second check prevents the worker from sending several messages from the same account during a single queue check.

Example: one account queues 200 messages

  1. All 200 accepted API requests are stored as queued.
  2. The worker loads the oldest 25. It sends the first message, then skips the other 24 because that account just sent.
  3. About 10 seconds later, the worker checks again and sends the next eligible message.
  4. At this pace, 100 messages take about 16 minutes 30 seconds after the first send, plus up to one initial worker interval.
  5. After the account reaches 100 API/MCP sends in the rolling 24-hour window, the remaining API messages stay queued. They resume as older sends fall outside that window.

The rolling limit is 100 combined API and MCP sends per WhatsApp account in 24 hours. API messages wait in the queue when the account has no remaining capacity. MCP sends use the same daily allowance but send immediately instead of using this API queue. Team inbox replies are immediate and are not part of the API/MCP daily allowance.

Repeating a request with the same Idempotency-Key returns the original attempt instead of creating a duplicate queued message.

The Send API is for transactional CRM messages, support replies, and expected automations. Bulk CSV/XLSX sending belongs in the upcoming Mass Messaging workflow, which will have campaign scheduling, reports, and dedicated safety controls.

Responses

Queued response
{
  "accepted": true,
  "sendAttemptId": "f1f7a5a0-2ff4-4ef7-b4bf-1a3b50ad6f53",
  "messageId": null,
  "remoteJid": null,
  "from": "+917000000001",
  "to": "+917999709798",
  "normalizedPhone": "917999709798",
  "status": "queued"
}

The Send API queues accepted requests. Use the send attempt ID to poll final status. Personal tokens can read their own send attempts. Owner/admin tokens can also read workspace sender mode attempts created from connected senders in the same workspace.

Status endpoint
GET https://whatan.app/api/v1/messages/SEND_ATTEMPT_ID
curl status
curl "https://whatan.app/api/v1/messages/SEND_ATTEMPT_ID" \
  -H "Authorization: Bearer YOUR_SEND_API_TOKEN"
Status response
{
  "sendAttemptId": "f1f7a5a0-2ff4-4ef7-b4bf-1a3b50ad6f53",
  "status": "accepted",
  "messageId": "BAE5...",
  "remoteJid": "[email protected]",
  "errorCode": null,
  "errorMessage": null,
  "createdAt": "2026-05-14T10:00:00.000Z",
  "updatedAt": "2026-05-14T10:00:04.000Z"
}

Error Codes

CodeMeaning
invalid_requestRequest JSON is missing required fields.
invalid_phone_numberPhone number must be international format.
whatsapp_not_connectedThe connected WhatsApp account is offline.
sender_selection_forbiddenThe token owner is not an owner or admin.
sender_not_allowedThe from number is not a sender in this workspace.
recipient_not_foundThe phone number is not reachable on WhatsApp.
invalid_media_urlMedia URL is not a safe public HTTPS URL.
idempotency_conflictThe key was reused with a different request.
rate_limitedThis WhatsApp account hit the v1 send limit.
WhatsApp can still limit or suspend accounts for unwanted or risky messaging. Start with expected, consent-based messages and avoid high-volume blasts from the Send API. Mass Messaging is an upcoming dedicated campaign feature with CSV/XLSX uploads, scheduling, reports, and additional safety controls.