Delivery Report

Delivery reports are a way to track if your messages are getting sent properly.


What is a delivery report?

After receiving a message, the handset responds to the operator with Delivery Report (DLR) so that Messente knows if and when the message was delivered.

Each time you send a message, Messente generates an ID that is unique to this particular message.

There are 2 ways you can get the status of the sent messages.

  1. Add a callback URL to your message. Messente will make a POST request with the relevant information to the callback any time the message status changes (suggested option).
  2. You can request a delivery report by manually making a call to the API.

The easiest way to use Omnichannel API is with our official libraries. They will take care of authentication, request validation and response handling automatically.

Option 1. Add a callback URL to the message

Messente will make a HTTP POST request to the URL in dlr_url property for every status update.

Callback URL

The provided Delivery report URL (drl_url) endpoint should respond with a HTTP status code within the range 200-399, otherwise the DRL will be considered undelivered.

To validate the callback request, you can validate it using X-Messente-Signature header.

# 1. Get a temporary WebHook URL from https://webhook.site.
# Leave the website open. This is where you'll see your incoming delivery reports.

# 2. Edit the previous code example by adding the delivery URL to the request.
omnimessage = Omnimessage(
    messages=tuple([sms]), to="<recipient_phone_number>", dlr_url="<webhook_url>"
)

# 3. Send an SMS with the script and monitor the incoming requests on the webhook's website.
// 1. Get a temporary WebHook URL from https://webhook.site.
// Leave the website open. This is where you'll see your incoming delivery reports.

// 2. Edit the previous code example by adding the delivery URL to the request.
const omnimessage = MessenteApi.Omnimessage.constructFromObject({
  messages: [sms],
  to: '<recipient_phone_number>',
  dlr_url: '<webhook_url>',
});

// 3. Send an SMS with the script and monitor the incoming requests on the webhook's website.
<?php
// 1. Get a temporary WebHook URL from https://webhook.site.
// Leave the website open. This is where you'll see your incoming delivery reports.

// 2. Edit the previous code example by adding the delivery URL to the request.
$omnimessage = new Omnimessage([
  'to' => '<recipient_phone_number>',
  'dlrUrl' => '<webhook_url>',
]);

$sms = new SMS(
  [
      'text' => 'hello sms',
      'sender' => '<sender name (optional)>',
  ]
);

$omnimessage->setMessages([$sms]);

// 3. Send an SMS with the script and monitor the incoming requests on the webhook's website.
?>
// 1. Get a temporary WebHook URL from https://webhook.site.
// Leave the website open. This is where you'll see your incoming delivery reports.

// 2. Edit the previous code example by adding the delivery URL to the request.
omnimessage.setDlrUrl("<webhook_url>");

// 3. Send an SMS with the script and monitor the incoming requests on the webhook's website.
# 1. Get a temporary WebHook URL from https://webhook.site.
# Leave the website open. This is where you'll see your incoming delivery reports.

# 2. Edit the previous code example by adding the delivery URL to the request.
omnimessage.dlr_url = '<webhook_url>'

# 3. Send an SMS with the script and monitor the incoming requests on the webhook's website.
// 1. Get a temporary WebHook URL from https://webhook.site.
// Leave the website open. This is where you'll see your incoming delivery reports.

// 2. Edit the previous code example by adding the delivery URL to the request.
var omnimessage = new Omnimessage(
    to: "<recipient_phone_number>",
    messages: messages,
    dlrUrl: "<webhook_url>"
);

// 3. Send an SMS with the script and monitor the incoming requests on the webhook's website.
# 1. Get a temporary WebHook URL from https://webhook.site.
# Leave the website open. This is where you'll see your incoming delivery reports.

