Skip to content

WhatsApp API

Send WhatsApp broadcasts, manage templates, contacts, and conversations with Zernio API

Quick Reference

PropertyValue
Message typesText, Template, Image, Video, Document, Audio
Template requiredYes (outside 24h conversation window)
Image formatsJPEG, PNG
Image max size5 MB
Video formatsMP4, 3GPP
Video max size16 MB
Document formatsPDF, DOC, DOCX, XLS, XLSX, PPT, PPTX, TXT
Document max size100 MB
Audio formatsMP3, OGG, AMR, AAC
Audio max size16 MB
SchedulingNo (use broadcasts with scheduling)
Inbox (DMs)Yes
Inbox (Comments)No
Group ChatsYes, (Usage plan) (non-coexistence numbers only, see Group Chats)
FlowsYes (interactive forms, surveys, booking)
AnalyticsNo

Before You Start

WhatsApp requires a WhatsApp Business Account (WABA). This is different from a regular WhatsApp account.

Requirements:

  • A Meta Business account (business.facebook.com)
  • WhatsApp Business Account (created during the connection flow)
  • At least one phone number registered with the WABA
  • Approved message templates for initiating conversations (Meta reviews these)
  • 24-hour rule: You can only send free-form messages within 24 hours of the customer's last message. Outside that window, you must use an approved template.

Connection (API)

WhatsApp requires a WhatsApp Business Account (WABA) and uses Meta's infrastructure for authentication. There are two ways to connect via the API:

The standard OAuth-style redirect flow. Works from any domain, no JavaScript SDK required. Same pattern as connecting Instagram, TikTok, or any other platform.

  1. Your app calls the connect endpoint to get an auth URL
  2. You redirect the user to Meta's WhatsApp signup page
  3. User selects or creates a WhatsApp Business Account and picks a phone number
  4. User is redirected back to your app with the connection details

Step 1: Get the auth URL

typescript
const { data } = await zernio.get('/v1/connect/whatsapp', {
  params: {
    profileId: 'YOUR_PROFILE_ID',
    redirect_url: 'https://yourdomain.com/callback'
  }
});

// Redirect your user to the auth URL
// data.authUrl -> Meta's WhatsApp signup page
python
response = client.get('/v1/connect/whatsapp', params={
    'profileId': 'YOUR_PROFILE_ID',
    'redirect_url': 'https://yourdomain.com/callback'
})
auth_url = response.json()['authUrl']
# Redirect user to auth_url
bash
curl "https://zernio.com/api/v1/connect/whatsapp?profileId=YOUR_PROFILE_ID&redirect_url=https://yourdomain.com/callback" \
  -H "Authorization: Bearer YOUR_API_KEY"
# Returns: { "authUrl": "https://facebook.com/...", "state": "..." }

Step 2: Redirect your user to the authUrl. They complete WhatsApp Business signup on Meta's page.

Step 3: After completing signup, the user is redirected back to your redirect_url with connection details appended as query parameters:

https://yourdomain.com/callback?connected=whatsapp&profileId=xxx&accountId=xxx&username=+1234567890

The account is now connected and ready to send and receive messages.

This is the same connect flow used by all platforms in Zernio. No Facebook JavaScript SDK is needed. Works from any domain.

Option 2: Headless Credentials (No Browser)

If you already have your Meta credentials, you can connect entirely via API with no browser popup. This is ideal for server-to-server integrations, CLI tools, or automated provisioning.

Prerequisites: Create a System User in Meta Business Suite, generate a permanent access token with whatsapp_business_management and whatsapp_business_messaging permissions, and get your WABA ID and Phone Number ID from the WhatsApp Manager.

typescript
const { data } = await zernio.post('/v1/connect/whatsapp/credentials', {
  profileId: 'YOUR_PROFILE_ID',
  accessToken: 'YOUR_META_SYSTEM_USER_TOKEN',
  wabaId: 'YOUR_WABA_ID',
  phoneNumberId: 'YOUR_PHONE_NUMBER_ID'
});
console.log('Connected:', data.account.accountId);
python
response = client.post('/v1/connect/whatsapp/credentials', json={
    'profileId': 'YOUR_PROFILE_ID',
    'accessToken': 'YOUR_META_SYSTEM_USER_TOKEN',
    'wabaId': 'YOUR_WABA_ID',
    'phoneNumberId': 'YOUR_PHONE_NUMBER_ID'
})
print(f"Connected: {response.json()['account']['accountId']}")
bash
curl -X POST https://zernio.com/api/v1/connect/whatsapp/credentials \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "profileId": "YOUR_PROFILE_ID",
    "accessToken": "YOUR_META_SYSTEM_USER_TOKEN",
    "wabaId": "YOUR_WABA_ID",
    "phoneNumberId": "YOUR_PHONE_NUMBER_ID"
  }'

The endpoint validates your credentials against Meta's API, creates the connection, subscribes to webhooks, and registers the phone number on the WhatsApp network. If the phoneNumberId is not found in your WABA, the response includes available phone numbers so you can correct it.

WhatsApp Business App Coexistence

Businesses that already use the WhatsApp Business app can connect their existing number to Cloud API without giving up the app. During the Embedded Signup flow (Option 1), they will see an option to connect their existing WhatsApp Business app account and phone number.

When a business chooses this option:

  • Their phone number works with both the WhatsApp Business app and Cloud API simultaneously
  • Messages sent and received are mirrored between both apps (up to 6 months of history is synced)
  • Contacts from the WhatsApp Business app are imported automatically
  • The business can still send individual messages from the WA Business app

Limitations:

FeatureStatus
ThroughputFixed at 20 messages per second
Group chats (app-side)Not synced. WA Business app groups are not visible via API
Groups APINot supported. To create or manage groups via API (see Group Chats) you need a non-coexistence number (Cloud API only)
Voice/video callsNot supported via API
Disappearing messagesTurned off for all 1:1 chats
View once messagesDisabled for all 1:1 chats
Broadcast listsDisabled in the WA Business app

Disconnection: The business disconnects from the WhatsApp Business app (Settings > Account > Business Platform > Disconnect). This cannot be done via API. When they disconnect, Zernio automatically deactivates the account.

