WACM.in Logo
Back to API Docs

WhatsApp Business API

Wpbox API Reference

Integrate with WhatsApp Cloud API to send messages, manage contacts, run campaigns, and automate customer communication at scale.

WhatsApp API - LLM Context

LLM Ready

Feed complete WhatsApp Business API specs directly to your AI agent or coding assistant.

Download .mdOpenAPI 3.1
Machine-Readable Feeds:/llms.txt /llms-full.txt

Overview

The Wpbox API provides programmatic access to WhatsApp Business features. Built on top of the Meta WhatsApp Cloud API, it enables you to send messages, manage contacts, create campaigns, and work with approved message templates.

Base URL

https://app.wacm.in/api/v1

All endpoints require authentication via Bearer token or query parameter. The API supports standard RESTful conventions with JSON request and response bodies.

Pagination

List endpoints (contacts, campaigns, conversations) return paginated responses. Use ?page= and ?limit= query parameters:

Paginated Request
curl -H "Authorization: Bearer YOUR_TOKEN" \
     "https://app.wacm.in/api/v1/contacts?page=2&limit=20"
Paginated Response
{
  "data": [...],
  "links": {
    "first": "...",
    "last": "...",
    "prev": "...",
    "next": "..."
  },
  "meta": {
    "current_page": 2,
    "last_page": 5,
    "per_page": 20,
    "total": 100
  },
  "status": "success",
  "message": "Contacts retrieved successfully"
}

Use ?search= to filter contacts and conversations by name or phone. Contacts, templates and campaigns use the resource pagination format above. Groups, campaign messages and conversations return a paginator nested under data; message history uses before_id.

Authentication

Use your Personal Access Token from the WACM dashboard (Settings → API) to authenticate requests.

Example Request
curl -X GET "https://app.wacm.in/api/v1/contacts" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Accept: application/json"

Webhook Setup

Configure your WhatsApp webhook URL in the Meta Developer Console to receive incoming messages and status updates.

Webhook URL
https://app.wacm.in/webhook/wpbox/receive/{your_token}

For manual connections, copy the callback URL and verify token from WACM WhatsApp setup. The callback accepts GET challenges and POST events. The verification token must match the token in the callback URL. Embedded Signup manages the connection through WACM onboarding.

Webhook Payload - Incoming Message

Text Message Payload
{
  "entry": [{
    "id": "WABA_ID",
    "changes": [{
      "value": {
        "messaging_product": "whatsapp",
        "messages": [{
          "from": "919876543210",
          "id": "wamid.XXX",
          "timestamp": "1234567890",
          "type": "text",
          "text": { "body": "Hello" }
        }],
        "contacts": [{
          "profile": { "name": "John Doe" },
          "wa_id": "919876543210"
        }]
      }
    }]
  }]
}

Webhook Payload - Status Update

Status Update Payload
{
  "entry": [{
    "changes": [{
      "value": {
        "messaging_product": "whatsapp",
        "statuses": [{
          "id": "wamid.XXX",
          "status": "delivered",
          "timestamp": "1234567890",
          "recipient_id": "919876543210"
        }]
      }
    }]
  }]
}

Profile

GET
/me

Get authenticated user profile and company context

Response
{
  "status": "success",
  "message": "Profile retrieved successfully",
  "data": {
    "id": 1,
    "name": "John Doe",
    "email": "john@example.com",
    "company_name": "Acme Corp"
  }
}

Contacts

GET
/contacts

List all contacts with pagination (page, limit, search, group_id, tag_id, filter_condition)

POST
/contacts

Create or update a contact with groups, tags, and custom fields

POST
/contacts/bulk-sync

Create or match contacts in bulk and optionally assign them to a group or tag

GET
/contacts/{id}

Get contact details with groups, tags, and fields

PUT
/contacts/{id}

Update contact information

DELETE
/contacts/{id}

Delete contact

GET
/contacts/{id}/groups-and-fields

Get contact groups and custom fields

GET
/contacts/{id}/notes

Get contact notes

POST
/contacts/check-phone

Check single-phone reachability (live checks may send a probe; 202 means pending)

POST
/contacts/check-phones

Bulk phone reachability check (safe mode by default; optional live probe with limits)

Single-phone checks accept phone and optional refresh. A live check may send a probe message. Results include nullable is_valid and exists_on_whatsapp, check_status (confirmed, unreachable or pending), source, checked_at and error fields. HTTP 202 with null reachability means pending webhook confirmation. Group preflight uses local data and sends no messages.

Create Contact

Request
curl -X POST "https://app.wacm.in/api/v1/contacts" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "John Doe",
    "phone": "+919876543210",
    "email": "john@example.com",
    "city": "Mumbai",
    "company_name": "Acme Corp"
  }'

Request Body

ParameterTypeRequiredDescription
phonestringRequiredWhatsApp phone number with country code
namestringOptionalContact full name
emailstringOptionalContact email address
citystringOptionalCity name
country_idintegerOptionalCountry ID reference
company_namestringOptionalCompany name
subscribedbooleanOptionalSubscription / opt-in status (default: true)
enabled_ai_botbooleanOptionalEnable or disable AI chatbot for this contact
groupsarrayOptionalArray of group IDs to assign
tagsarrayOptionalArray of tag IDs to assign
fieldsobjectOptionalKey-value map of custom field values

Response