# 2. Edit the previous code example by adding the delivery URL to the request.
curl -X POST \
  'https://api.messente.com/v1/omnimessage' \
  -u YOUR_MESSENTE_API_USERNAME:YOUR_MESSENTE_API_PASSWORD \
  -H 'Content-Type: application/json' \
  -d '{
    "to": "<recipient_phone_number>",
    "messages": [
      {
        "channel": "sms",
        "sender": "<sender name (optional)>",
        "text": "hello sms",
        "dlr_url": "<webhook_url>"
      }
    ]
  }'


# 3. Send an SMS with the script and monitor the incoming requests on the webhook's website.

Report structure in callback request

Example of a successful message

{
    "status": "DELIVRD",
    "sender": "MySender",
    "err": 0,
    "message_id": "3e28ec48-d620-4191-a96e-d91ba8ecc949",
    "to": "+3725555555",
    "channel": "sms",
    "error": null,
    "omnimessage_id": "d7248cda-6c1a-4436-acf5-aaf249bb67d3",
    "timestamp": "2020-02-04T08:09:42.389630",
    "price_info": {
      "part_price": "0.1",
      "parts_count": 2,
      "total_price": "0.2"
    }
}

Option 2. Make an API call

For most cases using dlr_url is a more suitable approach. Sometimes it's useful (usually for debugging purposes) to request the status of a specific message. In that case you can make a request to the API with the Omnimessage ID you need status of.

# pip install messente-api

from pprint import pprint
from messente_api import ApiClient, Configuration, DeliveryReportApi
from messente_api.rest import ApiException

configuration = Configuration()
configuration.username = "YOUR_MESSENTE_API_USERNAME"
configuration.password = "YOUR_MESSENTE_API_PASSWORD"

api_instance = DeliveryReportApi(ApiClient(configuration))
omnimessage_id = "YOUR_OMNIMESSAGE_ID"

try:
    api_response = api_instance.retrieve_delivery_report(omnimessage_id)
    pprint(api_response)
except ApiException as e:
    print("Exception when calling retrieve_delivery_report: %s\n" % e)
// npm i messente_api

const MessenteApi = require('messente_api');

const defaultClient = MessenteApi.ApiClient.instance;
const basicAuth = defaultClient.authentications['basicAuth'];
basicAuth.username = 'YOUR_MESSENTE_API_USERNAME';
basicAuth.password = 'YOUR_MESSENTE_API_PASSWORD';

const api = new MessenteApi.DeliveryReportApi();
const omnimessage_id = 'YOUR_OMNIMESSAGE_ID';

api.retrieveDeliveryReport(omnimessage_id, (error, data) => {
  if (error) {
    console.error(error);
  } else {
    console.log('API called successfully. Returned data: ', data);
  }
});
<?php

// composer require messente/messente-api-php

require_once __DIR__.'/vendor/autoload.php';

use Messente\Api\Api\DeliveryReportApi;
use Messente\Api\Configuration;

$config = Configuration::getDefaultConfiguration()
    ->setUsername('YOUR_MESSENTE_API_USERNAME')
    ->setPassword('YOUR_MESSENTE_API_PASSWORD');

$apiInstance = new DeliveryReportApi(
    new GuzzleHttp\Client(),
    $config
);

$omnimessage_id = 'YOUR_OMNIMESSAGE_ID';

try {
    $result = $apiInstance->retrieveDeliveryReport($omnimessage_id);
    print_r($result);
} catch (Exception $e) {
    echo 'Exception when retrieving delivery report: ', $e->getMessage(), PHP_EOL;
}
import com.messente.ApiClient;
import com.messente.ApiException;
import com.messente.api.DeliveryReportApi;
import com.messente.api.DeliveryReportResponse;
import com.messente.auth.HttpBasicAuth;

import java.util.Arrays;

// repositories { jcenter() }
// dependencies { implementation 'com.messente.api:messente-api' }