Coexistence is transparent to your integration. You use the same API endpoints for sending messages, managing contacts, and everything else. The only difference is the lower throughput limit (20 mps vs. the standard Cloud API throughput).

Getting Started (App Setup)

Follow these steps to connect your WhatsApp Business Account through the Zernio dashboard.

Step 1: Go to Connections

Navigate to Connections in the sidebar and find the WhatsApp card. Click + Connect to start the setup.

!Go to Connections and click Connect on WhatsApp

Step 2: Choose Your Number Type

You'll see two options:

  1. Get a US number (recommended) - $2/mo per number. Zernio handles everything including verification.
  2. Use my own number - Bring your existing phone number. Requires verification during setup.

!Choose between getting a US number or using your own

Step 3: Confirm Your Number

You'll be assigned a US phone number. Review the pricing ($2/mo per number) and click Confirm to proceed with the purchase.

!Confirm your phone number purchase

Step 4: Auto-Verification

Zernio automatically verifies your number with Meta. This usually takes about 30 seconds - just wait for the verification to complete.

!Auto-verifying your number with Meta

Step 5: Continue to Meta Registration

Once verification is complete, click Continue to WhatsApp setup to register your phone number with Meta.

!Click continue to register with Meta

Step 6: Meta Account Setup

You'll be redirected to Meta's Embedded Signup. Here you can either create a new WhatsApp Business Account or connect to an existing one. Follow the prompts to complete the setup.

!Meta Embedded Signup - create or choose account

Planning to use the Groups API? In this step, do not choose "Connect existing WhatsApp Business app account". That option activates Coexistence, which disables group create and management endpoints. Create a new WABA or select a number that is not already in the WhatsApp Business app.

Step 7: Select Your Number

In the phone number selection, you'll see the number you purchased already marked as Verified. Select it and continue.

!Your purchased number appears as verified

Step 8: Connected!

Once verified, your WhatsApp account appears in your connections list with a connected status. You can now click Settings to configure it.

!WhatsApp connected successfully

Step 9: Manage Templates

Click Settings on your WhatsApp connection to view and create message templates. Templates must be approved by Meta before use.

!View and manage your WhatsApp templates

Step 10: Configure Business Profile

Switch to the Business Profile tab to customize your profile picture, display name, about text, description, and contact information.

!Configure your WhatsApp Business Profile

After connecting, you'll start in Meta's sandbox tier with a limit of 250 unique contacts per day. This limit increases automatically as you build messaging history and maintain quality.

Click-to-WhatsApp ads & attribution

Click-to-WhatsApp (CTWA) ads are Meta ads that, when tapped, open a WhatsApp conversation with your business instead of a website. They're a Meta Ads concept, Zernio creates them via POST /v1/ads/ctwa (see the Meta Ads page for the request shape and prerequisites).

This page covers the WhatsApp side of the loop: capturing the originating click and sending conversion events back to Meta for attribution.

Automatic ctwa_clid capture

When a user reaches your WhatsApp business via a CTWA ad, Meta attaches a referral object, including ctwa_clid (Meta's click ID for WhatsApp), to the first inbound message of the conversation. Zernio's webhook handler captures it automatically and persists it on the Conversation record's metadata:

json
{
  "metadata": {
    "ctwa_clid": "AbCdEfGhIjKlMn0pQrStUvWxYz",
    "ctwa_captured_at": "2026-04-27T09:18:44.991Z",
    "ctwa_source_id": "120000000000000000",
    "ctwa_source_url": "https://fb.me/...",
    "ctwa_headline": "Chat with us on WhatsApp",
    "ctwa_source_type": "ad"
  }
}

The capture is one-shot, once ctwa_clid is set, later messages from the same user never overwrite it (Meta only emits referral on the first message after a click).

Conversions API for Business Messaging

Forward conversion events that happen inside the WhatsApp thread back to Meta with action_source = business_messaging so they attribute to the originating CTWA ad. Distinct from Meta Ads' general Conversions API: that one is for web pixel events; this one is purpose-built for messaging conversions.

Configuration prerequisites on the WhatsApp account's metadata:

  • metaCapiDatasetId, the Meta Pixel/Dataset ID linked to the WABA

  • connectedFacebookPageId, the Facebook Page paired with the WhatsApp number

    The WhatsApp account's access token must have access to the configured dataset. By default a WABA's system-user token is scoped to the WABA's own Business Manager and cannot post to a pixel owned by a different Business, Meta returns code 100 in that case. Either share the dataset with the WhatsApp app's Business in Meta Business Manager, or use a dataset already in the same Business as the WABA.

Send a conversion event:

typescript
const result = await zernio.whatsapp.sendWhatsAppConversion({ body: {
  accountId: 'WHATSAPP_ACCOUNT_ID',
  conversationId: 'CONVERSATION_ID', // or use phoneE164
  eventName: 'LeadSubmitted',
  eventId: 'lead_abc_123',
  value: 49.00,
  currency: 'USD',
}});
python
result = client.whatsapp.send_whats_app_conversion(
    account_id="WHATSAPP_ACCOUNT_ID",
    conversation_id="CONVERSATION_ID",
    event_name="LeadSubmitted",
    event_id="lead_abc_123",
    value=49.00,
    currency="USD",
)
bash
curl -X POST "https://zernio.com/api/v1/whatsapp/conversions" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "accountId": "WHATSAPP_ACCOUNT_ID",
    "conversationId": "CONVERSATION_ID",
    "eventName": "LeadSubmitted",
    "eventId": "lead_abc_123",
    "value": 49.00,
    "currency": "USD"
  }'

Supported event names

Meta's allowlist for business_messaging events is narrower than the standard pixel CAPI:

EventUse for
LeadSubmittedForm filled, contact details captured, lead qualified
PurchaseCustomer completed a purchase (payment confirmed, invoice issued)
AddToCartCustomer added an item to cart in-thread
InitiateCheckoutCustomer started a checkout flow
ViewContentCustomer viewed a specific product / service

Lead (the standard pixel name) is not accepted on business_messaging events. Use LeadSubmitted instead. Other standard pixel names (CompleteRegistration, Subscribe, Schedule, Contact, StartTrial, AddPaymentInfo, Search, SubmitApplication) are also rejected, these constraints are live-verified against Graph API v25.0 and enforced at Zernio's request boundary.

