WhatsApp Order Notification API: Events to Messages
"Where is my order?" is the question every online store answers more than any other. Customers ignore order emails, then message you on WhatsApp anyway. Sending the update to WhatsApp first is the obvious fix, and a WhatsApp order notification API makes it automatic: your store fires an event, a message goes out, and the customer has a tracking link in the chat they actually read.
The hard part is not the API call. It is deciding which events deserve a message, writing templates Meta keeps in the cheaper utility category, wiring events so customers never get duplicates, and handling the replies each update triggers. This guide walks through all four, with code, and ends with when a store's existing WhatsApp number is enough.
Map order events to messages
Not every status change deserves a WhatsApp message. Each one costs money on the official platform, and every unwanted message is a chance for the customer to block you, which drags down your number's quality rating. Pick the moments the customer actually cares about.
| Event | Typical trigger | Message | Button |
|---|---|---|---|
| Order placed | Store order-created webhook | Order number, total, delivery estimate | URL: View order |
| Cash on delivery check | COD order created | Ask the customer to confirm before you ship | Quick replies: Confirm, Cancel |
| Shipped | Fulfillment created with tracking | Carrier and tracking link | URL: Track package |
| Out for delivery | Carrier webhook | Heads-up, today's window | None |
| Delivery problem | Carrier exception | What happened, what happens next | URL: Update address |
| Delivered | Carrier webhook | Confirmation, "reply here if anything's wrong" | None |
| Refund issued | Refund created | Amount and timing | None |
Most stores do well with placed, shipped and delivered, plus exceptions. The cash-on-delivery check is worth it in markets where COD is common, since a confirmed order is less likely to be refused at the door.
Write templates that stay in the utility category
Order updates sent outside a 24-hour customer service window must be approved templates. They qualify as utility when they are about the customer's own order and contain nothing promotional. Meta's categorization guidance gives "Your package from order {{order_number}} is on its way" as a utility example, and says an order update with a promo mixed in becomes marketing.
Template: order_shipped (utility)
Header: Your order is on its way
Body: Hi {{1}}, order {{2}} has shipped with {{3}}. Expected delivery: {{4}}.
Reply to this message if you need to change anything.
Button: URL "Track package" https://track.example.com/{{1}}
Rules that keep you out of trouble:
- No cross-sell, ever. "Use code SAVE10 on your next order" turns the template into marketing. Meta normally gives one day's notice, then changes the category; the template stays approved but bills at the marketing rate.
- Watch for the category webhook. Subscribe to
template_category_updateso you hear about recategorization in code, not on your invoice. - Dynamic tracking links. A URL button can take one variable, appended to the end of the URL. Templates allow up to two URL buttons, and Meta asks you to percent-encode special characters in the value.
Our library of WhatsApp template examples has more order wording to adapt.
Wire store events to sends
The shape is the same on any platform: your store emits a webhook, your server turns it into a job, a worker sends the template, and status webhooks report back.
- Receive. Accept the store webhook (Shopify, WooCommerce or your own backend) and verify its signature.
- Deduplicate. Stores retry webhooks. Key each job on order id plus event, such as
1042:shipped, and skip keys you have already processed. - Queue. Return 200 to the store at once and send from a worker, so a slow WhatsApp call never makes the store retry.
- Send. Call Cloud API with the right template and parameters.
- Record. Store the WhatsApp message id on the order, then update it from status webhooks.
const GRAPH = "https://graph.facebook.com/v23.0"; // use the current Graph API version
const TEMPLATES = {
shipped: (o) => ({
name: "order_shipped",
body: [o.firstName, o.number, o.carrier, o.eta],
url: o.trackingCode,
}),
delivered: (o) => ({ name: "order_delivered", body: [o.firstName, o.number] }),
};
export async function notify(event, order) {
const t = TEMPLATES[event]?.(order);
if (!t || !order.whatsappOptIn) return null;
const components = [
{ type: "body", parameters: t.body.map((text) => ({ type: "text", text })) },
];
if (t.url) {
components.push({
type: "button", sub_type: "url", index: "0",
parameters: [{ type: "text", text: encodeURIComponent(t.url) }],
});
}
const res = await fetch(`${GRAPH}/${process.env.PHONE_NUMBER_ID}/messages`, {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.WHATSAPP_TOKEN}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
messaging_product: "whatsapp",
to: order.phone,
type: "template",
template: { name: t.name, language: { code: order.locale }, components },
}),
});
const data = await res.json();
if (!res.ok) throw new Error(data.error?.message ?? "send failed");
return data.messages[0].id; // save on the order
}
On WooCommerce the trigger is the woocommerce_order_status_changed hook; our WooCommerce WhatsApp notifications tutorial has the PHP side. Shopify users can start with WhatsApp for Shopify.
Expire updates that go stale
Utility templates default to a 30-day time-to-live. An "out for delivery today" message delivered three days later is wrong. Per Meta's time-to-live docs, utility templates accept a custom TTL from 30 seconds to 12 hours. Give time-sensitive templates a short one and leave confirmations on the default.
Handle the replies order updates trigger
Every update invites a reply, and a reply opens a 24-hour window in which you can answer with free-form messages. The replies cluster into a few types:
- Status questions. "When will it come?" Your bot or your agent can answer from the order record.
- Changes. Address corrections, delivery instructions, cancellations. These need a person with access to the order, fast, before the parcel leaves.
- Problems. Damaged, wrong item, missing item. These need a person, the order and the photos in one place.
Your webhook receives these as ordinary inbound messages. The guide to receiving WhatsApp messages by API walks through the payload. The design question is where they land. A webhook that writes to a database nobody watches is worse than email. Route replies to whoever handles support, with the order attached.
What order updates cost
Utility templates are billed per delivered message at your customer's market rate, and utility volume tiers lower the rate as monthly volume grows. As of October 2026, per Meta's pricing page, two changes affect stores:
- Utility inside an open window is now billed. From July 1, 2025, a utility template sent while the customer service window was open was free. From October 1, 2026, it is charged.
- Service replies are free only up to a point. Each business number gets 1,000 free service messages a month, then service messages are billed per message.
So a busy store now pays for the update, and for the conversation it causes once past the free tier. Sending fewer, better updates is the cheapest optimization there is. Our explainer on utility message pricing breaks down the category.
Where Tenashi fits
Plenty of smaller stores already run on one WhatsApp number: customers order in chat, ask questions in chat, and send delivery photos in chat. For them, Tenashi's API can send the order update from that same number. Your store webhook calls POST /api/v1/messages with the customer's phone and a message with the tracking link, and the update appears in the shared inbox. When the customer replies "can you deliver after 6?", whoever picks it up sees the order update, the history and the CRM record together.
The honest limits: no templates or buttons (text, media and quoted replies only), sends are paced at one every 4 to 12 seconds per number, and the API opens at most 50 new chats per number per day. That suits a store doing tens of orders a day with customers who already chat with it. A store shipping thousands of orders a day should use Cloud API utility templates, as covered in the complete guide to the WhatsApp API, and keep a shared inbox for the replies.
Read the API docs · See every feature
FAQ
Are WhatsApp order updates utility or marketing messages?
Utility, if they are about the customer's own order and contain no promotion. Order confirmations, shipping updates, delivery notices and refund confirmations all qualify. Add a discount code, a product recommendation or a review request with promotional content and Meta will treat the template as marketing, which costs more per message.
Do I need customer opt-in to send order notifications on WhatsApp?
Yes. An order confirmation is still a message your business starts, so it needs the customer's agreement to hear from you on WhatsApp. Put a WhatsApp updates checkbox next to the phone field at checkout, save the consent on the order record, and stop messaging anyone who replies STOP.
How do I add a tracking link to a WhatsApp template?
Use a URL button with a dynamic suffix, such as a base URL with one variable at the end, and pass the tracking code as the button parameter when you send. A template can have up to two URL buttons. Percent-encode special characters in the value, or the message may fail validation.
How do I stop customers getting duplicate order messages?
Deduplicate before sending. Store webhooks are retried, so key each send on order id plus event and skip keys you have already processed. Record the WhatsApp message id on the order. If your send call itself retries, check whether the first attempt succeeded before sending again.
Which order events are worth a WhatsApp message?
Order placed, shipped with tracking, and delivered cover most stores, plus delivery exceptions and refunds. Add a cash-on-delivery confirmation where COD is common. Skip internal statuses like "packed" or "label created". Each extra message costs money and gives customers another reason to mute or block your number.
Order updates are a send problem and a reply problem. If your store's customers already message one number, see how Tenashi's shared inbox handles both.