Third-Party API Integrations

WhatsApp Business API Integration for Indian Businesses

By Domain India Team · DomainIndia EngineeringPublished 11 min read
Knowledge base article
Contents (11 sections)

India is WhatsApp's largest market, and most customers would rather get an order update on WhatsApp than by SMS. The WhatsApp Business Platform lets your website send order updates, OTPs and approved promotional messages from code, and receive replies through a webhook. This guide covers the Meta Cloud API, managed providers, templates, webhooks and where the code runs on Domain India hosting.

Key takeaways

Use Meta's Cloud API directly if you have a developer, or a Business Solution Provider (BSP) such as Gupshup, Wati, Interakt or AiSensy if you want a dashboard. Every business-initiated message must use a template Meta has approved, and Meta charges by message category. A PHP or Node.js webhook runs fine on shared hosting; bulk sending with queue workers belongs on a VPS.

1. Which API is right for you

ProviderSetup effortCost modelBest for
Meta Cloud API (direct)A few days, including business verificationMeta's per-message charges onlyTeams with a developer
Gupshup and similar BSPsProvider guides onboardingMeta's charges plus the provider's feeBusinesses that want help with onboarding
Wati, Interakt, AiSensyQuick start with a no-code dashboard and an APIMonthly subscription plus message chargesNon-technical founders and marketing teams

Meta launched the Cloud API in 2022 and has since retired the self-hosted On-Premises API, so the Cloud API (directly or through a BSP) is the way in.

2. How Meta charges (check the live rate card)

Meta's pricing is the provider's own and changes regularly, so always read the current WhatsApp Business Platform rate card for India before you budget. The structure at the time of writing:

CategoryTypical useHow it is charged
MarketingOffers, campaigns, re-engagementPer delivered template message; the highest rate
UtilityOrder confirmation, delivery update, appointment reminderPer delivered template message; free when sent inside an open customer service window
AuthenticationOne-time passwordsPer delivered template message; low rate
ServiceFree-form replies to a customer who messaged youFree inside the 24-hour customer service window

When a customer messages you, a 24-hour customer service window opens. Inside it you can reply freely; outside it you must send an approved template.

3. Set up the Meta Cloud API

  1. Create a Meta developer app.
    Go to developers.facebook.com, open My Apps, create an app of the Business type and add the WhatsApp product.
  2. Test with the free test number.
    Meta gives you a test phone number and lets you message a few verified recipients.
  3. Verify your business.
    In Meta Business Manager, complete business verification with your company documents and a live website.
  4. Add your real phone number.
    Register the number you want customers to see. A number already used in the WhatsApp app must be moved or removed first.
  5. Create a permanent token.
    The token shown on the setup page expires in about 24 hours. For production, create a System User in Business Manager and generate a token for it. Store it as an environment variable or outside public_html, never in your code.

4. Send your first message

Use the current Graph API version shown in Meta's documentation; v23.0 below is an example.

bash
curl -X POST "https://graph.facebook.com/v23.0/$WA_PHONE_ID/messages" \
  -H "Authorization: Bearer $WA_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "messaging_product": "whatsapp",
    "to": "919876543210",
    "type": "template",
    "template": { "name": "hello_world", "language": { "code": "en_US" } }
  }'

hello_world is a sample template every new account has. For your own messages, you submit templates for approval.

PHP:

php
function sendWhatsApp(string $to, string $templateName, array $components = []): array {
    $url = 'https://graph.facebook.com/v23.0/' . getenv('WA_PHONE_ID') . '/messages';
    $body = [
        'messaging_product' => 'whatsapp',
        'to'       => $to,
        'type'     => 'template',
        'template' => [
            'name'       => $templateName,
            'language'   => ['code' => 'en'],   // must match the template's language
            'components' => $components,
        ],
    ];
    $ch = curl_init($url);
    curl_setopt_array($ch, [
        CURLOPT_POST           => true,
        CURLOPT_POSTFIELDS     => json_encode($body),
        CURLOPT_HTTPHEADER     => [
            'Authorization: Bearer ' . getenv('WA_ACCESS_TOKEN'),
            'Content-Type: application/json',
        ],
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_TIMEOUT        => 15,
    ]);
    $response = curl_exec($ch);
    if ($response === false) {
        throw new RuntimeException('WhatsApp API error: ' . curl_error($ch));
    }
    return json_decode($response, true);
}

// Order confirmation
sendWhatsApp('919876543210', 'order_confirmation', [[
    'type' => 'body',
    'parameters' => [
        ['type' => 'text', 'text' => 'Rajesh'],     // {{1}}
        ['type' => 'text', 'text' => 'ORD-1234'],   // {{2}}
        ['type' => 'text', 'text' => '₹1,500'],     // {{3}}
    ],
]]);