Attribution window & test mode

Meta's attribution window is 7 days from click. If the customer's ctwa_clid was captured more than 7 days ago, the event still posts but won't attribute.

Pass testCode: "TEST12345" at the request root to route events to the Test Events tab in Meta Events Manager without affecting production dataset data.

Resolving the conversation

You can identify the originating conversation either way:

  • conversationId, preferred. The Zernio Conversation _id returned by list conversations.
  • phoneE164, fallback. Digits only, no +. The handler picks the most recent CTWA-attributed conversation for that phone on the supplied account.

If the resolved conversation has no captured ctwa_clid, the request returns 422, there's nothing to attribute (the conversation didn't originate from a CTWA ad, or pre-dates Zernio's capture).

Pricing & Costs

WhatsApp has two separate billing components: Zernio platform fees and Meta messaging fees.

What Zernio charges

All WhatsApp features (broadcasts, sequences, DM conversations) are included with the Usage plan. The Usage plan has no post limits or profile limits.

What Meta charges

Meta charges per delivered template message. These fees are billed directly to your WhatsApp Business Account, not through Zernio.

Message typeCost
Template messages (marketing, utility, authentication)Charged per delivery (varies by category + recipient country)
Non-template messages (within 24h customer service window)Free
Utility templates sent within customer service windowFree

Rates depend on the template category and the recipient's country code. See Meta's pricing page and rate cards by country for current rates.

You must set up a payment method in your WhatsApp Business Account through Meta Business Suite. Without a valid payment method, Meta will block template message delivery once your free tier is exhausted.

How billing works

Zernio and Meta bill separately. Your Zernio subscription covers platform access (API, broadcasts, contacts, templates, inbox). Meta bills your credit card directly through your WABA for message delivery fees. Zernio does not charge or mark up Meta's messaging fees.

Sandbox vs production numbers

Sandbox number - When you first connect via Embedded Signup, you can test with Meta's sandbox. Sandbox numbers have limited sending (up to 250 unique contacts/day) and messages are tagged as test.

Pre-verified US number - A dedicated production number purchased through Zernio. Available on all plans. The first number purchase requires a small deposit via Stripe that goes toward your account credits.

Bring your own number - Connect via Headless Credentials using your existing Meta System User token and phone number.

Quick Start

Send a WhatsApp template message to multiple recipients. Create a broadcast, add phone numbers, and send:

typescript
import Zernio from '@zernio/node';

const zernio = new Zernio();

// Step 1: Create a WhatsApp broadcast with a Meta-approved template
const { data: broadcast } = await zernio.broadcasts.createBroadcast({
  body: {
    profileId: 'YOUR_PROFILE_ID',
    accountId: 'YOUR_WHATSAPP_ACCOUNT_ID',
    platform: 'whatsapp',
    name: 'Welcome Campaign',
    template: {
      name: 'hello_world',
      language: 'en'
    }
  }
});

// Step 2: Add WhatsApp recipients by phone number
await zernio.broadcasts.addBroadcastRecipients({
  path: { broadcastId: broadcast.broadcast.id },
  body: {
    phones: ['+1234567890', '+0987654321']
  }
});

// Step 3: Send the WhatsApp broadcast
const { data: result } = await zernio.broadcasts.sendBroadcast({
  path: { broadcastId: broadcast.broadcast.id }
});
console.log(`Sent: ${result.sent}, Failed: ${result.failed}`);
python
from zernio import Zernio

client = Zernio()

# Step 1: Create a WhatsApp broadcast with a Meta-approved template
broadcast = client.broadcasts.create_broadcast(
    profile_id='YOUR_PROFILE_ID',
    account_id='YOUR_WHATSAPP_ACCOUNT_ID',
    platform='whatsapp',
    name='Welcome Campaign',
    template={
        'name': 'hello_world',
        'language': 'en'
    }
)

# Step 2: Add WhatsApp recipients by phone number
client.broadcasts.add_broadcast_recipients(
    broadcast_id=broadcast.broadcast.id,
    phones=['+1234567890', '+0987654321']
)

# Step 3: Send the WhatsApp broadcast
result = client.broadcasts.send_broadcast(
    broadcast_id=broadcast.broadcast.id
)
print(f"Sent: {result.sent}, Failed: {result.failed}")
bash
# Step 1: Create a WhatsApp broadcast
BROADCAST_ID=$(curl -s -X POST https://zernio.com/api/v1/broadcasts \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "profileId": "YOUR_PROFILE_ID",
    "accountId": "YOUR_WHATSAPP_ACCOUNT_ID",
    "platform": "whatsapp",
    "name": "Welcome Campaign",
    "template": {
      "name": "hello_world",
      "language": "en"
    }
  }' | jq -r '.broadcast.id')

# Step 2: Add WhatsApp recipients by phone number
curl -X POST "https://zernio.com/api/v1/broadcasts/$BROADCAST_ID/recipients" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"phones": ["+1234567890", "+0987654321"]}'

# Step 3: Send the WhatsApp broadcast
curl -X POST "https://zernio.com/api/v1/broadcasts/$BROADCAST_ID/send" \
  -H "Authorization: Bearer YOUR_API_KEY"

Broadcasts

Send WhatsApp template messages to many recipients at once. Broadcasts support per-recipient template variables, scheduling, and delivery tracking (sent, delivered, read).

Create a Broadcast

Create a WhatsApp broadcast by specifying your WABA account and a Meta-approved template:

typescript
const { data } = await zernio.broadcasts.createBroadcast({
  body: {
    profileId: 'YOUR_PROFILE_ID',
    accountId: 'YOUR_WHATSAPP_ACCOUNT_ID',
    platform: 'whatsapp',
    name: 'January Newsletter',
    template: {
      name: 'monthly_update',
      language: 'en',
      components: [{
        type: 'body',
        parameters: [{ type: 'text', text: '{{1}}' }]
      }]
    }
  }
});
console.log('Broadcast created:', data.broadcast.id);
python
response = client.broadcasts.create_broadcast(
    profile_id='YOUR_PROFILE_ID',
    account_id='YOUR_WHATSAPP_ACCOUNT_ID',
    platform='whatsapp',
    name='January Newsletter',
    template={
        'name': 'monthly_update',
        'language': 'en',
        'components': [{
            'type': 'body',
            'parameters': [{'type': 'text', 'text': '{{1}}'}]
        }]
    }
)
print(f"Broadcast created: {response.broadcast.id}")
bash
curl -X POST https://zernio.com/api/v1/broadcasts \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "profileId": "YOUR_PROFILE_ID",
    "accountId": "YOUR_WHATSAPP_ACCOUNT_ID",
    "platform": "whatsapp",
    "name": "January Newsletter",
    "template": {
      "name": "monthly_update",
      "language": "en",
      "components": [{
        "type": "body",
        "parameters": [{"type": "text", "text": "{{1}}"}]
      }]
    }
  }'

Add Recipients

Add WhatsApp recipients by phone number, existing contact IDs, or by matching your contact segment filters. Phone numbers are in E.164 format (e.g., +1234567890):

typescript
// Add WhatsApp recipients by phone number (auto-creates contacts)
const { data } = await zernio.broadcasts.addBroadcastRecipients({
  path: { broadcastId: 'BROADCAST_ID' },
  body: {
    phones: ['+1555000111', '+1555000222']
  }
});
console.log(`Added: ${data.added}, Skipped: ${data.skipped}`);

// Or add existing contacts by ID
await zernio.broadcasts.addBroadcastRecipients({
  path: { broadcastId: 'BROADCAST_ID' },
  body: {
    contactIds: ['contact_1', 'contact_2']
  }
});

// Or auto-populate from your broadcast's segment filters (e.g., all contacts tagged "vip")
await zernio.broadcasts.addBroadcastRecipients({
  path: { broadcastId: 'BROADCAST_ID' },
  body: { useSegment: true }
});
python
# Add WhatsApp recipients by phone number (auto-creates contacts)
response = client.broadcasts.add_broadcast_recipients(
    broadcast_id='BROADCAST_ID',
    phones=['+1555000111', '+1555000222']
)
print(f"Added: {response.added}, Skipped: {response.skipped}")

# Or add existing contacts by ID
client.broadcasts.add_broadcast_recipients(
    broadcast_id='BROADCAST_ID',
    contact_ids=['contact_1', 'contact_2']
)

# Or auto-populate from your broadcast's segment filters
client.broadcasts.add_broadcast_recipients(
    broadcast_id='BROADCAST_ID',
    use_segment=True
)
bash
# Add WhatsApp recipients by phone number
curl -X POST "https://zernio.com/api/v1/broadcasts/BROADCAST_ID/recipients" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"phones": ["+1555000111", "+1555000222"]}'

# Or add existing contacts by ID
curl -X POST "https://zernio.com/api/v1/broadcasts/BROADCAST_ID/recipients" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"contactIds": ["contact_1", "contact_2"]}'

Send a Broadcast

Triggers immediate delivery of the WhatsApp template messages to all recipients:

typescript
const { data } = await zernio.broadcasts.sendBroadcast({
  path: { broadcastId: 'BROADCAST_ID' }
});
console.log(`Sent: ${data.sent}, Failed: ${data.failed}`);
python
response = client.broadcasts.send_broadcast(
    broadcast_id='BROADCAST_ID'
)
print(f"Sent: {response.sent}, Failed: {response.failed}")
bash
curl -X POST "https://zernio.com/api/v1/broadcasts/BROADCAST_ID/send" \
  -H "Authorization: Bearer YOUR_API_KEY"

Schedule a Broadcast

Schedule the WhatsApp broadcast for a future time. Zernio sends the template messages automatically at the scheduled time:

typescript
await zernio.broadcasts.scheduleBroadcast({
  path: { broadcastId: 'BROADCAST_ID' },
  body: { scheduledAt: '2025-02-01T10:00:00.000Z' }
});
python
client.broadcasts.schedule_broadcast(
    broadcast_id='BROADCAST_ID',
    scheduled_at='2025-02-01T10:00:00.000Z'
)
bash
curl -X POST "https://zernio.com/api/v1/broadcasts/BROADCAST_ID/schedule" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"scheduledAt": "2025-02-01T10:00:00.000Z"}'

Templates

WhatsApp templates are required for initiating conversations outside the 24-hour messaging window. They must be submitted to Meta for approval before use.

List Templates

typescript
const { data } = await zernio.whatsapp.getWhatsAppTemplates({
  query: { accountId: 'YOUR_ACCOUNT_ID' }
});
data.templates.forEach(t => console.log(`${t.name} (${t.status}) - ${t.language}`));
python
response = client.whatsapp.get_whats_app_templates(
    account_id='YOUR_ACCOUNT_ID'
)
for t in response.templates:
    print(f"{t.name} ({t.status}) - {t.language}")
bash
curl "https://zernio.com/api/v1/whatsapp/templates?accountId=YOUR_ACCOUNT_ID" \
  -H "Authorization: Bearer YOUR_API_KEY"

Create a Template

typescript
const { data } = await zernio.whatsapp.createWhatsAppTemplate({
  body: {
    accountId: 'YOUR_ACCOUNT_ID',
    name: 'order_confirmation',
    category: 'UTILITY',
    language: 'en',
    components: [{ type: 'BODY', text: 'Hi {{1}}, your order {{2}} has been confirmed!' }]
  }
});
console.log(`Template created: ${data.template.name} (${data.template.status})`);
python
response = client.whatsapp.create_whats_app_template(
    account_id='YOUR_ACCOUNT_ID',
    name='order_confirmation',
    category='UTILITY',
    language='en',
    components=[{'type': 'BODY', 'text': 'Hi {{1}}, your order {{2}} has been confirmed!'}]
)
print(f"Template created: {response.template.name} ({response.template.status})")
bash
curl -X POST https://zernio.com/api/v1/whatsapp/templates \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "accountId": "YOUR_ACCOUNT_ID",
    "name": "order_confirmation",
    "category": "UTILITY",
    "language": "en",
    "components": [{"type": "BODY", "text": "Hi {{1}}, your order {{2}} has been confirmed!"}]
  }'