200 OK
{
  "status": "success",
  "message": "Contact created/updated successfully",
  "data": {
    "id": 123,
    "name": "John Doe",
    "phone": "+919876543210",
    "email": "john@example.com",
    "city": "Mumbai",
    "country": "India",
    "company": "Acme Corp",
    "subscribed": true,
    "is_on_whatsapp": true,
    "enabled_ai_bot": true,
    "groups": [
      { "id": 1, "name": "VIP Customers" }
    ],
    "tags": [
      { "id": 1, "name": "Lead", "color": "#10B981" }
    ],
    "custom": {},
    "created_at": "2025-01-15T10:30:00.000000Z",
    "updated_at": "2025-01-15T10:30:00.000000Z"
  }
}

Bulk Sync and Group Assignment

Submit one or more contacts and optionally provide a company-owned group_id or tag_id. Existing contacts are matched by normalized phone number, new contacts are created within plan limits, and assignments are additive and idempotent.

Request
curl -X POST "https://app.wacm.in/api/v1/contacts/bulk-sync" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "contacts": [
      {"phone": "9876543210", "name": "Jane Doe"},
      {"phone": "+919876543211", "name": "John Doe"}
    ],
    "country_code": "91",
    "group_id": 123
  }'

Bulk Sync Request Body

ParameterTypeRequiredDescription
contactsarrayRequiredNon-empty contact list; every item requires a phone containing at least one digit
contacts[].phonestringRequiredPhone number; normalized before matching
contacts[].namestringOptionalContact name
country_codestringOptionalCountry calling code applied to local numbers
group_idintegerOptionalGroup ID owned by the authenticated company
tag_idintegerOptionalTag ID owned by the authenticated company
200 OK
{
  "status": "success",
  "message": "Contacts synced successfully",
  "data": {
    "synced_count": 2,
    "updated_count": 0,
    "created_count": 2,
    "skipped_limit_count": 0
  }
}

Messages

POST
/messages/text

Send a text, media, or quick-reply button message

GET
/messages/text

Send a text message (GET)

POST
/messages/template

Send an approved template message with component parameters

GET
/messages/template

Send template message (GET)

POST
/messages/list

Send an interactive list message

GET
/messages/list

Send list message (GET)

Send Text / Media Message

Request
curl -X POST "https://app.wacm.in/api/v1/messages/text" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "phone": "+919876543210",
    "message": "Hello! This is a test message from WACM API."
  }'

Request Body

ParameterTypeRequiredDescription
phonestringRequiredRecipient WhatsApp number
messagestringOptionalMessage text content
media_urlstring (URL)OptionalDirect URL to media attachment (image, document, audio, video)
imagefileOptionalMultipart file upload
buttonsarrayOptionalArray of up to 3 quick-reply buttons with id and title
headerstringOptionalOptional header text
footerstringOptionalOptional footer text
button_namestringOptionalCall-to-action button label
button_urlstring (URL)OptionalCall-to-action button URL

Send Template Message

Send an approved Meta WhatsApp template message to a recipient. Templates support dynamic body text placeholders ({{1}}, {{2}}), buttons, and rich media headers (Image, PDF / Document, or Video).

Request (WhatsApp Cloud API Components - Body Variables)
curl -X POST "https://app.wacm.in/api/v1/messages/template" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "phone": "+919876543210",
    "template_name": "order_confirmation",
    "template_language": "en",
    "components": [
      {
        "type": "body",
        "parameters": [
          { "type": "text", "text": "John Doe" },
          { "type": "text", "text": "ORD-12345" }
        ]
      }
    ]
  }'

Template Message Request Body Parameters

ParameterTypeRequiredDescription
phonestringRequiredRecipient phone number with country code (e.g. +919876543210)
template_namestringRequiredMeta-approved WhatsApp template name
template_languagestringOptionalLanguage code (default: en). Alias: language
componentsarrayOptionalStandard WhatsApp Cloud API component array for header, body, and button parameters
imagestring (URL)OptionalShorthand parameter: Direct public HTTPS URL for template image header
documentstring (URL)OptionalShorthand parameter: Direct public HTTPS URL for template document / PDF header
videostring (URL)OptionalShorthand parameter: Direct public HTTPS URL for template video header
variablesarray/objectOptionalShorthand parameter: Body variable replacement list (e.g. ["John", "ORD-12345"])
header_variablesarrayOptionalShorthand parameter: Text header variable replacement list
scheduled_atstringOptionalSchedule message delivery for a future time (ISO timestamp or YYYY-MM-DD HH:MM:SS)
timezonestringOptionalTimezone for scheduled delivery (e.g. Asia/Kolkata, UTC)

Template Media Headers: Image, PDF & Video

When your approved WhatsApp template has a media header (IMAGE, DOCUMENT, or VIDEO), you provide the direct public URL for the media asset when dispatching the message. WACM supports both the Standard Meta WhatsApp Cloud API components format and Clean Shorthand parameters.

1. Sending an Image Header

For promotional banners, discount vouchers, product highlights, and event posters

JPG, PNGMax 5 MB

To send an image header using Cloud API components, set the component type to header, the parameter type to image, and provide the direct HTTPS link in image: { link: "..." }.

