Order & Shipping Notifications
Overview
Transactional SMS and WhatsApp notifications are the fastest way to keep customers informed about their orders. While marketing emails average a 20% open rate, SMS messages are opened by over 95% of recipients, typically within 3 minutes of delivery.
This guide covers how to send order confirmations, shipping updates, and delivery notifications through the DIDfarm API. You will learn the API calls for each notification type, how to use WhatsApp templates for richer content, and how to track delivery status via webhooks.
Prerequisites
- A DIDfarm account with at least one SMS-enabled or WhatsApp-enabled number. Purchase numbers at /buy.
- An API key from the API Keys tab in your portal.
- Your e-commerce backend (Shopify, WooCommerce, custom) with webhook or event support for order lifecycle events.
- For WhatsApp: approved message templates (submitted via the DIDfarm WhatsApp Business dashboard).
Notification Types
A typical e-commerce order lifecycle includes four key notification touchpoints. Each serves a different purpose and should be sent at the right moment.
| Notification | Trigger | Channel | Example Message |
|---|---|---|---|
| Order Confirmation | Payment captured | SMS / WhatsApp | Order #1042 confirmed. 3 items, total EUR 89.50. |
| Shipping Update | Carrier scan / label created | SMS / WhatsApp | Your order #1042 has shipped! Track: https://trk.co/AB12 |
| Delivery Notification | Carrier delivery confirmation | SMS / WhatsApp | Your order #1042 has been delivered. Enjoy! |
| Return Confirmation | Return received at warehouse | SMS | Return for order #1042 received. Refund in 3-5 days. |
Order Confirmation
Send an order confirmation SMS
Trigger this immediately after payment is captured. Include the order number, item count, and total so the customer has an instant receipt on their phone.
const axios = require('axios');
async function sendOrderConfirmation(order) {
const message = [
`Hi ${order.customerName},`,
`Order #${order.id} confirmed!`,
`${order.itemCount} item${order.itemCount > 1 ? 's' : ''}, total EUR ${order.total.toFixed(2)}.`,
`We'll notify you when it ships.`,
`Questions? Reply to this message.`
].join(' ');
const response = await axios.post(
'https://didfarm.com/api/v1/sms/messages',
{
from: '+31201234567',
to: order.customerPhone,
body: message,
webhook_url: 'https://yourshop.com/webhooks/sms-status',
metadata: {
order_id: order.id,
notification_type: 'order_confirmation'
}
},
{
headers: {
'Authorization': `Bearer ${process.env.DIDFARM_API_KEY}`,
'Content-Type': 'application/json'
}
}
);
return response.data;
}
// Usage (e.g., in your payment webhook handler)
await sendOrderConfirmation({
id: '1042',
customerName: 'Anna',
customerPhone: '+4915112345678',
itemCount: 3,
total: 89.50
});{
"data": {
"message_id": "msg_c4e5f6a7b8d9e0f1",
"from": "+31201234567",
"to": "+4915112345678",
"status": "queued",
"segments": 1,
"metadata": {
"order_id": "1042",
"notification_type": "order_confirmation"
},
"created_at": "2026-04-05T14:22:00Z"
}
}Shipping Update
Send a shipping update with tracking link
Send this when your warehouse creates a shipping label or when the carrier performs the first scan. Always include a tracking link so customers can follow their package in real time.
async function sendShippingUpdate(order, tracking) {
const message = [
`Your order #${order.id} has shipped!`,
`Carrier: ${tracking.carrier}.`,
`Track your package: ${tracking.url}`,
`Estimated delivery: ${tracking.estimatedDate}.`
].join(' ');
return axios.post(
'https://didfarm.com/api/v1/sms/messages',
{
from: '+31201234567',
to: order.customerPhone,
body: message,
webhook_url: 'https://yourshop.com/webhooks/sms-status',
metadata: {
order_id: order.id,
notification_type: 'shipping_update',
tracking_number: tracking.number
}
},
{
headers: {
'Authorization': `Bearer ${process.env.DIDFARM_API_KEY}`,
'Content-Type': 'application/json'
}
}
);
}
// Usage
await sendShippingUpdate(
{ id: '1042', customerPhone: '+4915112345678' },
{
carrier: 'DHL',
number: 'JJD000390007827058',
url: 'https://trk.co/AB12CD',
estimatedDate: 'Apr 8'
}
);import requests
import os
def send_shipping_update(order: dict, tracking: dict) -> dict:
message = (
f"Your order #{order['id']} has shipped! "
f"Carrier: {tracking['carrier']}. "
f"Track your package: {tracking['url']} "
f"Estimated delivery: {tracking['estimated_date']}."
)
response = requests.post(
"https://didfarm.com/api/v1/sms/messages",
json={
"from": "+31201234567",
"to": order["customer_phone"],
"body": message,
"webhook_url": "https://yourshop.com/webhooks/sms-status",
"metadata": {
"order_id": order["id"],
"notification_type": "shipping_update",
"tracking_number": tracking["number"]
}
},
headers={
"Authorization": f"Bearer {os.environ['DIDFARM_API_KEY']}",
"Content-Type": "application/json"
}
)
response.raise_for_status()
return response.json()
# Usage
send_shipping_update(
{"id": "1042", "customer_phone": "+4915112345678"},
{
"carrier": "DHL",
"number": "JJD000390007827058",
"url": "https://trk.co/AB12CD",
"estimated_date": "Apr 8"
}
)trk.yourshop.com) or the full tracking URL to avoid delivery issues.
Delivery Notification
Send a delivery confirmation
Triggered when the carrier confirms delivery. This is also a great moment to request a review or offer a discount on the next order.
async function sendDeliveryNotification(order) {
const message = [
`Great news! Your order #${order.id} has been delivered.`,
`We hope you love it!`,
`Leave a review: ${order.reviewUrl}`
].join(' ');
return axios.post(
'https://didfarm.com/api/v1/sms/messages',
{
from: '+31201234567',
to: order.customerPhone,
body: message,
webhook_url: 'https://yourshop.com/webhooks/sms-status',
metadata: {
order_id: order.id,
notification_type: 'delivery_confirmation'
}
},
{
headers: {
'Authorization': `Bearer ${process.env.DIDFARM_API_KEY}`,
'Content-Type': 'application/json'
}
}
);
}
// Usage
await sendDeliveryNotification({
id: '1042',
customerPhone: '+4915112345678',
reviewUrl: 'https://yourshop.com/review/1042'
});WhatsApp Templates
WhatsApp Business messages require pre-approved templates for outbound (business-initiated) conversations. Templates support dynamic variables, rich media (images, documents), and interactive buttons, making them ideal for shipping notifications with images or PDF receipts.
Template Structure
Each template has a name, language, and numbered variables (1, 2, etc.) that you populate at send time.
| Template Name | Category | Variables | Example Output |
|---|---|---|---|
order_confirmed |
Transactional | 1=name, 2=order_id, 3=total |
Hi Anna, your order #1042 is confirmed. Total: EUR 89.50 |
shipping_update |
Transactional | 1=order_id, 2=carrier, 3=tracking_url |
Order #1042 shipped via DHL. Track: https://trk.co/AB12 |
delivered |
Transactional | 1=order_id, 2=review_url |
Order #1042 delivered! Leave a review: https://... |
return_received |
Transactional | 1=order_id, 2=refund_days |
Return for #1042 received. Refund in 3-5 business days. |
Sending a WhatsApp Template Message
async function sendWhatsAppOrderConfirmation(order) {
const response = await axios.post(
'https://didfarm.com/api/v1/whatsapp/messages',
{
from: '+31201234567',
to: order.customerPhone,
template: 'order_confirmed',
language: 'en',
variables: {
'1': order.customerName,
'2': order.id,
'3': `EUR ${order.total.toFixed(2)}`
},
webhook_url: 'https://yourshop.com/webhooks/whatsapp-status'
},
{
headers: {
'Authorization': `Bearer ${process.env.DIDFARM_API_KEY}`,
'Content-Type': 'application/json'
}
}
);
return response.data;
}async function sendWhatsAppShippingUpdate(order, tracking) {
return axios.post(
'https://didfarm.com/api/v1/whatsapp/messages',
{
from: '+31201234567',
to: order.customerPhone,
template: 'shipping_update',
language: 'en',
variables: {
'1': order.id,
'2': tracking.carrier,
'3': tracking.url
},
header: {
type: 'image',
url: 'https://yourshop.com/images/shipping-banner.jpg'
},
buttons: [
{
type: 'url',
text: 'Track Package',
url: tracking.url
}
],
webhook_url: 'https://yourshop.com/webhooks/whatsapp-status'
},
{
headers: {
'Authorization': `Bearer ${process.env.DIDFARM_API_KEY}`,
'Content-Type': 'application/json'
}
}
);
}Delivery Webhooks
DIDfarm sends real-time delivery status updates to the webhook_url you specify in each message. Use these webhooks to update your order management system, trigger follow-up messages, or alert your support team about failed deliveries.
Webhook Events
| Status | Description | Action |
|---|---|---|
queued |
Message accepted by DIDfarm | Log for audit trail |
sent |
Handed off to carrier | Log for audit trail |
delivered |
Confirmed delivered to handset | Mark notification as delivered in your system |
failed |
Delivery failed (invalid number, unreachable, etc.) | Retry via alternative channel or alert support |
read |
WhatsApp only: message read by recipient | Update engagement metrics |
Webhook Handler Example
const express = require('express');
const app = express();
app.use(express.json());
app.post('/webhooks/sms-status', async (req, res) => {
const { event, data } = req.body;
// Verify webhook signature (recommended)
const signature = req.headers['x-didfarm-signature'];
if (!verifySignature(req.body, signature, process.env.DIDFARM_WEBHOOK_SECRET)) {
return res.status(401).json({ error: 'Invalid signature' });
}
switch (data.status) {
case 'delivered':
console.log(`Message ${data.message_id} delivered to ${data.to}`);
await db.notifications.update({
where: { message_id: data.message_id },
data: {
status: 'delivered',
delivered_at: data.delivered_at
}
});
break;
case 'failed':
console.error(`Message ${data.message_id} failed: ${data.error_message}`);
await db.notifications.update({
where: { message_id: data.message_id },
data: {
status: 'failed',
error_code: data.error_code,
error_message: data.error_message
}
});
// Retry via WhatsApp if SMS failed
if (data.metadata?.notification_type && data.metadata?.order_id) {
await retryViaWhatsApp(data.metadata.order_id, data.metadata.notification_type);
}
break;
default:
console.log(`Status update: ${data.message_id} -> ${data.status}`);
}
res.status(200).json({ received: true });
});
app.listen(3000);{
"event": "message.status_update",
"data": {
"message_id": "msg_c4e5f6a7b8d9e0f1",
"from": "+31201234567",
"to": "+4915112345678",
"status": "delivered",
"delivered_at": "2026-04-05T14:22:04Z",
"metadata": {
"order_id": "1042",
"notification_type": "order_confirmation"
}
},
"timestamp": "2026-04-05T14:22:04Z"
}{
"event": "message.status_update",
"data": {
"message_id": "msg_d5f6a7b8c9e0f1a2",
"from": "+31201234567",
"to": "+3312345678900",
"status": "failed",
"error_code": "30005",
"error_message": "Unknown destination number",
"metadata": {
"order_id": "1043",
"notification_type": "shipping_update"
}
},
"timestamp": "2026-04-05T15:10:12Z"
}X-DIDfarm-Signature header using your webhook secret. This prevents attackers from sending fake delivery confirmations to your endpoint.
Best Practices
Message Content
- Always include the order number so customers can immediately identify which order the message relates to.
- Keep SMS messages under 160 characters (GSM-7 encoding) to stay within a single segment. Multi-segment messages cost more and may arrive out of order on older networks.
- For longer content (receipts, maps, images), use WhatsApp templates instead of SMS.
- Include a clear call to action: a tracking link, review link, or support contact.
Timing
- Send order confirmations immediately after payment capture. Delays create anxiety.
- Send shipping updates when the carrier performs the first scan, not when the label is created (which may be hours before pickup).
- Respect quiet hours: avoid sending non-urgent notifications between 21:00 and 08:00 in the recipient's local timezone.
Channel Strategy
- Use SMS for time-critical notifications (order confirmation, OTP). It works on every phone without app requirements.
- Use WhatsApp for rich content (shipping updates with tracking maps, delivery photos, PDF receipts).
- Implement fallback logic: try WhatsApp first, fall back to SMS if not delivered within 15 seconds. This optimizes cost while ensuring delivery.
- Always ask for opt-in consent before sending transactional SMS. Collect the phone number and messaging preference during checkout.
Reliability
- Store every
message_idreturned by the API. This is your audit trail for delivery tracking. - Use the
metadatafield to attach your internal order ID and notification type to each message. This makes webhook handling straightforward. - Implement idempotency: check if a notification was already sent for an order before sending. Duplicate shipping updates frustrate customers.
- Set up monitoring for failed deliveries. Alert your support team if failure rates exceed 5% in any 1-hour window.
FAQ
How much does each notification cost?
Pricing depends on the destination country and channel. SMS messages are billed per segment (160 chars for GSM-7, 70 chars for Unicode). WhatsApp messages are billed per conversation (24-hour window). Check your Billing tab for current rates per country.
Can I send notifications in multiple languages?
Yes. For SMS, simply include the translated text in the message body. For WhatsApp, submit separate templates for each language (e.g., order_confirmed in English, German, French, Dutch). Use the language parameter to select the correct template at send time.
What happens if a customer replies to a notification?
Inbound replies are delivered to your webhook as message.received events. You can route these to your support team, auto-respond with order status, or feed them into a chatbot. For WhatsApp, customer replies open a free 24-hour conversation window where you can send additional follow-up messages without templates.
How do I handle phone number changes?
If a delivery fails with error code 30003 (unreachable) or 30005 (unknown number), the customer may have changed their number. Flag these orders for manual review and send a follow-up notification via email as a backup.
Is there a bulk sending endpoint?
Yes. Use POST /api/v1/sms/messages/batch to send up to 1,000 messages in a single API call. Each message in the batch can have a different recipient, body, and metadata. Batch messages are queued and processed within seconds.
View the full SMS API reference
All parameters, error codes, webhook events, and rate limits in one place.