Templates are reviewed by Meta and can take up to 24 hours to be approved. Only approved templates can be used for sending messages.

Contacts

Manage your WhatsApp contact list for broadcasts and messaging. Store phone numbers, tags, opt-in status, and custom fields for each contact.

Create a Contact

Create a WhatsApp contact with their phone number. The phone number links the contact to your WABA for messaging:

typescript
const { data } = await zernio.contacts.createContact({
  body: {
    profileId: 'YOUR_PROFILE_ID',
    name: 'John Doe',
    email: 'john@example.com',
    tags: ['vip', 'newsletter'],
    // Link this contact to your WhatsApp number
    accountId: 'YOUR_WHATSAPP_ACCOUNT_ID',
    platform: 'whatsapp',
    platformIdentifier: '+1234567890'
  }
});
console.log('Contact created:', data.contact.id);
python
response = client.contacts.create_contact(
    profile_id='YOUR_PROFILE_ID',
    name='John Doe',
    email='john@example.com',
    tags=['vip', 'newsletter'],
    # Link this contact to your WhatsApp number
    account_id='YOUR_WHATSAPP_ACCOUNT_ID',
    platform='whatsapp',
    platform_identifier='+1234567890'
)
print(f"Contact created: {response.contact.id}")
bash
curl -X POST https://zernio.com/api/v1/contacts \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "profileId": "YOUR_PROFILE_ID",
    "name": "John Doe",
    "email": "john@example.com",
    "tags": ["vip", "newsletter"],
    "accountId": "YOUR_WHATSAPP_ACCOUNT_ID",
    "platform": "whatsapp",
    "platformIdentifier": "+1234567890"
  }'

Bulk Import

Import up to 1,000 WhatsApp contacts at once with phone numbers and tags. Duplicates are automatically skipped:

typescript
const { data } = await zernio.contacts.bulkCreateContacts({
  body: {
    profileId: 'YOUR_PROFILE_ID',
    accountId: 'YOUR_WHATSAPP_ACCOUNT_ID',
    platform: 'whatsapp',
    contacts: [
      { name: 'John Doe', platformIdentifier: '+1234567890', tags: ['vip'] },
      { name: 'Jane Smith', platformIdentifier: '+0987654321', tags: ['newsletter'] }
    ]
  }
});
console.log(`Created: ${data.created}, Skipped: ${data.skipped}`);
python
response = client.contacts.bulk_create_contacts(
    profile_id='YOUR_PROFILE_ID',
    account_id='YOUR_WHATSAPP_ACCOUNT_ID',
    platform='whatsapp',
    contacts=[
        {'name': 'John Doe', 'platform_identifier': '+1234567890', 'tags': ['vip']},
        {'name': 'Jane Smith', 'platform_identifier': '+0987654321', 'tags': ['newsletter']}
    ]
)
print(f"Created: {response.created}, Skipped: {response.skipped}")
bash
curl -X POST https://zernio.com/api/v1/contacts/bulk \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "profileId": "YOUR_PROFILE_ID",
    "accountId": "YOUR_WHATSAPP_ACCOUNT_ID",
    "platform": "whatsapp",
    "contacts": [
      {"name": "John Doe", "platformIdentifier": "+1234567890", "tags": ["vip"]},
      {"name": "Jane Smith", "platformIdentifier": "+0987654321", "tags": ["newsletter"]}
    ]
  }'

Update a Contact

Update a WhatsApp contact's tags, opt-in status, or other fields:

typescript
const { data } = await zernio.contacts.updateContact({
  path: { contactId: 'CONTACT_ID' },
  body: {
    tags: ['vip', 'promo-march'],
    isSubscribed: true
  }
});
console.log('Updated:', data.contact.id);
python
response = client.contacts.update_contact(
    contact_id='CONTACT_ID',
    tags=['vip', 'promo-march'],
    is_subscribed=True
)
print(f"Updated: {response.contact.id}")
bash
curl -X PATCH "https://zernio.com/api/v1/contacts/CONTACT_ID" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"tags": ["vip", "promo-march"], "isSubscribed": true}'

Business Profile

typescript
// Get business profile
const { data } = await zernio.whatsapp.getWhatsAppBusinessProfile({
  query: { accountId: 'YOUR_ACCOUNT_ID' }
});
console.log(data.businessProfile);

// Update business profile
await zernio.whatsapp.updateWhatsAppBusinessProfile({
  body: {
    accountId: 'YOUR_ACCOUNT_ID',
    about: 'Your go-to store for widgets',
    description: 'We sell the best widgets in town.',
    email: 'hello@example.com',
    websites: ['https://example.com']
  }
});
python
# Get business profile
response = client.whatsapp.get_whats_app_business_profile(
    account_id='YOUR_ACCOUNT_ID'
)
print(response.business_profile)

# Update business profile
client.whatsapp.update_whats_app_business_profile(
    account_id='YOUR_ACCOUNT_ID',
    about='Your go-to store for widgets',
    description='We sell the best widgets in town.',
    email='hello@example.com',
    websites=['https://example.com']
)
bash
# Get business profile
curl "https://zernio.com/api/v1/whatsapp/business-profile?accountId=YOUR_ACCOUNT_ID" \
  -H "Authorization: Bearer YOUR_API_KEY"

# Update business profile
curl -X POST https://zernio.com/api/v1/whatsapp/business-profile \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "accountId": "YOUR_ACCOUNT_ID",
    "about": "Your go-to store for widgets",
    "description": "We sell the best widgets in town.",
    "email": "hello@example.com",
    "websites": ["https://example.com"]
  }'

Phone Numbers

Manage WhatsApp phone numbers: purchase, verify, and release numbers for your WABA.

List Your Numbers

typescript
const { data } = await zernio.whatsappphonenumbers.getWhatsAppPhoneNumbers();
data.numbers.forEach(n => console.log(`${n.phoneNumber} (${n.status})`));
python
response = client.whatsapp_phone_numbers.get_whats_app_phone_numbers()
for n in response.numbers:
    print(f"{n.phone_number} ({n.status})")