Standard Cloud API Components (Image Header)
curl -X POST "https://app.wacm.in/api/v1/messages/template" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "phone": "+919876543210",
    "template_name": "seasonal_sale_banner",
    "template_language": "en",
    "components": [
      {
        "type": "header",
        "parameters": [
          {
            "type": "image",
            "image": {
              "link": "https://cdn.example.com/promotions/diwali_special_banner.jpg"
            }
          }
        ]
      },
      {
        "type": "body",
        "parameters": [
          { "type": "text", "text": "Param" },
          { "type": "text", "text": "FESTIVE50" }
        ]
      }
    ]
  }'

⚡ Shorthand Alternative

Shorthand Parameter (Image Header)
curl -X POST "https://app.wacm.in/api/v1/messages/template" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "phone": "+919876543210",
    "template_name": "seasonal_sale_banner",
    "template_language": "en",
    "image": "https://cdn.example.com/promotions/diwali_special_banner.jpg",
    "variables": ["Param", "FESTIVE50"]
  }'

2. Sending a PDF / Document Header

For GST tax invoices, monthly statements, e-tickets, lab reports, and policy documents

PDFMax 100 MB

For document templates, specify the parameter type as document with its link. You can also specify an optional filename attribute so the recipient sees a neat, human-readable file name (e.g. Tax_Invoice_INV2026.pdf) in their WhatsApp chat interface.

Standard Cloud API Components (PDF Document Header + Custom Filename)
curl -X POST "https://app.wacm.in/api/v1/messages/template" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "phone": "+919876543210",
    "template_name": "invoice_notification",
    "template_language": "en",
    "components": [
      {
        "type": "header",
        "parameters": [
          {
            "type": "document",
            "document": {
              "link": "https://cdn.example.com/invoices/2026/INV-98231.pdf",
              "filename": "Tax_Invoice_INV98231.pdf"
            }
          }
        ]
      },
      {
        "type": "body",
        "parameters": [
          { "type": "text", "text": "Param Mehta" },
          { "type": "text", "text": "INV-98231" },
          { "type": "text", "text": "₹14,999" }
        ]
      }
    ]
  }'

⚡ Shorthand Alternative

Shorthand Parameter (PDF Document Header)
curl -X POST "https://app.wacm.in/api/v1/messages/template" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "phone": "+919876543210",
    "template_name": "invoice_notification",
    "template_language": "en",
    "document": "https://cdn.example.com/invoices/2026/INV-98231.pdf",
    "variables": ["Param Mehta", "INV-98231", "₹14,999"]
  }'

3. Sending a Video Header

For onboarding tutorials, product launch teasers, video greetings, and campaign demos

MP4, 3GPMax 16 MB

For video templates, specify the parameter type as video and supply the direct link to the .mp4 file encoded with H.264 video and AAC audio codecs.

Standard Cloud API Components (Video Header)
curl -X POST "https://app.wacm.in/api/v1/messages/template" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "phone": "+919876543210",
    "template_name": "product_onboarding_tour",
    "template_language": "en",
    "components": [
      {
        "type": "header",
        "parameters": [
          {
            "type": "video",
            "video": {
              "link": "https://cdn.example.com/videos/onboarding_quickstart.mp4"
            }
          }
        ]
      },
      {
        "type": "body",
        "parameters": [
          { "type": "text", "text": "Alex" }
        ]
      }
    ]
  }'

⚡ Shorthand Alternative

Shorthand Parameter (Video Header)
curl -X POST "https://app.wacm.in/api/v1/messages/template" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "phone": "+919876543210",
    "template_name": "product_onboarding_tour",
    "template_language": "en",
    "video": "https://cdn.example.com/videos/onboarding_quickstart.mp4",
    "variables": ["Alex"]
  }'

Code Examples in Popular Languages

Send a PDF Invoice template message programmatically using your preferred runtime.

Node.js (Fetch API)
// Send PDF Invoice Template with Node.js
const response = await fetch('https://app.wacm.in/api/v1/messages/template', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer ' + process.env.WACM_API_TOKEN,
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    phone: '+919876543210',
    template_name: 'invoice_notification',
    template_language: 'en',
    components: [
      {
        type: 'header',
        parameters: [
          {
            type: 'document',
            document: {
              link: 'https://cdn.example.com/invoices/2026/INV-98231.pdf',
              filename: 'Tax_Invoice_INV98231.pdf'
            }
          }
        ]
      },
      {
        type: 'body',
        parameters: [
          { type: 'text', text: 'Param Mehta' },
          { type: 'text', text: 'INV-98231' },
          { type: 'text', text: '₹14,999' }
        ]
      }
    ]
  })
});

const data = await response.json();
console.log('Message WAMID:', data.data?.message_wamid);
Python (requests)
# Send Media Template with Python
import os
import requests

url = "https://app.wacm.in/api/v1/messages/template"
headers = {
    "Authorization": f"Bearer {os.getenv('WACM_API_TOKEN')}",
    "Content-Type": "application/json"
}

payload = {
    "phone": "+919876543210",
    "template_name": "seasonal_sale_banner",
    "template_language": "en",
    "components": [
        {
            "type": "header",
            "parameters": [
                {
                    "type": "image",
                    "image": {
                        "link": "https://cdn.example.com/promotions/diwali_special_banner.jpg"
                    }
                }
            ]
        },
        {
            "type": "body",
            "parameters": [
                {"type": "text", "text": "Param"},
                {"type": "text", "text": "FESTIVE50"}
            ]
        }
    ]
}

response = requests.post(url, json=payload, headers=headers)
print(response.json())

