WhatsApp Business Platform API
Create and manage WhatsApp templates, send individual messages, and dispatch bulk campaigns from your own application. Templates are approved by Meta and then referenced by name; message sends and campaigns both run against those approved templates.
| Document ID | Version | Status | Protocol | Authentication | Last updated |
|---|---|---|---|---|---|
| FON-API-WA-001 | 1.0 | Released | REST over HTTPS, JSON | Bearer token | 07 September 2026 |
1. Overview
An integration follows a fixed order. Create a template and wait for Meta to approve it, verify the approval, then send — either to a single number through the message sender, or to a list through the campaign creator. Nothing can be sent from an unapproved template.
BASE URL — https://app.fonada.ai/functions/v1
| Endpoint | Method | Purpose |
|---|---|---|
/whatsapp_templates | GET | List templates, optionally filtered by status or category. |
/whatsapp_template_manager | POST | Create, check status of, sync, or delete a template. The action field selects the operation. |
/whatsapp_message_sender | POST | Send a text, image, document, or interactive message to one number. |
/whatsapp_campaign_creator | POST | Send an approved template to an audience list in a single call. |
1.1 The 24-hour conversation window
Free-form messages — text, image, document, and interactive — may only be sent within 24 hours of the customer's last inbound message. Once that window closes, the send fails with error 131047 and a template message must be used instead. Template messages, including every campaign send, are not subject to the window.
1.2 Conventions used in this document
| Notation | Meaning |
|---|---|
| Required | The request is rejected if the field is absent. |
| Conditional | Required only when a related condition applies — the condition is stated in the description. |
| Optional | May be omitted. Any default is stated in the description. |
{{1}} | A numbered template variable. Values are supplied via sample_values at creation and BODY_n at campaign dispatch. |
fsk_… | Placeholder for your workspace API key. Replace it with your own value in every example. |
2. Authentication
All endpoints accept a bearer token in the Authorization header. Three credential types are supported; use the API key for server-to-server integrations.
| Credential | Format | Use |
|---|---|---|
| API key | fsk_… | Standard server-side integrations. Valid on every endpoint in this document. |
| WhatsApp API token | UUID | Account-scoped token. The account is implied by the token, so account_id is not sent. |
| Supabase JWT | JWT | Session-based access, used by the console. |
Authorization: Bearer fsk_your_api_key_here Content-Type: application/json
accountId is derived from the token and must not be included in template payloads. For message sends with an fsk_ key or JWT, account_id may be omitted when exactly one active WABA is linked to your user; include it in the body otherwise.
3. Template management
3.1 List templates
GET /whatsapp_templates — 100 requests / minute
Returns the templates available to your account. Use it to confirm the exact, case-sensitive template name before a send.
curl -G 'https://app.fonada.ai/functions/v1/whatsapp_templates' \ -H 'Authorization: Bearer fsk_your_key_here' \ --data-urlencode 'status=APPROVED'
| Query parameter | Required | Description |
|---|---|---|
status | Optional | Filter by approval status, for example APPROVED. |
category | Optional | Filter by category, for example MARKETING. See the dashboard for the exact filter values. |
{ "success": true, "data": { "templates": [ ... ] }, "count": N }3.2 Create a template
POST /whatsapp_template_manager — "action": "create"
A template defines the exact message structure Meta will approve. Once approved, reference it by name from campaigns and message sends.
Rules before creating
| Field | Rule |
|---|---|
name | Lowercase with underscores only — no spaces, uppercase, or hyphens. The name cannot be changed after creation. |
category | Uppercase: MARKETING, UTILITY, or AUTHENTICATION. |
language | Must include the locale — en_US, hi_IN, en_GB. A bare en is rejected. |
variables | Numbered sequentially — {{1}}, {{2}}, {{3}}. |
BODY | At least one BODY component is mandatory. |
Payload structure
{
"action": "create",
"templateData": {
"name": "your_template_name",
"category": "MARKETING",
"language": "en_US",
"components": [ ... ],
"sample_values": { "1": "example value" }
}
}accountId is auto-derived from your token — do not include it.
Example A — body-only template
A single-paragraph message with one variable, suitable for OTPs, order updates, or welcome messages.
curl -X POST 'https://app.fonada.ai/functions/v1/whatsapp_template_manager' \
-H 'Authorization: Bearer fsk_your_key_here' \
-H 'Content-Type: application/json' \
-d '{
"action": "create",
"templateData": {
"name": "welcome_new_customer",
"category": "MARKETING",
"language": "en_US",
"components": [{
"type": "BODY",
"text": "Welcome {{1}}! Thank you for joining us."
}],
"sample_values": { "1": "John Doe" },
"include_optout": true,
"optout_message": "Reply STOP to unsubscribe"
}
}'Example B — header, body, and footer
curl -X POST 'https://app.fonada.ai/functions/v1/whatsapp_template_manager' \
-H 'Authorization: Bearer fsk_your_key_here' \
-H 'Content-Type: application/json' \
-d '{
"action": "create",
"templateData": {
"name": "order_confirmed_full",
"category": "UTILITY",
"language": "en_US",
"components": [
{ "type": "HEADER", "format": "TEXT", "text": "Order Confirmed" },
{ "type": "BODY", "text": "Hi {{1}}, your order #{{2}} has been confirmed.\nTotal: Rs. {{3}}\nExpected delivery: {{4}}" },
{ "type": "FOOTER", "text": "Thank you for shopping with us!" }
],
"sample_values": { "1": "Priya Sharma", "2": "ORD-12345", "3": "1,999", "4": "Feb 28, 2026" }
}
}'Example C — template with action buttons
curl -X POST 'https://app.fonada.ai/functions/v1/whatsapp_template_manager' \
-H 'Authorization: Bearer fsk_your_key_here' \
-H 'Content-Type: application/json' \
-d '{
"action": "create",
"templateData": {
"name": "delivery_update_with_cta",
"category": "UTILITY",
"language": "en_US",
"components": [
{ "type": "BODY", "text": "Your order #{{1}} is out for delivery! Estimated arrival: {{2}}" },
{ "type": "BUTTONS", "buttons": [
{ "type": "URL", "text": "Track Order", "url": "https://yourstore.com/track/{{1}}" },
{ "type": "PHONE_NUMBER", "text": "Call Support", "phone_number": "+910000000000" }
]}
],
"sample_values": { "1": "ORD-98765", "2": "Today by 6 PM" }
}
}'Component constraints
| Component | Max per template | Max variables | Max length | Mandatory |
|---|---|---|---|---|
HEADER | 1 | 1 | 60 characters | No |
BODY | 1 | 10 | 1,024 characters | Yes |
FOOTER | 1 | None | 60 characters | No |
BUTTONS | 1 set | 3 buttons total | 20 characters per button | No |
Button types
| Type | Description | Required fields |
|---|---|---|
URL | Opens a website | text, url |
PHONE_NUMBER | Dials a number | text, phone_number |
QUICK_REPLY | Sends a pre-filled reply back to you | text |
Success response
{
"success": true,
"template": {
"id": "7119e2f3-7469-4cbe-a85b-5e7cf614ae03",
"template_name": "order_confirmed_full",
"status": "PENDING",
"category": "UTILITY",
"language": "en_US",
"created_at": "2026-02-26T12:00:00Z"
},
"message": "Template submitted to WhatsApp for review. Approval typically takes 24-48 hours."
}Common errors
| Message | Cause | Fix |
|---|---|---|
| action is required | Missing root-level action field | Add "action": "create". |
| templateData is required | Missing wrapper object | Wrap the template inside "templateData": {}. |
| Template name invalid | Name contains uppercase or spaces | Use lowercase with underscores only. |
| Language format should be locale-specific | Using en instead of en_US | Always include the locale, for example en_US or hi_IN. |
| BODY component is required | No BODY in the components array | Add { "type": "BODY", "text": "…" }. |
| Template already exists | Duplicate name | Names cannot be reused — choose a new one. |
3.3 Get template status
POST /whatsapp_template_manager — "action": "get_status"
curl -X POST 'https://app.fonada.ai/functions/v1/whatsapp_template_manager' \
-H 'Authorization: Bearer fsk_your_key_here' \
-H 'Content-Type: application/json' \
-d '{ "action": "get_status", "templateName": "order_confirmed_full" }'{
"success": true,
"template": {
"id": "7119e2f3-7469-4cbe-a85b-5e7cf614ae03",
"template_name": "order_confirmed_full",
"status": "APPROVED",
"rejection_reason": null,
"quality_score": "HIGH"
}
}| Status | Meaning | Next action |
|---|---|---|
PENDING | Under Meta review | Wait 24 to 48 hours, then poll again. |
APPROVED | Ready to use | Proceed to campaigns or message sends. |
REJECTED | Meta declined the template | Delete it and recreate under a different name. |
3.4 Sync templates from Meta
POST /whatsapp_template_manager — "action": "sync"
Pulls the latest template statuses from Meta into the Fonada database.
curl -X POST 'https://app.fonada.ai/functions/v1/whatsapp_template_manager' \
-H 'Authorization: Bearer fsk_your_key_here' \
-H 'Content-Type: application/json' \
-d '{ "action": "sync" }'3.5 Delete a template
POST /whatsapp_template_manager — "action": "delete"
A template in use by an active campaign cannot be deleted. Stop the campaign first.
curl -X POST 'https://app.fonada.ai/functions/v1/whatsapp_template_manager' \
-H 'Authorization: Bearer fsk_your_key_here' \
-H 'Content-Type: application/json' \
-d '{ "action": "delete", "templateName": "old_promo_v1" }'4. Message sending
POST /whatsapp_message_sender — 80 requests / second
Sends an individual message to one WhatsApp number. All four message types below are free-form and therefore restricted to the 24-hour conversation window described in section 1.1.
4.1 Text message
curl -X POST 'https://app.fonada.ai/functions/v1/whatsapp_message_sender' \
-H 'Authorization: Bearer fsk_your_key_here' \
-H 'Content-Type: application/json' \
-d '{
"to": "919876543210",
"message": {
"type": "text",
"text": { "body": "Hello! Your order has been dispatched and will arrive by tomorrow." }
}
}'| Field | Required | Description |
|---|---|---|
to | Required | Phone number with country code — no +, no spaces. For example 919876543210. |
message.type | Required | Set to text. |
message.text.body | Required | Message content. Maximum 4,096 characters. |
{
"success": true,
"data": {
"message_id": "wamid.HBgLOTE5ODc2NTQzMjEwFQIAERgS...",
"wa_id": "919876543210",
"status": "sent"
},
"performance": { "total_time_ms": 1682 }
}4.2 Image message
curl -X POST 'https://app.fonada.ai/functions/v1/whatsapp_message_sender' \
-H 'Authorization: Bearer fsk_your_key_here' \
-H 'Content-Type: application/json' \
-d '{
"to": "919876543210",
"message": {
"type": "image",
"image": {
"link": "https://yourcdn.com/products/item-001.jpg",
"caption": "Your ordered item — arrives by tomorrow!"
}
}
}'Requirements: JPEG or PNG, maximum 5 MB, caption up to 1,024 characters.
4.3 Document message
curl -X POST 'https://app.fonada.ai/functions/v1/whatsapp_message_sender' \
-H 'Authorization: Bearer fsk_your_key_here' \
-H 'Content-Type: application/json' \
-d '{
"to": "919876543210",
"message": {
"type": "document",
"document": {
"link": "https://yourcdn.com/invoices/INV-2026-001.pdf",
"filename": "Invoice_March2026.pdf",
"caption": "Your invoice for order ORD-12345"
}
}
}'Requirements: PDF, DOC, DOCX, XLS, XLSX, PPT, or PPTX, maximum 100 MB.
4.4 Interactive buttons
curl -X POST 'https://app.fonada.ai/functions/v1/whatsapp_message_sender' \
-H 'Authorization: Bearer fsk_your_key_here' \
-H 'Content-Type: application/json' \
-d '{
"to": "919876543210",
"message": {
"type": "interactive",
"interactive": {
"type": "button",
"body": { "text": "Your order ORD-12345 is ready for pickup. Confirm?" },
"action": {
"buttons": [
{ "type": "reply", "reply": { "id": "confirm_pickup", "title": "Yes, confirm" } },
{ "type": "reply", "reply": { "id": "reschedule", "title": "Reschedule" } },
{ "type": "reply", "reply": { "id": "cancel_order", "title": "Cancel order" } }
]
}
}
}
}'- Minimum 1 and maximum 3 buttons.
- title is limited to 20 characters.
- id is returned in the webhook when tapped — use it to identify the customer's choice.
- Must be sent within the 24-hour customer-initiated window.
4.5 Message status values
| Status | Meaning | Billing |
|---|---|---|
sent | Dispatched from Meta's servers | — |
delivered | Delivered to the recipient's device | Billed at this point |
read | Read by the recipient | — |
failed | Could not be delivered | Not billed |
Common errors on message sends
| Error | Code | Cause | Fix |
|---|---|---|---|
| Invalid phone number | 400 | Missing country code or wrong format | Use 919876543210 — no +, no spaces. |
| Re-engagement required | 131047 | 24-hour window closed | Switch to a template message. |
| Media type mismatch | 131053 | Wrong MIME type | Match the MIME type to the file extension. |
| Message undeliverable | 131026 | Number unreachable or blocked | Verify the phone number. |
| Rate limit exceeded | 133000 | More than 80 messages per second | Throttle your send rate. |
5. Campaigns
POST /whatsapp_campaign_creator
Use this endpoint to send the same approved template to many recipients in one call, with per-recipient variable values. The message sender targets a single number; the campaign creator accepts an audience list and handles bulk dispatch.
| Field | Required | Description |
|---|---|---|
campaign_name | Required | Unique name for this campaign run, in lowercase with underscores. Used for tracking and reporting in the dashboard. |
template_name | Required | Name of an approved template. Case-sensitive; must match the value listed by GET /whatsapp_templates. |
audience_rows | Required | Array of recipient objects. Each contains phone plus one key per template variable — BODY_1, BODY_2, … BODY_n. |
audience_rows[].phone | Required | Country code and number, no + prefix and no spaces. For example 917983272926. |
audience_rows[].BODY_n | Conditional | Value for the n-th variable in the template body. Required when the template contains {{n}} placeholders. Must start at BODY_1 and be consecutive. |
curl --location 'https://app.fonada.ai/functions/v1/whatsapp_campaign_creator' \
--header 'Authorization: Bearer fsk_your_key_here' \
--header 'Content-Type: application/json' \
--data '{
"campaign_name": "test_abc1",
"template_name": "test_abcd",
"audience_rows": [
{ "phone": "917983272926", "BODY_1": "test1" },
{ "phone": "917428346262", "BODY_1": "test1" }
]
}'{
"success": true,
"campaign": {
"id": "c3a1e2f4-9b7d-4e6a-a123-0d8f1e5c2b90",
"campaign_name": "test_abc1",
"template_name": "test_abcd",
"status": "launched",
"total_recipients": 2,
"queued_at": "2026-04-29T10:00:00Z"
}
}Common campaign errors
| Code | Cause | Fix |
|---|---|---|
| 400 | campaign_name or template_name missing | Include both fields in the request body. |
| 400 | audience_rows empty or missing | Provide at least one recipient object. |
| 404 | Template not found | Verify the exact name using GET /whatsapp_templates. |
| 409 | Campaign name already exists | Choose a unique campaign_name. |
| 402 | Insufficient credits | Top up the balance under Billing in the dashboard. |
| 133000 / 130429 | Rate limit exceeded | Throttle the send rate to 80 messages per second or lower. |
6. Error reference
6.1 HTTP status codes
| Code | Status | Meaning | Action |
|---|---|---|---|
| 200 | OK | Request succeeded | Process the response. |
| 207 | Multi-Status | Campaign saved but auto-launch failed | Use campaign.id to retry the launch. |
| 400 | Bad Request | Invalid payload or missing fields | Read the error field in the response body. |
| 401 | Unauthorized | Token missing, invalid, or expired | Regenerate your API token. |
| 402 | Payment Required | Insufficient credits | Top up under Billing in the dashboard. |
| 403 | Forbidden | Token does not own this resource | Verify the token matches the campaign or account. |
| 404 | Not Found | Campaign, template, or account not found | Verify the name or UUID. |
| 409 | Conflict | Duplicate name | Use a different name. |
| 500 | Internal Server Error | Server-side failure | Retry once; if it persists, contact support. |
| 503 | Service Unavailable | Fonada or Meta temporarily unavailable | Retry after a few minutes. |
6.2 WhatsApp error codes
These appear in the error_data.code field when Meta rejects a message.
| Code | Error | Cause | Fix |
|---|---|---|---|
| 130429 | Rate limit hit | Too many messages too quickly | Slow to 80 messages per second or lower. |
| 131047 | Re-engagement required | 24-hour conversation window closed | Use a template message. |
| 131026 | Message undeliverable | Number unreachable or blocked | Verify the phone number. |
| 131053 | Media type mismatch | Wrong MIME type | Match the MIME type to the file extension. |
| 133000 | Rate limit exceeded | Account messaging tier limit reached | Reduce volume or upgrade the tier. |
| 100 | Invalid parameter | Malformed request | Check the template structure and parameters. |
6.3 Troubleshooting
| Scenario | Cause | Fix |
|---|---|---|
| Template name lookup returns 404 | The name must match exactly, in lowercase, and the template must belong to the account tied to your token. | List templates with section 3.1 and verify the exact template_name. |
| API token returns 401 | The token is revoked, expired after its 365-day limit, or belongs to another account. | Generate a new token from the dashboard. |
7. Support
When raising a ticket, quote the message_id for a single send or the campaign id for a bulk send — these identify the exact dispatch in platform logs.
| Technical support | 1800 120 0081 |
| info@fonada.com | |
| Console | app.fonada.ai |
| Related documentation | WhatsApp onboarding, RCS Campaign API, KPI Analytics |
Appendix A — Field formats and rate limits
Phone number format
| Value | Valid | Note |
|---|---|---|
919876543210 | Yes | India — correct |
14155551234 | Yes | USA — correct |
9876543210 | No | Missing country code |
+919876543210 | No | Remove the + prefix |
91 9876543210 | No | Remove the space |
Date and time format (ISO 8601, UTC)
| Value | Valid |
|---|---|
2026-02-26T12:00:00Z | Yes |
2026-02-26T12:00:00.000Z | Yes |
26/02/2026 | No |
Feb 26, 2026 | No |
Template name format
| Value | Valid | Note |
|---|---|---|
order_confirmation_v2 | Yes | — |
welcome_customer_march2026 | Yes | — |
Order Confirmation | No | Spaces and uppercase not allowed |
order-confirmation | No | Hyphens not allowed |
OrderConfirmation | No | CamelCase not allowed |
WhatsApp messaging tiers (enforced by Meta)
| Tier | Messages per 24 hours | How to reach the next tier |
|---|---|---|
| Tier 1 | 1,000 | Message 1,000 unique users while maintaining good quality. |
| Tier 2 | 10,000 | Maintain consistent quality after Tier 1. |
| Tier 3 | 100,000 | Maintain consistent quality after Tier 2. |
| Tier 4 | Unlimited | Enterprise — contact Meta directly. |
API request limits (enforced by Fonada)
| Endpoint | Limit |
|---|---|
/whatsapp_message_sender | 80 requests per second |
/whatsapp_templates | 100 requests per minute |
/whatsapp_campaign_creator | Subject to the WhatsApp messaging tier limits above |
Appendix B — Revision history
| Version | Date | Summary of change | Author |
|---|---|---|---|
| 1.0 | 07 Sep 2026 | First released edition. Template management, message sending, campaign dispatch, error reference, and format appendix. | Platform Engineering |