bash
curl "https://zernio.com/api/v1/whatsapp/phone-numbers" \
  -H "Authorization: Bearer YOUR_API_KEY"

Purchase a Number

typescript
const { data } = await zernio.whatsappphonenumbers.purchaseWhatsAppPhoneNumber({
  body: { profileId: 'YOUR_PROFILE_ID' }
});
// First number returns a Stripe checkout URL
if (data.checkoutUrl) {
  console.log('Complete payment:', data.checkoutUrl);
} else {
  console.log('Number provisioned:', data.phoneNumber.phoneNumber);
}
python
response = client.whatsapp_phone_numbers.purchase_whats_app_phone_number(
    profile_id='YOUR_PROFILE_ID'
)
# First number returns a Stripe checkout URL
if hasattr(response, 'checkout_url') and response.checkout_url:
    print(f"Complete payment: {response.checkout_url}")
else:
    print(f"Number provisioned: {response.phone_number.phone_number}")
bash
curl -X POST https://zernio.com/api/v1/whatsapp/phone-numbers/purchase \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"profileId": "YOUR_PROFILE_ID"}'

Verify a Number

After purchasing, verify the number with Meta by requesting an OTP and submitting it:

The published Node SDK (@zernio/node) and Python SDK (zernio-sdk) do not yet expose dedicated methods for requestWhatsAppVerificationCode / verifyWhatsAppPhoneNumber. Use raw HTTP requests until the next SDK regen catches up.

bash
# Step 1: Request verification code
curl -X POST "https://zernio.com/api/v1/whatsapp/phone-numbers/PHONE_NUMBER_ID/request-code" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"method": "SMS"}'

# Step 2: Submit the code
curl -X POST "https://zernio.com/api/v1/whatsapp/phone-numbers/PHONE_NUMBER_ID/verify" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"code": "123456"}'

Media Requirements

Images

PropertyRequirement
FormatsJPEG, PNG
Max file size5 MB

Videos

PropertyRequirement
FormatsMP4, 3GPP
Max file size16 MB
CodecH.264 video, AAC audio

Documents

PropertyRequirement
FormatsPDF, DOC, DOCX, XLS, XLSX, PPT, PPTX, TXT
Max file size100 MB

Audio

PropertyRequirement
FormatsMP3, OGG (with opus codec), AMR, AAC
Max file size16 MB

Analytics

WhatsApp does not provide post-level analytics through its API. Message delivery status (sent, delivered, read) is tracked per-recipient in broadcasts.

What You Can't Do

  • Send free-form messages outside the 24-hour conversation window (must use templates)
  • Send messages to numbers without WhatsApp
  • Use personal WhatsApp accounts (must be WhatsApp Business)
  • Send more than 250 unique contacts/day on a new account (tier 0 limit, increases with usage)
  • Schedule individual messages (use broadcasts with scheduling instead)
  • Get per-message analytics (only delivery status)

Common Errors

ErrorCauseFix
"Template not found" (132001)Template name or language code doesn't matchVerify the exact template name and language code (e.g., "en" not "en_US")
"Invalid phone number" (131021)Recipient number format is incorrect or doesn't have WhatsAppUse E.164 format with country code (e.g., +1234567890)
"Re-engagement required" (131026)24-hour conversation window expiredSend an approved template message to re-initiate
"Rate limit hit" (131047)Too many messages sent too quicklyReduce sending frequency, wait for rate limit to reset
"Media download failed" (131052)WhatsApp can't fetch media from the URLEnsure URL is publicly accessible with no auth required
"Not in allowed list" (131030)Number not in Meta's sandbox test listAdd the number to your test recipients in Meta Business Suite
"Account locked" (131031)Meta suspended the WhatsApp Business accountContact Meta support to resolve

Group Chats

Create and manage WhatsApp group conversations directly from the API. Groups appear in the Inbox alongside individual conversations, and you can send messages to groups using the same messaging endpoints.

The Groups API is not supported on phone numbers connected via Coexistence (Cloud API + WhatsApp Business app on the same number). Meta disables group create, list, and management endpoints for coexistence and Multi-solution Conversations setups. To use the Groups API, connect a number in Cloud API-only mode.

How to tell if a number is in Coexistence

  • If the same phone number is still active in the WhatsApp Business app on a phone and connected to Zernio at the same time, it's Coexistence.
  • You can also check in Meta Business Suite under WhatsApp Accounts > Phone Numbers. Numbers running Coexistence keep the mobile app registration active alongside the Cloud API.

Migrating a Coexistence number to Cloud API-only

Meta does not expose an API to flip an existing number out of Coexistence. The business has to disconnect from the WhatsApp Business app (Settings > Account > Business Platform > Disconnect on the phone). Once disconnected, Zernio deactivates the account automatically. Reconnect the number via Embedded Signup or Headless Credentials without choosing the "existing WA Business app account" option, and the Groups API will be available.

These are actual WhatsApp group chats on the platform, not contact groups used for broadcast targeting (which are at /v1/whatsapp/groups).

Create a Group

typescript
const { data } = await zernio.whatsapp.createWhatsAppGroupChat({
  body: {
    accountId: 'YOUR_WHATSAPP_ACCOUNT_ID',
    subject: 'Customer Support Team',
    description: 'Internal support coordination',
    joinApprovalMode: 'approval_required'
  }
});
console.log('Group created:', data.group.groupId);
console.log('Invite link:', data.group.inviteLink);
python
response = client.whatsapp.create_whats_app_group_chat(
    account_id='YOUR_WHATSAPP_ACCOUNT_ID',
    subject='Customer Support Team',
    description='Internal support coordination',
    join_approval_mode='approval_required'
)
print(f"Group created: {response.group.group_id}")
bash
curl -X POST https://zernio.com/api/v1/whatsapp/wa-groups \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "accountId": "YOUR_WHATSAPP_ACCOUNT_ID",
    "subject": "Customer Support Team",
    "description": "Internal support coordination",
    "joinApprovalMode": "approval_required"
  }'

List Active Groups