Important Media Header Rules & Guidelines

Direct HTTPS URLs Required

The media link must be a direct public URL accessible over https:// without requiring cookies, session tokens, or authentication. Do NOT use Google Drive preview links (e.g. drive.google.com/file/d/.../view) or Dropbox landing pages; provide direct asset URLs from AWS S3, Cloudflare R2, Google Cloud Storage, or your public web server.

Template Header Type Must Match Meta Approval

When you submit a template for approval to Meta, you select the header format (IMAGE, DOCUMENT, or VIDEO). When sending via API, the media component type in your payload must strictly match the approved format, or Meta will return an error (#132000 Template param count mismatch).

Document Filename Recommendation

When sending invoices or sensitive documents, always populate the filename property inside document. This provides a clear, professional preview inside the recipient's WhatsApp conversation list and helps customers easily locate downloaded files in their device storage.

Supported Media Sources: Public URLs, Firebase Storage, Base64 & Meta Media ID

Developers frequently ask how WhatsApp Cloud API handles different storage and backend architectures. Here is the definitive breakdown of how Official Meta WhatsApp Cloud API works versus how WACM makes media sending effortless.

Official Meta Cloud API Specification
  • • No native Base64: Meta's official Cloud API does not accept raw Base64 data strings directly in template parameters or media payloads. Attempting to pass Base64 to Meta triggers (#100) Invalid parameter: link is not a valid URL.
  • • Requires Public HTTPS URL (link): Meta servers must download the file via standard HTTP/HTTPS GET without custom headers or cookies.
  • • Or Meta Media ID (id): Assets pre-uploaded via Meta's POST /{phone-number-id}/media Graph API endpoint.
WACM Smart Handling & Convenience
  • • Firebase Storage URLs Supported: Standard Firebase download URLs (with public download token) work 100% natively as link.
  • • Built-in Base64 Auto-Decoding: WACM automatically intercepts Data URIs (data:image/...;base64,... or data:application/pdf;base64,...), decodes the binary, persists it to your company storage, and supplies Meta with the required HTTPS link.
  • • Meta Media ID Pass-Through: If you already upload media via Meta Graph API, provide the numeric ID in { id: "123456789" }.
Method 1: Firebase Storage Public Download URLs
Standard Link

When using Firebase Storage, generate a download URL via the Firebase Client/Admin SDK (getDownloadURL()). The resulting URL contains a public query token (?alt=media&token=...) allowing Meta's crawler to fetch the media without needing Firebase Auth headers.

Firebase Storage URL in Template Header
curl -X POST "https://app.wacm.in/api/v1/messages/template" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "phone": "+919876543210",
    "template_name": "order_receipt_pdf",
    "template_language": "en",
    "components": [
      {
        "type": "header",
        "parameters": [
          {
            "type": "document",
            "document": {
              "link": "https://firebasestorage.googleapis.com/v0/b/my-app.appspot.com/o/invoices%2FINV-8941.pdf?alt=media&token=4a1c5d9e-8b2f-4e6a-912c-7b8a3e4f5d6c",
              "filename": "Invoice_INV8941.pdf"
            }
          }
        ]
      },
      {
        "type": "body",
        "parameters": [
          { "type": "text", "text": "Param" },
          { "type": "text", "text": "INV-8941" }
        ]
      }
    ]
  }'
Method 2: Direct Base64 Data URI (Auto-Hosted by WACM)
WACM Exclusive

Ideal when generating invoices (PDFs) or dynamic vouchers (PNG/JPG) on the fly in backend memory (e.g. Puppeteer, jsPDF, PDFKit, DOMPDF). Pass standard Data URI format (data:<mime>;base64,<data>) directly in link or shorthand. WACM automatically saves the asset and supplies Meta with the required public URL.

Node.js: Sending Dynamic Base64 PDF Invoice
// Node.js: Generating and sending Base64 PDF directly
import fs from 'fs';

// In-memory buffer or generated invoice
const pdfBuffer = fs.readFileSync('./generated-invoice.pdf');
const base64Pdf = `data:application/pdf;base64,${pdfBuffer.toString('base64')}`;

const response = await fetch('https://app.wacm.in/api/v1/messages/template', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer ' + process.env.WACM_API_TOKEN,
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    phone: '+919876543210',
    template_name: 'monthly_statement_pdf',
    template_language: 'en',
    components: [
      {
        type: 'header',
        parameters: [
          {
            type: 'document',
            document: {
              link: base64Pdf,
              filename: 'Statement_March_2026.pdf'
            }
          }
        ]
      },
      {
        type: 'body',
        parameters: [
          { type: 'text', text: 'Param' },
          { type: 'text', text: 'March 2026' }
        ]
      }
    ]
  })
});

const data = await response.json();
console.log('Result:', data);

⚡ Python Base64 Example

Python: Sending Base64 PDF / Image
import base64
import requests

with open("invoice.pdf", "rb") as f:
    b64_data = base64.b64encode(f.read()).decode("utf-8")

data_uri = f"data:application/pdf;base64,{b64_data}"

response = requests.post(
    "https://app.wacm.in/api/v1/messages/template",
    headers={"Authorization": "Bearer YOUR_API_TOKEN"},
    json={
        "phone": "+919876543210",
        "template_name": "invoice_receipt",
        "template_language": "en",
        "document": data_uri,
        "filename": "Invoice_9021.pdf",
        "variables": ["Param", "₹4,999"]
    }
)
print(response.json())
Method 3: Meta Media ID (id)
Meta Upload