Node.js (built-in fetch, Node 18 and later):

javascript
async function sendWhatsApp(to, template, components = []) {
  const resp = await fetch(
    `https://graph.facebook.com/v23.0/${process.env.WA_PHONE_ID}/messages`,
    {
      method: 'POST',
      headers: {
        Authorization: `Bearer ${process.env.WA_ACCESS_TOKEN}`,
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        messaging_product: 'whatsapp',
        to,
        type: 'template',
        template: { name: template, language: { code: 'en' }, components },
      }),
    }
  );
  if (!resp.ok) throw new Error(`WhatsApp API ${resp.status}: ${await resp.text()}`);
  return resp.json();
}

5. Get your templates approved

Meta reviews every template before you can send it. Many are reviewed within minutes; some take up to a day.

  1. Open the template manager.
    In WhatsApp Manager, go to Message templates and create a new one.
  2. Name it.
    Lowercase with underscores, for example order_confirmation.
  3. Pick the category.
    Marketing, Utility or Authentication. Choose honestly; Meta can recategorise a template.
  4. Pick the language.
    English, Hindi, Tamil and other Indian languages are supported. Each language is a separate version.
  5. Write the body with variables.
    For example: "Hi {{1}}, your order {{2}} for {{3}} has been confirmed. Track it on our website." Add sample values when asked.
  6. Submit.
    If it is rejected, read the reason, edit and resubmit.

Approval tips:

  • Keep utility templates clearly transactional; promotional wording belongs in Marketing.
  • Don't start or end the body with a variable, and don't put two variables side by side.
  • Use your own full domain in links; shortened links are often rejected.
  • Keep emojis and capitals to a minimum.

6. Receive messages with a webhook

Replies and delivery receipts arrive at a webhook on your site, for example https://yourcompany.com/webhook/whatsapp. Meta requires HTTPS with a valid certificate. Check the X-Hub-Signature-256 header so nobody else can post fake events.

javascript
import express from 'express';
import crypto from 'node:crypto';

const app = express();

// Verification (GET): Meta checks the endpoint when you register it
app.get('/webhook/whatsapp', (req, res) => {
  if (req.query['hub.mode'] === 'subscribe' &&
      req.query['hub.verify_token'] === process.env.WA_VERIFY_TOKEN) {
    return res.send(req.query['hub.challenge']);
  }
  res.sendStatus(403);
});

// Events (POST): keep the raw body to check the signature
app.post('/webhook/whatsapp', express.raw({ type: 'application/json' }), async (req, res) => {
  const expected = 'sha256=' + crypto
    .createHmac('sha256', process.env.WA_APP_SECRET)
    .update(req.body)
    .digest('hex');
  const got = req.get('X-Hub-Signature-256') || '';
  if (got.length !== expected.length ||
      !crypto.timingSafeEqual(Buffer.from(got), Buffer.from(expected))) {
    return res.sendStatus(401);
  }

  res.sendStatus(200);          // answer quickly; Meta retries slow or failed deliveries

  const value = JSON.parse(req.body).entry?.[0]?.changes?.[0]?.value;
  for (const msg of value?.messages ?? []) {
    await handleIncomingMessage(msg.from, msg.text?.body);   // auto-reply, create ticket, etc.
  }
  for (const s of value?.statuses ?? []) {
    await updateDeliveryStatus(s.id, s.status);              // sent, delivered, read, failed
  }
});

The same flow in PHP: read php://input, compare hash_hmac('sha256', $raw, $appSecret) with the header using hash_equals, then decode the JSON. Register the webhook URL and verify token in the app's WhatsApp configuration, and subscribe to the messages field.

Meta can deliver the same event more than once, so store message IDs and ignore duplicates.

7. Interactive messages: buttons and lists

Inside the 24-hour window you can send interactive messages.

Quick reply buttons:

json
{
  "messaging_product": "whatsapp",
  "to": "919876543210",
  "type": "interactive",
  "interactive": {
    "type": "button",
    "body": { "text": "Did your package arrive?" },
    "action": {
      "buttons": [
        { "type": "reply", "reply": { "id": "yes", "title": "Yes" } },
        { "type": "reply", "reply": { "id": "no", "title": "No, issues" } }
      ]
    }
  }
}

Product lists (for businesses with a catalogue connected in Commerce Manager) use "type": "product_list" with your catalog_id and sections of product IDs. Customers browse, add to cart and send the order without leaving WhatsApp.

8. OTPs over WhatsApp