typescript
const { data } = await zernio.whatsapp.listWhatsAppGroupChats({
  query: { accountId: 'YOUR_WHATSAPP_ACCOUNT_ID', limit: 50 }
});
data.groups.forEach(g => console.log(`${g.subject} (${g.id})`));
python
response = client.whatsapp.list_whats_app_group_chats(
    account_id='YOUR_WHATSAPP_ACCOUNT_ID',
    limit=50
)
for g in response.groups:
    print(f"{g.subject} ({g.id})")
bash
curl "https://zernio.com/api/v1/whatsapp/wa-groups?accountId=YOUR_WHATSAPP_ACCOUNT_ID&limit=50" \
  -H "Authorization: Bearer YOUR_API_KEY"

Manage Participants

Add up to 8 participants per request, or remove participants from a group:

typescript
// Add participants
await zernio.whatsapp.addWhatsAppGroupParticipants({
  path: { groupId: 'GROUP_ID' },
  query: { accountId: 'YOUR_WHATSAPP_ACCOUNT_ID' },
  body: { phoneNumbers: ['+1234567890', '+0987654321'] }
});

// Remove participants
await zernio.whatsapp.removeWhatsAppGroupParticipants({
  path: { groupId: 'GROUP_ID' },
  query: { accountId: 'YOUR_WHATSAPP_ACCOUNT_ID' },
  body: { phoneNumbers: ['+1234567890'] }
});
python
# Add participants
client.whatsapp.add_whats_app_group_participants(
    group_id='GROUP_ID',
    account_id='YOUR_WHATSAPP_ACCOUNT_ID',
    phone_numbers=['+1234567890', '+0987654321']
)

# Remove participants
client.whatsapp.remove_whats_app_group_participants(
    group_id='GROUP_ID',
    account_id='YOUR_WHATSAPP_ACCOUNT_ID',
    phone_numbers=['+1234567890']
)
bash
# Add participants
curl -X POST "https://zernio.com/api/v1/whatsapp/wa-groups/GROUP_ID/participants?accountId=YOUR_WHATSAPP_ACCOUNT_ID" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"phoneNumbers": ["+1234567890", "+0987654321"]}'

# Remove participants
curl -X DELETE "https://zernio.com/api/v1/whatsapp/wa-groups/GROUP_ID/participants?accountId=YOUR_WHATSAPP_ACCOUNT_ID" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"phoneNumbers": ["+1234567890"]}'

Generate invite links for your group and manage pending join requests:

typescript
// Create invite link
const { data } = await zernio.whatsapp.createWhatsAppGroupInviteLink({
  path: { groupId: 'GROUP_ID' },
  query: { accountId: 'YOUR_WHATSAPP_ACCOUNT_ID' }
});
console.log('Invite link:', data.inviteLink);

// List pending join requests (for groups with approval_required)
const { data: requests } = await zernio.whatsapp.listWhatsAppGroupJoinRequests({
  path: { groupId: 'GROUP_ID' },
  query: { accountId: 'YOUR_WHATSAPP_ACCOUNT_ID' }
});

// Approve join requests
await zernio.whatsapp.approveWhatsAppGroupJoinRequests({
  path: { groupId: 'GROUP_ID' },
  query: { accountId: 'YOUR_WHATSAPP_ACCOUNT_ID' },
  body: { phoneNumbers: ['+1234567890'] }
});
bash
# Create invite link
curl -X POST "https://zernio.com/api/v1/whatsapp/wa-groups/GROUP_ID/invite-link?accountId=YOUR_WHATSAPP_ACCOUNT_ID" \
  -H "Authorization: Bearer YOUR_API_KEY"

# List pending join requests
curl "https://zernio.com/api/v1/whatsapp/wa-groups/GROUP_ID/join-requests?accountId=YOUR_WHATSAPP_ACCOUNT_ID" \
  -H "Authorization: Bearer YOUR_API_KEY"

# Approve join requests
curl -X POST "https://zernio.com/api/v1/whatsapp/wa-groups/GROUP_ID/join-requests?accountId=YOUR_WHATSAPP_ACCOUNT_ID" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"phoneNumbers": ["+1234567890"]}'

Sending Messages to Groups

Send messages to a group using the standard Inbox messaging API. Group conversations are created automatically when a group message is received, and you can reply using the conversation ID:

typescript
// Send a text message to a group conversation
await zernio.messages.sendInboxMessage({
  path: { conversationId: 'CONVERSATION_ID' },
  body: {
    accountId: 'YOUR_ACCOUNT_ID',
    message: 'Hello team!',
  },
});
python
client.messages.send_inbox_message(
    conversation_id="CONVERSATION_ID",
    account_id="YOUR_ACCOUNT_ID",
    message="Hello team!",
)
bash
curl -X POST "https://zernio.com/api/v1/inbox/conversations/CONVERSATION_ID/messages" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "accountId": "YOUR_ACCOUNT_ID",
    "message": "Hello team!"
  }'

Group messages from all participants appear in the Inbox. Each group has its own conversation thread identified by the group ID.

Inbox

> Included — Inbox (DMs, comments, reviews) is bundled with every paid account on the Usage plan.

All WhatsApp features (broadcasts, sequences, DM conversations) are included with the Usage plan. WhatsApp DM conversations are available through the unified Inbox API, which aggregates conversations across all supported platforms.

Direct Messages

FeatureSupported
List conversationsYes
Fetch messagesYes
Send text messagesYes
Send attachmentsYes (images, videos, documents, audio)
Archive/unarchiveYes

Attachment Support

TypeSupportedMax Size
ImagesYes5 MB
VideosYes16 MB
DocumentsYes100 MB
AudioYes16 MB

Webhooks

WhatsApp emits the full set of message + delivery lifecycle webhooks:

EventWhen it fires
message.receivedNew incoming WhatsApp message
message.sentOutgoing message is sent
message.deliveredOutgoing message is delivered to the recipient
message.readRecipient reads an outgoing message
message.failedOutgoing message fails to deliver, the payload error object carries the Cloud API error code (e.g. 131026 recipient phone not reachable)
message.deletedThe business deletes a previously-sent outgoing message via DELETE /v1/inbox/conversations/{conversationId}/messages/{messageId}

Subscribe via Create webhook settings. See the Webhooks page for payload details.

Note: WhatsApp Cloud API does not expose incoming-message edits or recipient-side unsends, so message.edited and incoming-side message.deleted are not emitted. These are platform limitations.

