Skip to main content

Waplify API — Complete Reference

This page contains every endpoint, request/response schema, and example in one place. Copy it and paste into any AI tool to generate integration code instantly.

AI-ready API reference

Copy this page and paste into ChatGPT, Claude, or Cursor to generate integration code

Setup

ItemValue
Base URLhttps://server.waplify.io
Auth HeaderAuthorization: Bearer wapl_your_api_key
Content-Typeapplication/json
Rate Limit100 requests/minute per API key
Phone FormatCountry code + number, no + sign (e.g., 911234567890)

1. Send Template Message

Send a WhatsApp message using an approved template. Works anytime (no 24-hour window restriction).

POST /api/v1/messages/send

Request:

{
"template_name": "order_confirmation",
"contact_phone": "911234567890",
"contact_name": "John Doe",
"body_data": {
"1": "John",
"2": "Premium Plan",
"3": "99"
},
"header_data": {
"1": "Daily Report"
},
"media_url": "https://example.com/image.png",
"filename": "Report.pdf",
"waba_phone_id": "123456789"
}
FieldRequiredDescription
template_nameYesTemplate name (case-sensitive)
contact_phoneYesWith country code, no +
contact_nameNoDefaults to "User #random"
body_dataNoTemplate body variables (required if template has {{1}} etc.)
header_dataNoFor TEXT header variables only
media_urlConditionalRequired if template has IMAGE/VIDEO/DOCUMENT header
filenameNoFor document templates
waba_phone_idNoDefaults to user's primary number

Response (200):

{
"status": "success",
"message": "Message sent successfully",
"message_id": "wamid.HBgNOTE4MDMxMjM0NTY3OA==",
"contact_id": "507f1f77bcf86cd799439012",
"template_name": "order_confirmation",
"timestamp": "2024-06-15T10:00:00Z"
}

Errors: 400 (missing variables, invalid phone, template not approved, media required), 401 (invalid API key), 404 (template not found), 429 (rate limit)

IMPORTANT — "success" means accepted, not delivered:

  • A "status": "success" response means WhatsApp has accepted the message — it does NOT mean it was delivered
  • Actual delivery status arrives later via webhooks: message.sentmessage.deliveredmessage.read
  • If delivery fails, you receive a message.failed webhook
  • You MUST set up webhooks to track actual delivery

Notes:

  • Contact auto-created if phone number doesn't exist
  • Variables can be positional ("1", "2") or named ("name", "amount")
  • Media limits: Image 5MB (JPEG/PNG), Video 16MB (MP4), Document 100MB (PDF/DOC/DOCX/PPT/PPTX/TXT)

2. Send Free-Form Message

Send a text or media message without a template. Only works within 24-hour window (contact must have messaged you in last 24 hours).

POST /api/v1/messages/send-message

Request:

{
"contact_phone": "911234567890",
"contact_name": "John Doe",
"message_type": "text",
"message": "Hello! How can I help?",
"media_url": "https://example.com/file.pdf",
"caption": "Here is the document",
"filename": "Report.pdf",
"waba_phone_id": "123456789"
}
FieldRequiredDescription
contact_phoneYesWith country code, no +
contact_nameNoDefaults to "User #random"
message_typeYestext, image, video, audio, or document
messageFor textText message body (max 4,096 chars)
media_urlFor mediaRequired for image/video/audio/document
captionNoCaption for image/video/document
filenameNoFor document type
waba_phone_idNoDefaults to user's primary number

Response (200):

{
"status": "success",
"message": "Message sent successfully",
"message_id": "wamid.HBgNOTE4MDMxMjM0NTY3OA==",
"contact_id": "507f1f77bcf86cd799439012",
"message_type": "text",
"timestamp": "2024-06-15T10:00:00Z"
}

Errors: 400 (invalid phone, missing message/media), 401 (invalid API key), 403 (24-hour window closed — use template endpoint instead), 429 (rate limit)

Note: 403 errors use detail field: {"detail": "Cannot send free-form message: ..."}

Media limits: Image 5MB (JPEG/PNG), Video 16MB (MP4), Audio 16MB (AAC/MP3/M4A/AMR/OGG), Document 100MB (PDF/DOC/DOCX/PPT/PPTX/TXT)


3. List Templates

Get all approved WhatsApp message templates.

GET /api/v1/templates/

Response (200):

{
"status": "success",
"templates": [
{
"id": "507f1f77bcf86cd799439012",
"name": "order_confirmation",
"category": "UTILITY",
"language": "en_US",
"status": "APPROVED",
"header_format": "IMAGE",
"body": "Hello {{1}}, your order {{2}} is confirmed for {{3}}.",
"requires_media": true,
"created_at": "2024-06-15T10:00:00Z"
}
],
"total": 1
}

Key fields: header_format (NONE/TEXT/IMAGE/VIDEO/DOCUMENT), requires_media (true = need media_url), body (parse {{1}} etc. for variable count)


4. List Contacts

GET /api/v1/contacts/?page=1&limit=20&search=john

ParamDefaultDescription
page1Page number
limit20Per page (max 100)
searchSearch name, phone, or email

Response (200):

{
"status": "success",
"contacts": [
{
"id": "507f1f77bcf86cd799439012",
"first_name": "John",
"last_name": "Doe",
"phone_number": "911234567890",
"email": "john@example.com",
"company": "Acme Corp",
"tags": ["vip"],
"opted_in": true,
"source": "api",
"created_at": "2024-06-15T10:00:00Z"
}
],
"total": 1,
"page": 1,
"limit": 20
}