If your workflow uploads media assets directly to Meta's servers using the WhatsApp Resumable Upload API or POST /{phone-number-id}/media, you can supply the resulting numeric id instead of a URL.

Using Meta Media ID in Header Parameter
curl -X POST "https://app.wacm.in/api/v1/messages/template" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "phone": "+919876543210",
    "template_name": "product_brochure",
    "template_language": "en",
    "components": [
      {
        "type": "header",
        "parameters": [
          {
            "type": "image",
            "image": {
              "id": "184920491823910"
            }
          }
        ]
      }
    ]
  }'
Media Source Comparison
Source TypeMeta Native?WACM Support?Best ForParameter Format
Public HTTPS URL (S3, CDN)YesYesPre-hosted static assets, catalogs{ "link": "https://..." }
Firebase Storage URLYes (with token)YesMobile & Firebase web apps{ "link": "https://firebasestorage..." }
Base64 Data URINo (rejected by Meta)Yes (Auto-hosted)In-memory generated invoices, receipts{ "link": "data:image/...;base64,..." }
Meta Media IDYesYesPre-uploaded Meta media workflows{ "id": "184920491823910" }

Sending Templates with Dynamic URLs & Buttons

WhatsApp Business templates frequently require customized URLs for each recipient — including order tracking links, invoice download pages, payment gateways, and authentication links. WhatsApp supports dynamic URLs in two primary ways: Call-to-Action (CTA) URL Buttons and Body Variables.

1. Dynamic URL Buttons (Call-to-Action Buttons)
CTA Button

When creating a template in Meta Business Manager with a Visit Website button set to Dynamic URL (e.g. Base URL: https://track.wacm.in/shipment/{{1}} or https://mybrand.com/invoice/{{1}}), provide the button parameter using type: "button", sub_type: "url", and the 0-based index of the button:

Template with Dynamic URL Button (cURL)
curl -X POST "https://app.wacm.in/api/v1/messages/template" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "phone": "+919876543210",
    "template_name": "order_tracking_update",
    "template_language": "en",
    "components": [
      {
        "type": "body",
        "parameters": [
          { "type": "text", "text": "Param Mehta" },
          { "type": "text", "text": "ORD-98412" }
        ]
      },
      {
        "type": "button",
        "sub_type": "url",
        "index": "0",
        "parameters": [
          {
            "type": "text",
            "text": "ORD-98412"
          }
        ]
      }
    ]
  }'
WACM Exclusive: Smart URL Prefix Auto-Stripping

In raw Meta Cloud API, if your template URL is https://track.wacm.in/shipment/{{1}}, Meta strictly expects only the suffix "ORD-98412" and throws an error if you pass the full URL. WACM is smarter: You can pass either the dynamic suffix ("ORD-98412") or the full URL ("https://track.wacm.in/shipment/ORD-98412"). WACM automatically detects and strips the static domain prefix before dispatching to Meta, preventing validation failures.

2. Dynamic Full URLs inside Body Placeholders
Body Variable

If your approved template contains a placeholder in the body text (e.g. "Click here to track your package: {{2}}" or "Reset your password: {{2}}"), you can pass a full dynamic URL directly in variables or components:

Dynamic URL in Body Variables (Shorthand or Components)
curl -X POST "https://app.wacm.in/api/v1/messages/template" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "phone": "+919876543210",
    "template_name": "password_reset_link",
    "template_language": "en",
    "variables": [
      "Param Mehta",
      "https://example.com/reset-password?token=EXAMPLE_TOKEN"
    ]
  }'
Programmatic SDK Examples (Dynamic URL Button)
Node.js: Template with Dynamic URL Button
import fetch from 'node-fetch';

const orderId = 'ORD-98412';

const res = await fetch('https://app.wacm.in/api/v1/messages/template', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer ' + process.env.WACM_API_TOKEN,
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    phone: '+919876543210',
    template_name: 'order_shipped_tracker',
    template_language: 'en',
    components: [
      {
        type: 'body',
        parameters: [
          { type: 'text', text: 'Param Mehta' },
          { type: 'text', text: orderId }
        ]
      },
      {
        type: 'button',
        sub_type: 'url',
        index: '0',
        parameters: [
          // Suffix or full URL both work seamlessly in WACM
          { type: 'text', text: orderId }
        ]
      }
    ]
  })
});
const data = await res.json();
console.log('Dispatch result:', data);
Python: Template with Dynamic URL Button
import requests

order_id = "ORD-98412"

response = requests.post(
    "https://app.wacm.in/api/v1/messages/template",
    headers={
        "Authorization": "Bearer YOUR_API_TOKEN",
        "Content-Type": "application/json"
    },
    json={
        "phone": "+919876543210",
        "template_name": "order_shipped_tracker",
        "template_language": "en",
        "components": [
            {
                "type": "body",
                "parameters": [
                    {"type": "text", "text": "Param Mehta"},
                    {"type": "text", "text": order_id}
                ]
            },
            {
                "type": "button",
                "sub_type": "url",
                "index": "0",
                "parameters": [
                    {"type": "text", "text": order_id}
                ]
            }
        ]
    }
)
print(response.json())

Send Interactive List Message

