SMS Callbacks

Overview

In this tutorial, you will learn how callbacks help analyze the delivery status of your SMS & MMS traffic. Webhooks make it possible to track the delivery status of your outgoing and incoming messages. For every single SMS & MMS message you send and receive, Plivo sends a status update to your URL configured as a callback. You can read and store the information on your server for delivery status analysis.

Get started with Webhooks

Webhooks are “user-defined HTTP callbacks.” They are event-based and operate based on the concept of “event reaction.” They can be integrated into web services without adding new infrastructure.

The webhooks you integrate with Plivo are usually triggered by incoming messages or incoming calls. During these events, Plivo makes an HTTP request (POST or GET) to the endpoint URL configured for the webhook. To handle a webhook, you have to create a listener (web app) that can accept these HTTP requests from Plivo.

Webhooks are helpful to create instant & real-time notifications.

SMS callbacks

Webhooks for Outbound SMS

Here’s how to use Plivo APIs to send SMS messages from your web application with a callback URL. We’ll start by describing some prerequisite steps you should take before diving into the code.

  • Plivo Auth ID and Auth Token: You will find your Plivo Auth ID and Auth Token on the home screen of your Plivo Console. Click here to sign-up for a Plivo account if you haven’t already.

credentials

  • Plivo phone number: You must have an SMS-enabled Plivo phone number to send messages to the US and Canada. You can purchase numbers from the Numbers section of your Plivo Console. It is also possible to purchase numbers using the Numbers API.

Buy New Number

  • Webhook: For Plivo to invoke your webhook and send HTTP requests, you have to configure the URL parameter with your webhook URL and set the method as either POST or GET. Message status-related callbacks will be sent to this URL.

Code

1
2
3
4
5
6
7
8
9
10
11
12
import plivo

client = plivo.RestClient("auth_id", "auth_token")
response = client.messages.create(
    src='+15671234567',
    dst='+14152223333',
    text='Hello, this is a sample text',
    url='http://foo.com/sms_status/',
)
print(response)
# prints only the message_uuid
print(response.message_uuid)
1
2
3
4
5
6
7
8
9
10
11
12
13
require "plivo"
include Plivo

api = RestClient.new("auth_id", "auth_token")
response = api.messages.create(
  '+15671234567', #from
  ["+14151112222"], #to
  "Hello, this is a sample text", #text
  { url: "http://foo.com/sms_status/" },
)
puts response
#Prints only the message_uuid
puts response.message_uuid
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
var plivo = require('plivo');

(function main() {
    'use strict';
    var client = new plivo.Client("auth_id", "auth_token");
    client.messages.create(
        "plivo_src_number", //src
        "+the_destination_number", // dst
        "Hello, this is a sample text from Plivo", // text
        {
            method: "GET",
            url: "http://foo.com/sms_status/"
        },
    ).then(function (response) {
        console.log(response);
        //Prints only the message_uuid
        console.log(response.messageUuid);
    }, );
})();
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?php
require 'vendor/autoload.php';
use Plivo\RestClient;

$client = new RestClient("auth_id", "auth_token");
$response = $client->messages->create(
  '+15671234567', #src
  ['+14152223333'], #dst
  'Hello, this is a sample text', #text
  ["url"=>"http://foo.com/sms_status/"],
);
print_r($response);
// Prints only the message_uuid
print_r($response->getmessageUuid(0));
?>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
import java.io.IOException;
import java.net.URL;
import java.util.Collections;

import com.plivo.api.Plivo;
import com.plivo.api.exceptions.PlivoRestException;
import com.plivo.api.models.message.Message;
import com.plivo.api.models.message.MessageCreateResponse;