Notes

  • 24-hour window: Free-form messages only within 24 hours of customer's last message
  • Templates: Required to initiate or re-initiate conversations outside the window
  • Delivery tracking: Messages have sent/delivered/read status updates via webhooks

See Inbox API Reference for endpoint details.

Flows

WhatsApp Flows let you build native interactive forms, surveys, and booking experiences inside WhatsApp. Flows are created in DRAFT status, populated with a Flow JSON definition, then published for sending. Published flows are immutable -- to update, create a new flow (optionally cloning the old one).

Create and Publish a Flow

typescript
// Step 1: Create a flow
const { data } = await zernio.whatsappflows.createWhatsAppFlow({
  body: {
    accountId: 'YOUR_WHATSAPP_ACCOUNT_ID',
    name: 'lead_capture_form',
    categories: ['LEAD_GENERATION']
  }
});
const flowId = data.flow.id;

// Step 2: Upload the Flow JSON
await zernio.whatsappflows.uploadWhatsAppFlowJson({
  path: { flowId },
  body: {
    accountId: 'YOUR_WHATSAPP_ACCOUNT_ID',
    flow_json: {
      version: '6.0',
      screens: [{
        id: 'LEAD_FORM',
        title: 'Get a Quote',
        terminal: true,
        success: true,
        layout: {
          type: 'SingleColumnLayout',
          children: [
            { type: 'TextInput', name: 'full_name', label: 'Full Name', required: true, 'input-type': 'text' },
            { type: 'TextInput', name: 'email', label: 'Email', required: true, 'input-type': 'email' },
            { type: 'Footer', label: 'Submit', 'on-click-action': { name: 'complete', payload: { full_name: '${form.full_name}', email: '${form.email}' } } }
          ]
        }
      }]
    }
  }
});

// Step 3: Publish (irreversible)
await zernio.whatsappflows.publishWhatsAppFlow({
  path: { flowId },
  body: { accountId: 'YOUR_WHATSAPP_ACCOUNT_ID' }
});
python
# Step 1: Create a flow
response = client.whatsapp_flows.create_whats_app_flow(
    account_id='YOUR_WHATSAPP_ACCOUNT_ID',
    name='lead_capture_form',
    categories=['LEAD_GENERATION']
)
flow_id = response.flow.id

# Step 2: Upload the Flow JSON
client.whatsapp_flows.upload_whats_app_flow_json(
    flow_id=flow_id,
    account_id='YOUR_WHATSAPP_ACCOUNT_ID',
    flow_json={
        'version': '6.0',
        'screens': [{
            'id': 'LEAD_FORM',
            'title': 'Get a Quote',
            'terminal': True,
            'success': True,
            'layout': {
                'type': 'SingleColumnLayout',
                'children': [
                    {'type': 'TextInput', 'name': 'full_name', 'label': 'Full Name', 'required': True, 'input-type': 'text'},
                    {'type': 'TextInput', 'name': 'email', 'label': 'Email', 'required': True, 'input-type': 'email'},
                    {'type': 'Footer', 'label': 'Submit', 'on-click-action': {'name': 'complete', 'payload': {'full_name': '${form.full_name}', 'email': '${form.email}'}}}
                ]
            }
        }]
    }
)

# Step 3: Publish (irreversible)
client.whatsapp_flows.publish_whats_app_flow(
    flow_id=flow_id,
    account_id='YOUR_WHATSAPP_ACCOUNT_ID'
)
bash
# Step 1: Create a flow
FLOW_ID=$(curl -s -X POST https://zernio.com/api/v1/whatsapp/flows \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "accountId": "YOUR_WHATSAPP_ACCOUNT_ID",
    "name": "lead_capture_form",
    "categories": ["LEAD_GENERATION"]
  }' | jq -r '.flow.id')

# Step 2: Upload the Flow JSON
curl -X PUT "https://zernio.com/api/v1/whatsapp/flows/$FLOW_ID/json" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "accountId": "YOUR_WHATSAPP_ACCOUNT_ID",
    "flow_json": {
      "version": "6.0",
      "screens": [{
        "id": "LEAD_FORM",
        "title": "Get a Quote",
        "terminal": true,
        "success": true,
        "layout": {
          "type": "SingleColumnLayout",
          "children": [
            {"type": "TextInput", "name": "full_name", "label": "Full Name", "required": true, "input-type": "text"},
            {"type": "TextInput", "name": "email", "label": "Email", "required": true, "input-type": "email"},
            {"type": "Footer", "label": "Submit", "on-click-action": {"name": "complete", "payload": {"full_name": "${form.full_name}", "email": "${form.email}"}}}
          ]
        }
      }]
    }
  }'

# Step 3: Publish (irreversible)
curl -X POST "https://zernio.com/api/v1/whatsapp/flows/$FLOW_ID/publish" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"accountId": "YOUR_WHATSAPP_ACCOUNT_ID"}'

Flow Lifecycle

StatusDescription
DRAFTEditable. Upload/update JSON, change name and categories.
PUBLISHEDImmutable. Can be sent to users. To update, create a new flow (optionally clone via cloneFlowId).
DEPRECATEDNo longer sendable.
BLOCKEDBlocked by Meta for policy violations.
THROTTLEDTemporarily rate-limited by Meta.

Flow Categories

SIGN_UP, SIGN_IN, APPOINTMENT_BOOKING, LEAD_GENERATION, CONTACT_US, CUSTOMER_SUPPORT, SURVEY, OTHER

Publishing a flow is irreversible. Once published, the flow and its JSON cannot be modified. To make changes, create a new flow using cloneFlowId to copy the existing one as a starting point.

See WhatsApp Flows API Reference for all endpoints.

  • Broadcasts - Create and send WhatsApp broadcast campaigns
  • Contacts - Manage your WhatsApp contact list
  • Templates - Manage Meta-approved WhatsApp templates
  • Group Chats - Create and manage WhatsApp group conversations
  • Flows - Build interactive forms, surveys, and booking experiences
  • Connect via Credentials - Headless WhatsApp connection
  • Inbox - View and manage WhatsApp DM conversations (included with the Usage plan)