public class Main {
    public static void main(String[] args) {
        ApiClient apiClient = new ApiClient();

        HttpBasicAuth basicAuth = (HttpBasicAuth) apiClient.getAuthentication("basicAuth");
        basicAuth.setUsername("YOUR_MESSENTE_API_USERNAME");
        basicAuth.setPassword("YOUR_MESSENTE_API_PASSWORD");

        String omnimessageId = "YOUR_OMNIMESSAGE_ID";

        DeliveryReportApi apiInstance = new DeliveryReportApi(apiClient);

        try {
            DeliveryReportResponse result = apiInstance
                    .retrieveDeliveryReport(omnimessageId);
            System.out.println(result);
        } catch (ApiException e) {
            System.err.println(e.getResponseBody());
        }
    }
}
# gem install messente_api

require 'messente_api'

MessenteApi.configure do |config|
  config.username = 'YOUR_MESSENTE_API_USERNAME'
  config.password = 'YOUR_MESSENTE_API_PASSWORD'
end

api_instance = MessenteApi::DeliveryReportApi.new
ominmessage_id = 'YOUR_OMNIMESSAGE_ID'

begin
  result = api_instance.retrieve_delivery_report(ominmessage_id)
  p result
rescue MessenteApi::ApiError => e
  puts "Exception when calling retrieve_delivery_report: #{e}"
end
// PM > Install-Package com.Messente.Api

using System;
using System.Diagnostics;
using com.Messente.Api.Api;
using com.Messente.Api.Client;

namespace Example
{
    public class SendOmniMessageExample
    {
        public static void Main()
        {
            Configuration conf = new Configuration();
            conf.Username = "YOUR_MESSENTE_API_USERNAME";
            conf.Password = "YOUR_MESSENTE_API_PASSWORD";
            var apiInstance = new DeliveryReportApi(conf);
            var omnimessageId = "YOUR_OMNIMESSAGE_ID";

            try
            {
                var result = apiInstance.RetrieveDeliveryReport(omnimessageId);
                Debug.WriteLine(result.ToJson());
            }
            catch (Exception e)
            {
                Debug.Print("Exception when retrieving dlr" + e.Message);
            }
        }
    }
}
curl https://api.messente.com/v1/omnimessage/YOUR_OMNIMESSAGE_ID/status \
  -u MESSENTE_API_USERNAME:MESSENTE_API_PASSWORD

Requesting regular updates for every message via API calls is very resource heavy and costly approach. Before implementing please consider using Option 1.

Report structure in API response

Example of a successful message

{
  "omnimessage_id": "6e29aeef-f43d-4dc0-bd12-195374c845fa",
  "statuses": [
    {
      "status": "DELIVRD",
      "sender": "MySender",
      "err": 0,
      "message_id": "3e28ec48-d620-4191-a96e-d91ba8ecc949",
      "to": "+3725555555",
      "channel": "sms",
      "error": null,
      "omnimessage_id": "d7248cda-6c1a-4436-acf5-aaf249bb67d3",
      "timestamp": "2020-02-04T08:09:42.389630",
      "price_info": {
        "part_price": "0.1",
        "parts_count": 2,
        "total_price": "0.2"
      }
    }
  ],
  "to": "RECIPIENT"
}

Difference between omnimessage_id and message_id

message_id is a unique identifier for a single message and omnimessage_id groups messages that are sent with multi-channel fallback.

Although Omnichannel API can easily be used to send single messages we've built it with multi-channel capabilities in mind. To allow easy migration between the two we add omnimessage_id to every message.


List of Message Statuses

There can be various reasons why a message wasn't delivered or hasn't been delivered yet.

Status Constant Description
ACK Operator has accepted the message for delivery
DELIVRD The message has been successfully delivered to the handset
UNDELIV Unable to deliver message to the handset
FAILED Failed to deliver message to the handset
UNKNOWN Unknown status has been reported by the operator
ACCEPTD Message has been accepted for the delivery and is in the operators's delivery queue
REJECTD The message was rejected by the operator
EXPIRED Delivery of the message expired
NACK The message delivery has been rejected
SEEN The message has been seen by the recipient