DIDfarm
  • Numbers
  • Trunks
  • Messaging
  • Connect
  • Pricing
  • Coverage
  • Help
🇬🇧 EN 🇳🇱 NL 🇩🇪 DE 🇫🇷 FR 🇪🇸 ES 🇧🇷 PT 🇸🇦 AR 🇨🇳 ZH 🇯🇵 JA 🇮🇳 HI
Sign in Get a Number
← Help Center
On this page
Overview Prerequisites Notification Types Order Confirmation Shipping Update Delivery Notification WhatsApp Templates Delivery Webhooks Best Practices FAQ

Order & Shipping Notifications

Messaging · 12 min read Notifications SMS WhatsApp

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.

Why SMS for transactional messages? Speed, reliability, and reach. SMS works on every phone (no app required), arrives in seconds, and has near-universal open rates. Combine with WhatsApp for rich media support in markets where it is dominant.

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).
Tip: For the best customer experience, use a number local to your customer's country. DIDfarm numbers in 70+ countries ensure your messages appear as local traffic, improving delivery rates and trust.

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

1

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.

Node.js — Order Confirmation
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
});
API Response — 201 Created
{
  "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"
  }
}
Character count: The example message above is 136 characters, which fits in a single SMS segment (160 chars for GSM-7 encoding). Keeping messages under 160 characters avoids multi-segment costs.

Shipping Update

2

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.

Node.js — Shipping Update
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'
  }
);
Python — Shipping Update
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"
    }
)
URL shorteners: Some carriers filter messages with shortened URLs from generic shorteners (bit.ly, tinyurl). Use your own branded short domain (e.g., trk.yourshop.com) or the full tracking URL to avoid delivery issues.

Delivery Notification

3

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.

Node.js — Delivery Notification
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'
});
Conversion tip: Including a review link in delivery notifications can increase review rates by 3-5x compared to email-only review requests. Keep the SMS concise and link to a mobile-optimized review page.

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

Node.js — WhatsApp Order Confirmation
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;
}
Node.js — WhatsApp Shipping Update with Image
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'
      }
    }
  );
}
Template approval: New WhatsApp templates require Meta approval, which typically takes 24–48 hours. Submit templates well before you plan to use them in production. Transactional templates have higher approval rates than marketing templates.

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

Node.js — Express Webhook Handler
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);
Webhook Payload — Delivered
{
  "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"
}
Webhook Payload — Failed
{
  "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"
}
Webhook security: Always verify the 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_id returned by the API. This is your audit trail for delivery tracking.
  • Use the metadata field 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.
Production checklist: Opt-in consent collected, order number in every message, tracking links use branded domain, webhook handler verified, quiet hours respected, fallback channel configured, idempotency checks in place.

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.

SMS API Reference →
© 2026 DIDfarm · didfarm.com
About Blog Partners Coverage API Docs Status Privacy Terms Cookies Help

We use essential cookies to make DIDfarm work. With your consent, we also use analytics cookies to improve our service. Cookie Policy