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.
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
| Provider | Setup effort | Cost model | Best for |
|---|---|---|---|
| Meta Cloud API (direct) | A few days, including business verification | Meta's per-message charges only | Teams with a developer |
| Gupshup and similar BSPs | Provider guides onboarding | Meta's charges plus the provider's fee | Businesses that want help with onboarding |
| Wati, Interakt, AiSensy | Quick start with a no-code dashboard and an API | Monthly subscription plus message charges | Non-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:
| Category | Typical use | How it is charged |
|---|---|---|
| Marketing | Offers, campaigns, re-engagement | Per delivered template message; the highest rate |
| Utility | Order confirmation, delivery update, appointment reminder | Per delivered template message; free when sent inside an open customer service window |
| Authentication | One-time passwords | Per delivered template message; low rate |
| Service | Free-form replies to a customer who messaged you | Free 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
- 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.
- Test with the free test number.Meta gives you a test phone number and lets you message a few verified recipients.
- Verify your business.In Meta Business Manager, complete business verification with your company documents and a live website.
- 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.
- 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.
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:
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):
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.
- Open the template manager.In WhatsApp Manager, go to Message templates and create a new one.
- Name it.Lowercase with underscores, for example
order_confirmation. - Pick the category.Marketing, Utility or Authentication. Choose honestly; Meta can recategorise a template.
- Pick the language.English, Hindi, Tamil and other Indian languages are supported. Each language is a separate version.
- 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.
- 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.
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:
{
"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.
$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_execworks; 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.
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
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.
Run your WhatsApp webhook and order notifications on Domain India hosting with free SSL.
See hosting plans