class MessageCreate {
    public static void main(String[] args) {
        Plivo.init("auth_id", "auth_token");
        try {
            MessageCreateResponse response = Message.creator("plivo_src_number", Collections.singletonList("+14151112222"),
                    "Hello, this is test message").url(new URL("http://foo.com/sms_status/"))
                    .create();
            System.out.println(response);
            // Prints only the message_uuid
            System.out.println(response.getMessageUuid());
        }

        catch (PlivoRestException | IOException e) {
            e.printStackTrace();
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
package main

import "fmt"
import "github.com/plivo/plivo-go"

func main() {
	client, err := plivo.NewClient("auth_id", "auth_token", &plivo.ClientOptions{})
	if err != nil {
		panic(err)
	}
	response, err := client.Messages.Create(
		plivo.MessageCreateParams{
			Src:  "plivo_src_number",
			Dst:  "+14151112222",
			Text: "Hello, this is a sample text",
			URL:  "http://foo.com/sms_status/",
		},
	)
	if err != nil {
		panic(err)
	}
	fmt.Printf("Response: %#v\n", response)
	// Prints only the message_uuid
	fmt.Printf("Response: %#v\n", response.MessageUUID)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
using System;
using System.Collections.Generic;
using Plivo;

namespace PlivoExamples
{
    internal class Program
    {
        public static void Main(string[] args)
        {
            var api = new PlivoApi("auth_id", "auth_token");
            var response = api.Message.Create(
                src: "plivo_src_number",
                dst: new List<String> { "+14151112222" },
                text: "Hello, this is sample text",
                url: "http://foo.com/sms_status/"
                );
            Console.WriteLine(response);
            // Prints the message_uuid
            Console.WriteLine(response.MessageUuid[0]);
        }
    }
}
1
2
3
4
curl -i --user auth_id:auth_token \
-H "Content-Type: application/json" \
-d '{"src": "plivo_src_number","dst": "+14152223333", "text": "Hello, this is a sample text.", "url":"http://webhook.site/c7a0b423-8d1f-46fe-9a81-1dfa8254bdaf"}' \
https://api.plivo.com/v1/Account/{auth_id}/Message/
Note:
  • Replace the placeholders auth_id & auth_token with your credentials from Plivo Console
  • Replace the placeholder plivo_source_number with the Phone number which you have purchased and the_destination_number with the phone number you will be sending SMS text messages to
  • Both plivo_source_number and the_destination_number should be in E.164 format, for example +15671234567.
  • If you are using a Plivo trial account for this example, you can only send SMS to phone numbers that have been verified with Plivo. Phone numbers can be verified through the Sandbox Numbers page.

Webhooks for Inbound SMS

Webhooks can be used with Plivo numbers to receive callbacks for incoming messages. When a Plivo phone number (two-way and SMS-enabled) receives a message, Plivo will send an HTTP request callback (either POST or GET based on the method set for the webhook) to the URL specified in the application of the phone number.

In the callback, you would have all the information related to the inbound message either in the POST request’s body or the GET request’s query parameters. You can check here for the list of parameters that are sent by Plivo.

You can check the receive SMS usage guide for more information about how to receive SMS on a two-way SMS enabled Plivo phone number.

Handle callbacks in your web app

To handle callbacks in your app, your endpoint should:

  • Capture HTTP requests
  • Respond to the requests

When Plivo sends the HTTP request callbacks to the webhook during an event, you should capture the request (POST or GET based on the type you have defined for the URL), and respond with a 200 OK response. To process the callback, you can store the data to your database.

Note: Plivo automatically retries webhooks for 10 minutes (exponentially, i.e at 60 secs, 120 secs, 240 secs and 480secs) if HTTP 200 status code is not returned.

Test and validate

To understand more about webhooks and how to handle callbacks, Let’s take a look at an example. Typically, you would include a URL that points to your web app, but we will use Requestbin so we can check and debug the callbacks sent to your webhook by Plivo.

  • Create a new bin in Requestbin
  • Replace the ‘url’ placeholder with the URL of the new bin that’s created
  • Run the script. You will receive the SMS message to the phone number defined in DST, you would also see the callback request in the Requestbin similar to the below screenshots for different callback events such as queued, sent & delivered.

Queued Status Callback

Queued status event

Sent Status Callback

Sent status event

Delivered Status Callback

Delivered status event

Note:
  • Handling callbacks for incoming messages work in the same manner as outbound messages.
  • You will also receive other statuses such as undelivered or failed, and some messages may remain in the sent state. For more information about message status, please read our different SMS states support article.

Validating callbacks

To avoid any spoof attacks, you can validate the callbacks that your server URL receives. All requests made by Plivo to your server URLs consist of an X-Plivo-Signature-V2, X-Plivo-Signature-Ma-V2, and X-Plivo-Signature-V2-Nonce HTTP headers. You can use the same to validate that the request is from Plivo.

You can read more about signature validation in this guide

Conversion feedback to Plivo

From the message status callbacks, you can store the data in your database and process it as per your requirement and you can choose to provide the same to Plivo as Message Delivery Feedback.

Plivo’s Conversion Feedback API enables you to update Plivo on conversions for your critical 2FA/OTP SMS messages. This feedback plays an important role in ensuring consistently high delivery rates for your 2FA/OTP SMS messages to countries where carrier networks are generally unstable. Plivo’s dynamic routing engine ensures that your messages are delivered over the best performing carrier route to the destination mobile network at any given point in time.

You can check the conversion feedback guide for more information on integrating the API into your app.