Request
curl -X POST "https://app.wacm.in/api/v1/messages/list" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "phone": "+919876543210",
    "message": "Please select from the options below:",
    "header": "Main Menu",
    "footer": "Powered by WACM",
    "action": {
      "button": "View Options",
      "sections": [
        {
          "title": "Menu Options",
          "rows": [
            { "id": "opt1", "title": "Check Order Status", "description": "Track your recent order" },
            { "id": "opt2", "title": "Talk to Support", "description": "Connect with an agent" }
          ]
        }
      ]
    }
  }'

List Message Request Body

ParameterTypeRequiredDescription
phonestringRequiredRecipient WhatsApp number
messagestringRequiredMain body message
actionobjectRequiredInteractive action configuration containing button label and sections list
headerstringOptionalOptional text header
footerstringOptionalOptional text footer

Media Upload & Meta Cloud API

Upload documents (PDFs), images, videos, audio clips, and stickers directly to the official Meta WhatsApp Cloud API (POST /{phone-number-id}/media). WACM streams the file to Meta's infrastructure, saves a copy in your configured company storage, and returns the official numeric Meta Media ID (id) alongside a storage url. Use the returned id in template header components. Meta controls media availability and download URL expiry; re-upload media when needed.

POST
/media

Upload media file directly to Meta Cloud API and company storage (returns Meta media ID and URL)

GET
/media/{id}

Retrieve Meta media metadata and temporary download URL from Meta Graph API

DELETE
/media/{id}

Delete media asset from Meta WhatsApp Cloud API

Media Upload Parameters (multipart/form-data)

ParameterTypeRequiredDescription
filefileRequiredBinary media file. Max sizes: Document (PDF) 100MB, Video 16MB, Audio 16MB, Image (JPG/PNG) 5MB, Sticker 100KB

Upload Media File (cURL)

POST /api/v1/media
curl -X POST "https://app.wacm.in/api/v1/media" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -F "file=@/path/to/invoice_INV-9821.pdf" \
  -F "type=document"

Upload Response

201 Created - Meta Media ID & Hosted URL
{
  "status": "success",
  "message": "Media uploaded to Meta successfully",
  "data": {
    "id": "184920491823910",
    "url": "https://app.wacm.in/storage/uploads/companies/1/media/2026/03/invoice_INV-9821.pdf",
    "mime_type": "application/pdf",
    "file_name": "invoice_INV-9821.pdf",
    "file_size": 245100
  }
}
How to Use the Returned Meta Media ID

Instead of re-uploading or exposing private S3/GCS buckets, pass the returned numeric id directly into your template header or message payload. WhatsApp servers already hold the binary, avoiding another upload.

Send Template Using the Returned Meta Media ID
curl -X POST "https://app.wacm.in/api/v1/messages/template" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "phone": "+919876543210",
    "template_name": "invoice_delivery",
    "template_language": "en",
    "components": [
      {
        "type": "header",
        "parameters": [
          {
            "type": "document",
            "document": {
              "id": "184920491823910",
              "filename": "Invoice_March2026.pdf"
            }
          }
        ]
      },
      {
        "type": "body",
        "parameters": [
          { "type": "text", "text": "Param Mehta" },
          { "type": "text", "text": "₹14,999" }
        ]
      }
    ]
  }'

Retrieve Media Details (GET)

Fetch Meta metadata and temporary download URL using the Media ID:

GET /api/v1/media/{id}
curl -X GET "https://app.wacm.in/api/v1/media/184920491823910" \
  -H "Authorization: Bearer YOUR_API_TOKEN"

Delete Media (DELETE)

Delete a media file from Meta WhatsApp Cloud servers:

DELETE /api/v1/media/{id}
curl -X DELETE "https://app.wacm.in/api/v1/media/184920491823910" \
  -H "Authorization: Bearer YOUR_API_TOKEN"

Programmatic SDK Examples (Upload & Send Flow)

Node.js: Upload File & Send Template
import fs from 'fs';
import FormData from 'form-data';
import fetch from 'node-fetch';

const TOKEN = process.env.WACM_API_TOKEN;

// 1. Upload to Meta via WACM
const form = new FormData();
form.append('file', fs.createReadStream('./invoice.pdf'));
form.append('type', 'document');

const uploadRes = await fetch('https://app.wacm.in/api/v1/media', {
  method: 'POST',
  headers: { 'Authorization': `Bearer ${TOKEN}`, ...form.getHeaders() },
  body: form
});
const { data: media } = await uploadRes.json();
console.log('Meta Media ID:', media.id);

