Send a WhatsApp Message
Sends a free-form text message to a WhatsApp recipient. Free-form text is restricted to Meta's 24-hour customer-service window — the customer must have messaged the agent within the last 24 hours. For sends outside the window, use Send Template instead.
Which endpoint do I call?
POST to /v1/whatsapp/messages over HTTPS. The endpoint requires the whatsapp:send scope on your API key — see Authentication for how scopes work.
POST /v1/whatsapp/messages
What does the request look like?
curl -X POST https://api.mojeeb.app/v1/whatsapp/messages \
-H "Authorization: Bearer mk_live_YOUR_KEY_HERE" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: reply-to-ticket-9001" \
-d '{
"agent_id": "12345678-1234-1234-1234-123456789012",
"from": "+15557654321",
"to": "+15551234567",
"text": { "body": "Thanks for reaching out! How can I help?" }
}'
What goes in the request body?
Four required fields. The agent and from together identify which WhatsApp number you're sending from; to and text.body carry the destination and the message itself.
| Field | Type | Required | Description |
|---|---|---|---|
agent_id | UUID | Yes | The agent to send from. Must be authorized for this API key. |
from | E.164 string | Yes | The WhatsApp business number to send from. Must match an active WhatsApp connection on the agent. |
to | E.164 string | Yes | Recipient's phone, e.g. +15551234567. |
text.body | string | Yes | The message text. Its length limit is in the reference. |
Which optional headers should I send?
Two are worth knowing about — both improve reliability and traceability without changing what gets sent.
| Header | Purpose |
|---|---|
Idempotency-Key | Make retries safe. See Idempotency. |
X-Correlation-ID | Custom trace id we'll honor when valid and reflect in the response; see Errors for the rules. |
What does a success response look like?
HTTP 202 Accepted with the message object: its id, status: "queued", the agent_id and to you sent, type: "text", and created_at. Every field, with an example, is in the reference for this endpoint, rendered from the API's own contract so it is never out of date.
The 202 means the message is queued for delivery. Use the returned id with Get Message Status to track delivery.
What can go wrong?
The standard error envelope is returned. Common codes are below; branch on code (stable) — never on message (may be reworded). The full catalog is on the Errors page.
code | HTTP | When |
|---|---|---|
invalid_request_body | 422 | Required field missing — param names which |
invalid_phone_number | 422 | to isn't valid E.164 |
invalid_from_phone | 422 | from isn't valid E.164 |
from_phone_not_found_for_agent | 422 | from doesn't match any active WhatsApp connection — available_phones lists what would work |
agent_not_authorized | 403 | API key isn't allowed to use this agent |
insufficient_scope | 403 | API key lacks whatsapp:send |
rate_limit_exceeded | 429 | Per-key budget hit — see Rate Limits |
What about the 24-hour window?
WhatsApp Business rules require free-form text to be sent inside the 24-hour customer-service window — the customer must have messaged the agent within the last 24 hours. Outside this window, Meta will reject delivery even though Mojeeb accepts the request and returns a 202.
If you send free-form outside the window, the immediate response is still 202 (we accept and queue), but the message will transition to status: "failed" with a populated failed_at once Meta rejects delivery. Poll Get Message Status to see this happen. A failed send is retried a few times, so wait a couple of minutes before treating failed as final; see Is failed final?
For sends outside the window, use a pre-approved template instead — templates can be sent at any time.
Common questions
Can I send media (images, audio, documents)?
Not in v1 of the public API. Media support is reserved as an additive change. Use the dashboard for media sends in the meantime.
What's the maximum body length?
The exact limit is in the reference for this endpoint; it matches WhatsApp's own limit. Longer bodies are rejected with invalid_request_body.
Does the API check whether the recipient is inside the 24h window?
No — Meta enforces the window, not us. The API accepts your request and queues the send; if Meta rejects on delivery, you'll see status: "failed" on the message status lookup.
Can the same number send to itself?
You can't send to your own business number — Meta rejects this at the platform level. The send returns 202 from us but failed on status lookup.