Expertise technical

Using Delivery Report (DLR) webhooks correctly: architecture and best practices

Webhook delivery report dlr best practices: technical guide with code examples for developers in Morocco.

Using Delivery Report (DLR) webhooks correctly: architecture and best practices
Table of Contents
  1. When submitting an SMS via the API, the status `HTTP 200 OK` absolutely does not mean that the client received the message. It simply means that the EnvoiSMS platform has accepted your request.
  2. Anatomy of a typical DLR payload
  3. Where and how to store this data for analysis
  4. Build an in-house deliverability dashboard
  5. Automatic alert in the event of a drop in the delivery rate

When submitting an SMS via the API, the status `HTTP 200 OK` absolutely does not mean that the client received the message. It simply means that the EnvoiSMS platform has accepted your request.

To find out what's happening "on the ground" (was the SMS blocked by IAM? Is the number out of service? Is the phone turned off?), you need to listen to the network. This is the critical role of the Delivery Report (DLR).

Rather than polling the platform in a loop to ask for status (Polling) – a cumbersome and inefficient practice – the modern method consists of using a Webhook. Our server "pushes" the result to yours as soon as the Moroccan operator responds to us. Here's how to architect this.

Anatomy of a typical DLR payload

When the operator (IAM, Orange, inwi) updates the status of the message, our API triggers an HTTP POST request to the URL you have configured in your customer area.

The payload (request body) is in this strict JSON format:

json
{
  "message_id": "msg_5f8b3c9a2d1e4",
  "phone_number": "+212600000000",
  "status": "DELIVERED",
  "operator": "INWI",
  "error_code": null,
  "timestamp": "2026-06-25T14:32:01Z",
  "price_mad": 0.65,
  "segments": 1
}

The possible statuses are generally: PENDING (Queued), DELIVERED (Delivered to the terminal), REJECTED (Rejected by the operator, often a problem of Sender ID blacklisted) or FAILED (Delivery failure, such as a number invalid).

Where and how to store this data for analysis

The biggest technical mistake is tying webhook reception directly to a user interface or heavy computation. The webhook endpoint must respond to our platform with an HTTP 200 promptly (within the configured timeout), otherwise our system will consider that you are down and will attempt to restart the webhook (Retry).

Recommended architecture:

  1. The webhook receives the JSON.
  2. It validates the security signature (HMAC).
  3. It inserts the raw data asynchronously into a read-optimized SQL table (or pushes it into a RabbitMQ/Kafka queue).
  4. It responds HTTP 200 OK immediately.

Minimum table schema (MySQL / PostgreSQL):```sql
CREATE TABLE sms_delivery_logs (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
message_id VARCHAR(64) UNIQUE NOT NULL,
campaign_id INT NULL,
phone_number VARCHAR(20) NOT NULL,
status VARCHAR(20) NOT NULL, -- DELIVERED, FAILED, etc.
error_code VARCHAR(10) NULL,
operator VARCHAR(20) NULL,
delivered_at DATETIME NULL,
INDEX idx_status (status),
INDEX idx_campaign (campaign_id)
);

bash

Build an in-house deliverability dashboard

Once this data is stored in real time, you no longer need to wait for the end of the campaign to react. You can create an internal dashboard (Grafana, Metabase or a tailor-made admin panel) that monitors these 3 vital metrics:

  1. The Delivery Ratio: (Nb Delivered / Total Sent) * 100. If it falls below 90%, immediate action is required.
  2. Delivery Time (Latency): The time difference between the sending date and the timestamp of the DELIVERED status. If it exceeds 30 seconds for an OTP, the customer has surely already abandoned their transaction.
  3. Breakdown by Operator: If 99% of Orange sends are DELIVERED but 80% of IAM sends are REJECTED, you have diagnosed a whitelisting problem at a glance.

Automatic alert in the event of a drop in the delivery rate

Rather than looking at the dashboard all day, let the data alert you. Configure a script that runs every 15 minutes during your mass mailings.

If it detects an unusual peak in FAILED or REJECTED statuses (e.g.: +20% failures over the last 5 minutes), the script triggers a Slack/Teams alert or sends an emergency email to DevOps and the Marketing manager. This allows you to immediately stop a faulty campaign before burning your entire SMS budget in the void.

Why choose EnvoiSMS for your business?

Carrier Delivery

Local routes to IAM, Orange and Inwi, with automatic failover between routes and delivery status sent by webhook.

Cost Optimization

WhatsApp Business API from 0.65 MAD per message with optimal ROI.

Sovereign Data (CNDP)

Full compliance with Moroccan personal data protection regulations (CNDP).

What is the routing latency on the IAM, Inwi and Orange networks?
On our local routes to Maroc Telecom (IAM), Orange and inwi, the average delivery latency is between 2 and 4 seconds for transactional flows.
How does the platform manage the format of Moroccan numbers?
EnvoiSMS automatically normalizes the numbers entered (06..., 07..., 00212...) to the E.164 standard (+212) to avoid any delivery failure.

Suggested Articles

SMS Formatting in Morocco: Line Breaks, GSM-7 vs UCS-2 Encoding and Cost Optimization
technical

SMS Formatting in Morocco: Line Breaks, GSM-7 vs UCS-2 Encoding and Cost Optimization

WhatsApp Business Formatting in Morocco: Enriched Text, Emojis and Interactive Buttons
technical

WhatsApp Business Formatting in Morocco: Enriched Text, Emojis and Interactive Buttons

One-Tap Autofill & 1-Click WhatsApp OTP Authentication in Morocco
technical

One-Tap Autofill & 1-Click WhatsApp OTP Authentication in Morocco