// 2. Dispatch Template with returned Meta Media ID
const msgRes = await fetch('https://app.wacm.in/api/v1/messages/template', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${TOKEN}`,
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    phone: '+919876543210',
    template_name: 'invoice_ready',
    template_language: 'en',
    components: [
      {
        type: 'header',
        parameters: [{ type: 'document', document: { id: media.id, filename: 'Invoice.pdf' } }]
      },
      {
        type: 'body',
        parameters: [{ type: 'text', text: 'Param' }]
      }
    ]
  })
});
console.log('Template dispatch:', await msgRes.json());
Python: Upload File & Send Template
import requests

TOKEN = "YOUR_API_TOKEN"
HEADERS = {"Authorization": f"Bearer {TOKEN}"}

# 1. Upload file to Meta Cloud API via WACM
with open("invoice.pdf", "rb") as f:
    files = {"file": ("invoice.pdf", f, "application/pdf")}
    data = {"type": "document"}
    upload_res = requests.post("https://app.wacm.in/api/v1/media", headers=HEADERS, files=files, data=data)

media = upload_res.json()["data"]
print("Meta Media ID:", media["id"])

# 2. Send template using the Meta Media ID
template_payload = {
    "phone": "+919876543210",
    "template_name": "invoice_ready",
    "template_language": "en",
    "components": [
        {
            "type": "header",
            "parameters": [
                {
                    "type": "document",
                    "document": {
                        "id": media["id"],
                        "filename": "Invoice.pdf"
                    }
                }
            ]
        },
        {
            "type": "body",
            "parameters": [{"type": "text", "text": "Param"}]
        }
    ]
}

send_res = requests.post("https://app.wacm.in/api/v1/messages/template", headers=HEADERS, json=template_payload)
print("Template dispatch:", send_res.json())

Templates

GET
/templates

List templates in all statuses (supports ?name=, ?status=, ?category=, ?language= filters; check status before sending)

GET
/templates/capabilities

Get workspace template creation capabilities, AI availability, and opt-out settings

GET
/templates/starters

List quick-start WhatsApp template presets with opt-out buttons

GET
/templates/library

Search pre-built industry WhatsApp templates by category, industry, and language

POST
/templates

Create and submit a new WhatsApp template to Meta

GET
/templates/{id}

Get template details

PUT
/templates/{id}

Edit and resubmit a rejected or paused WhatsApp template to Meta

POST
/templates/validate

Validate template structure and Meta compliance rules without submitting

POST
/templates/ai/generate

Generate a compliant WhatsApp template draft from a natural-language prompt

POST
/templates/ai/review

Audit a template draft for Meta approval risk and policy compliance

POST
/templates/sync

Sync all templates from WhatsApp Business Account

POST
/templates/{id}/sync

Sync a single template status from Meta

DELETE
/templates/{id}

Delete template from WhatsApp and local database

Response

200 OK
{
  "data": [
    {
      "id": 1,
      "name": "order_confirmation",
      "language": "en",
      "status": "APPROVED",
      "category": "UTILITY",
      "components": [
        {
          "type": "BODY",
          "text": "Hi {{1}}, your order {{2}} has been confirmed!"
        }
      ],
      "created_at": "2025-01-15T10:30:00.000000Z",
      "updated_at": "2025-01-15T10:30:00.000000Z"
    }
  ],
  "status": "success",
  "message": "Templates retrieved successfully"
}

Groups

GET
/groups

List contact groups with contacts_count

POST
/groups

Create a contact group

GET
/groups/{id}

Get contact group details and up to 50 sample contacts

PUT
/groups/{id}

Rename a contact group

DELETE
/groups/{id}

Delete a contact group and detach its contacts

POST
/groups/{id}/contacts

Bulk attach, detach, or sync contacts in a group (contact_ids, action: attach|detach|sync)

GET
/groups/{id}/preflight

Local group readiness summary; no WhatsApp messages are sent

POST
/groups/{id}/check-phones

Deprecated alias for local preflight; no background WhatsApp probing

Response
{
  "status": "success",
  "message": "Groups retrieved successfully",
  "data": {
    "current_page": 1,
    "data": [
      {
        "id": 1,
        "name": "VIP Customers",
        "contacts_count": 150,
        "created_at": "2025-01-15T10:30:00.000000Z",
        "updated_at": "2025-01-15T10:30:00.000000Z"
      }
    ],
    "total": 1
  }
}

Tags & Custom Fields

GET
/tags

List all contact tags

POST
/tags

Create a new tag (name, color)

GET
/tags/{id}

Get tag details and up to 50 sample tagged contacts

PUT
/tags/{id}

Update an existing tag name or color

DELETE
/tags/{id}

Delete a tag

POST
/tags/{id}/contacts

Bulk attach, detach, or sync contacts on a tag (contact_ids, action: attach|detach|sync)

GET
/fields

List company custom contact field definitions

GET
/fields/{id}

Get custom contact field definition by ID

POST
/fields

Create a custom contact field (name, type: text|number|date|email|Select, options)

PUT
/fields/{id}

Update a custom contact field definition

DELETE
/fields/{id}

Delete a custom contact field definition and its values

Campaigns

GET
/campaigns

List all campaigns with pagination (page, limit, search, type)

POST
/campaigns

Create and dispatch a new campaign

POST
/campaigns/audience-preview

Preview eligible opted-in contacts count before launching

GET
/campaigns/{id}

Get campaign statistics and details

GET
/campaigns/{id}/messages

List campaign message delivery transactions with status filter

PUT
/campaigns/{id}

Update campaign status (pause/resume with is_active)

POST
/campaigns/{id}/retry

Reactivate campaign and requeue retryable failures; returns retried and skipped counts

DELETE
/campaigns/{id}

Delete a campaign

POST
/campaigns/send

Queue a message from an existing campaign (phone and campaign_id required)

Audience Preview

Request
curl -X POST "https://app.wacm.in/api/v1/campaigns/audience-preview" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "audience_type": "group",
    "group_id": 1,
    "template_id": 12,
    "prevent_template_duplicates": true
  }'
200 OK
{
  "status": "success",
  "message": "Campaign audience preview retrieved successfully",
  "data": {
    "audience_type": "group",
    "eligible_contacts": 142
  }
}

Audience preview does not send messages. Creating a campaign queues delivery and returns HTTP 201; it is not a draft. Include an Idempotency-Key header (max 255 characters) when creating campaigns: an identical retry returns the existing campaign with HTTP 200, while different input with the same key returns 409.

Create Campaign

Request
curl -X POST "https://app.wacm.in/api/v1/campaigns" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Summer Sale 2025",
    "template_id": 1,
    "audience_type": "all",
    "send_now": true,
    "paramvalues": {
      "1": "Summer Sale",
      "2": "50% OFF"
    }
  }'

Request Body

ParameterTypeRequiredDescription
namestringRequiredCampaign name
template_idintegerRequiredApproved WhatsApp template ID
audience_typestringOptionalExplicitly set all, group, or contact. If omitted, inferred from group_id/contact_id, otherwise all.
group_idintegerOptionalRequired if audience_type is "group". Prohibited otherwise.
contact_idintegerOptionalRequired if audience_type is "contact". Prohibited otherwise.
send_nowbooleanOptionalSend immediately (true, default) or schedule later (false)
send_timestringOptionalISO date string to send if send_now is false
prevent_template_duplicatesbooleanOptionalExclude contacts that already received this template
paramvaluesobject | array | JSON stringOptionalTemplate variable mapping values
parammatchobject | array | JSON stringOptionalTemplate variable field mapping
pdffileOptionalMultipart form data for PDF attachments
imageuploadfileOptionalMultipart form data for Image/Video attachments

Send from an Existing Campaign

POST /api/v1/campaigns/send request
{
  "phone": "+919876543210",
  "campaign_id": 123
}

Optional data supplies extra template values. This endpoint uses the existing campaign's template; use /messages/template to send by template name. Paused campaigns return 409; ineligible contacts return 422. A successful response contains message_id, nullable message_wamid, numeric status, and billing_status.

Conversations

GET
/conversations

List all conversations with pagination (page, limit, search, lastmessagetime)

GET
/conversations/{id}/messages

Get conversation messages with pagination (limit, before_id, search, lastmessagetime)

Conversation IDs are contact IDs. Workspace and agent permissions apply. Lists default to 50 results; message history uses before_id for older messages.

GET
/conversation-agents

List eligible workspace agents

GET
/conversations/{id}

Get operational details; id is the contact ID

PUT
/conversations/{id}/customer

Required name, email, city; email/city nullable; phone changes prohibited

PUT
/conversations/{id}/ai-bot

Required boolean enabled_ai_bot

PUT
/conversations/{id}/assignment

Required user_id; null unassigns

PUT
/conversations/{id}/status

Required status: open or resolved

PUT
/conversations/{id}/snooze

Required hours: 1–168; null clears snooze

GET
/conversations/{id}/notes

List up to 50 internal notes

POST
/conversations/{id}/notes

Required nonblank note, max 2000 characters; 201; no outbound message

PUT
/conversations/{id}/tags

Required tag_ids array; up to 50 distinct workspace IDs; empty array clears tags

POST
/conversations/{id}/read

Optional last_read_message_id; marks read for current user

Get Conversation Messages

Response
{
  "data": [
    {
      "id": 1,
      "fb_message_id": "wamid.HBgM...",
      "contact_id": 123,
      "value": "Hello! How can I help you?",
      "status": 4,
      "is_message_by_contact": 0,
      "message_type": 1,
      "created_at": "2025-01-15T10:30:00.000000Z",
      "updated_at": "2025-01-15T10:30:00.000000Z"
    }
  ],
  "status": "success",
  "message": "Messages retrieved successfully"
}

Message Types Reference

TypeCodeDescription
TEXT1Plain text message
MEDIA2Image, video, document, or audio
LOCATION3Location share (Google Maps)
NFM_REPLY5Interactive flow reply

Media Specifications & Constraints

Summary of supported file formats, MIME types, and file size limits for WhatsApp template media headers and direct media messages.

Media TypeSupported MIME TypesMax SizeRecommended Specs & Notes
Imageimage/jpeg, image/png5 MB800x800 or 1200x628 (1.91:1) recommended. RGB/RGBA. Animated GIFs or WebP are not supported in template headers.
Document / PDFapplication/pdf100 MBStandard PDF format. Pass filename attribute to control file name displayed in WhatsApp UI.
Videovideo/mp4, video/3gpp16 MBH.264 video codec and AAC audio codec. 720p or 1080p resolution recommended. Must contain an audio track.
Audioaudio/aac, audio/mp4, audio/mpeg16 MBMono or stereo audio. Used for voice notes and voice recordings.

Message Status Codes

0Scheduled - Message queued for sending
1Sending - Message being sent to WhatsApp
2Sent - WhatsApp accepted the message
3Delivered - Message delivered to device
4Read - Message read by recipient
5Failed - Message failed to send

Error Responses

400Bad Request - Invalid parameters or payload
401Unauthorized - Invalid or missing API token
403Forbidden - Insufficient permissions or plan limits
404Not Found - Resource does not exist
429Too Many Requests - Rate limit exceeded
500Internal Server Error - Something went wrong

Error Response Format

Error Response
{
  "message": "The phone number is required.",
  "errors": {
    "phone": ["The phone field is required."]
  }
}

eCommerce Store API

Manage products, categories, and orders.

View Docs