5. Create Contact

POST /api/v1/contacts/

Request:

{
"phone_number": "911234567890",
"first_name": "John",
"last_name": "Doe",
"email": "john@example.com",
"company": "Acme Corp",
"tags": ["vip", "newsletter"]
}

Fields: phone_number (required), first_name (required), last_name (optional), email (optional), company (optional), tags (optional).

Response (201):

{
"status": "success",
"message": "Contact created successfully",
"contact": { /* same fields as list response */ }
}

6. Get Contact

GET /api/v1/contacts/{contact_id}

Response (200): Same as create contact response.


7. Delete Contact

DELETE /api/v1/contacts/{contact_id}

Response (200):

{
"status": "success",
"message": "Contact deleted successfully",
"contact_id": "507f1f77bcf86cd799439012"
}

Note: Soft delete — contact deactivated, not permanently removed.


8. List Groups

GET /api/v1/groups/?page=1&limit=20&search=vip

Response (200):

{
"status": "success",
"groups": [
{
"id": "507f1f77bcf86cd799439050",
"name": "VIP Customers",
"description": "High-value customers",
"tags": ["vip"],
"contact_count": 42,
"created_at": "2024-06-15T10:00:00Z"
}
],
"total": 1,
"page": 1,
"limit": 20
}

9. Create Group

POST /api/v1/groups/

Request:

{
"name": "VIP Customers",
"description": "High-value customers",
"tags": ["vip"],
"contact_ids": ["507f1f77bcf86cd799439012"]
}

Fields: name (required, unique per account), description (optional), tags (optional), contact_ids (optional — add contacts immediately).

Response (201):

{
"status": "success",
"message": "Contact group created successfully",
"group": { /* same fields as list response */ }
}

10. Get Group

GET /api/v1/groups/{group_id}


11. Delete Group

DELETE /api/v1/groups/{group_id}

Note: Contacts are NOT deleted — only removed from the group.


12. Add Contacts to Group

POST /api/v1/groups/{group_id}/contacts

Request:

{
"contact_ids": ["507f1f77bcf86cd799439012", "507f1f77bcf86cd799439013"]
}

Response (200):

{
"status": "success",
"message": "2 contact(s) added to group",
"group_id": "507f1f77bcf86cd799439050",
"contact_ids": ["507f1f77bcf86cd799439012", "507f1f77bcf86cd799439013"]
}

Duplicates are silently skipped.


13. Remove Contacts from Group

DELETE /api/v1/groups/{group_id}/contacts

Request:

{
"contact_ids": ["507f1f77bcf86cd799439012"]
}

Contacts are NOT deleted from your account — only removed from this group.


Webhooks

Configuration

Register endpoints at Developers > Webhooks in the dashboard.

SettingDefaultDescription
urlHTTPS URL to receive notifications
secretOptional HMAC-SHA256 signing secret
subscribed_eventsallWhich events to receive
retry_count3Max retries (0–10)
timeout5sRequest timeout (1–30s)

Events

EventWhen
message.sentMessage accepted by WhatsApp
message.deliveredDelivered to contact's phone
message.readRead by contact
message.failedDelivery failed
button.clickedButton interaction
message.receivedNew inbound message
message.replyReply to your outbound message

Payload — Message Status

{
"event": "message.delivered",
"timestamp": "2024-06-15T10:05:00",
"campaign_id": "507f1f77bcf86cd799439060",
"campaign_name": "Summer Promo",
"message": {
"message_id": "507f1f77bcf86cd799439070",
"contact_phone": "911234567890",
"contact_name": "John Doe",
"status": "delivered",
"previous_status": "sent",
"status_timestamp": "2024-06-15T10:05:00"
}
}

For message.failed, adds: error_message (string), error_code (number).

Payload — Inbound Message

{
"event": "message.received",
"timestamp": "2024-06-15T10:15:00",
"message": {
"message_id": "wamid.HBgNOTE4MDMxMjM0NTY3OQ==",
"contact_phone": "911234567890",
"contact_name": "John Doe",
"content": "Hi, I have a question",
"message_type": "text",
"timestamp": "2024-06-15T10:15:00",
"waba_phone_id": "123456789012345",
"is_reply": false,
"is_from_ad": false
}
}

Payload — Reply

{
"event": "message.reply",
"timestamp": "2024-06-15T10:10:00",
"campaign_id": "507f1f77bcf86cd799439060",
"campaign_name": "Summer Promo",
"original_message": {
"message_id": "507f1f77bcf86cd799439070",
"contact_phone": "911234567890",
"contact_name": "John Doe",
"sent_at": "2024-06-15T10:00:00"
},
"reply": {
"message_id": "507f1f77bcf86cd799439071",
"contact_phone": "911234567890",
"contact_name": "John Doe",
"content": "Yes, I'd like to know more!",
"message_type": "text",
"timestamp": "2024-06-15T10:10:00"
}
}

Signature Verification

Header: X-Webhook-Signature: sha256=<hex_digest>

Verify: HMAC-SHA256(your_secret, raw_request_body) must match the hex digest after sha256=.

Retry Policy

  • 2xx → success
  • 4xx (except 429) → not retried
  • 429/5xx/timeout → retried with exponential backoff (1s, 2s, 4s, 8s...)

Status Flow

pending → accepted → sent → delivered → read → clicked
↘ failed

Delivery Headers

Content-Type: application/json
User-Agent: Waplify-Webhook/1.0
X-Webhook-Signature: sha256=... (if secret configured)