WhatsApp OTPs use the Authentication category. Meta supplies the wording for authentication templates ("{{1}} is your verification code", with optional security and expiry lines) and adds a copy-code or one-tap button; you can't write free text.

php
$otp = random_int(100000, 999999);

// Store only a hash, with an expiry, in your database
$stmt = $pdo->prepare('REPLACE INTO otp_codes (phone, code_hash, expires_at) VALUES (?, ?, NOW() + INTERVAL 10 MINUTE)');
$stmt->execute([$phone, password_hash((string) $otp, PASSWORD_DEFAULT)]);

sendWhatsApp($phone, 'otp_login', [
    ['type' => 'body', 'parameters' => [['type' => 'text', 'text' => (string) $otp]]],
    ['type' => 'button', 'sub_type' => 'url', 'index' => '0',
     'parameters' => [['type' => 'text', 'text' => (string) $otp]]],
]);

Limit attempts per phone number, delete the code once it is used, and keep SMS as a fallback for users without WhatsApp.

9. Running this on Domain India hosting

  • Shared hosting (cPanel or DirectAdmin): a PHP webhook and sendWhatsApp() calls are ordinary request/response code, so they run on shared hosting. The free SSL on your hosting gives Meta the HTTPS endpoint it needs. On cPanel, curl_exec works; on DirectAdmin it is disabled on many sites, so test on your plan (see PHP disabled functions on shared hosting).
  • Node.js: the Setup Node.js App tool on cPanel and DirectAdmin can run the Express webhook above. See deploying a Node.js app on shared hosting. The App Platform also detects and builds Node.js apps automatically.
  • No Redis on shared hosting or the App Platform. Store OTPs and message IDs in MySQL or PostgreSQL, as in the example above.
  • Bulk campaigns and queue workers: long-running processes are stopped on shared hosting, and scheduled jobs run at most every 4 minutes. For large sends with a queue and workers, use a VPS, which is self-managed.
Keep your access token secret

Anyone with your WhatsApp access token can send messages as your business and run up charges. Keep it in an environment variable or a config file outside public_html, never in JavaScript that reaches the browser, and rotate it if it leaks.

10. Common pitfalls

Sending without an approved template
Meta rejects business-initiated messages that don't use an approved template. Free-form text works only inside the 24-hour window.
24-hour window expired
You can't send free text after the window closes. Send a template to restart the conversation.
Business not verified
Production sending needs a verified business. The test number works until then.
Messaging limit reached
New numbers can message a limited number of unique users per day. The limit rises as you send good-quality messages.
Blocks and spam reports
When users block you, your quality rating drops and Meta may lower your limits. Send only what customers asked for.
Unsigned webhooks
Without the X-Hub-Signature-256 check, anyone can post fake "message received" events to your endpoint.

FAQ

Can I automate a normal WhatsApp or WhatsApp Business app number?

No. Automating the consumer or Business app breaks WhatsApp's terms and risks a ban. The WhatsApp Business Platform (the Cloud API, directly or through a BSP) is the supported way to automate messages.

Should I use Meta directly or a BSP?

If you have a developer, the Cloud API directly avoids a middleman's fee. If you want a no-code dashboard, shared inbox and campaign tools, a BSP such as Gupshup, Wati, Interakt or AiSensy is quicker to start with.

How long does business verification take?

It varies, from a day or two to longer if Meta asks for more documents. Keep your company documents ready and make sure your website is live and shows the same business name.

Can I send marketing messages to anyone?

No. Customers must have opted in to receive WhatsApp messages from you, for example with a consent checkbox on your website. Messaging people who didn't opt in leads to blocks and lower limits.

What does WhatsApp messaging cost in India?

Meta charges per delivered template message, with Marketing the most expensive and Authentication and Utility much cheaper; replies inside the 24-hour customer service window are free. Rates change, so check Meta's current rate card for India.

Can I run a WhatsApp webhook on Domain India shared hosting?

Yes, for request/response code such as a PHP webhook or a Node.js app in Setup Node.js App on cPanel or DirectAdmin. Long-running queue workers are stopped on shared hosting, so bulk sending with workers needs a VPS.

Ready to connect WhatsApp to your site? Host the webhook on cPanel hosting or DirectAdmin hosting, run a Node.js service on the App Platform, or use a VPS for bulk sending. Questions about your plan? Open a support ticket.

Send WhatsApp updates from your website

Run your WhatsApp webhook and order notifications on Domain India hosting with free SSL.

See hosting plans

Was this article helpful?

Your answer helps us decide what to improve next.

Still need help? Open a support ticket and our team will reply.

Prefer an app? Add this site to your home screen.Get the app