SMS Callbacks

    You can create analytics on your SMS and MMS traffic by using event-based webhooks — user-defined HTTP callbacks — to track the delivery status of outgoing and incoming messages.

    For every SMS and MMS message you send and receive, Plivo sends a status update to a URL you configure as a callback. You can store the information on your server for delivery status analysis.SMS callbacksThe webhooks you integrate with Plivo are triggered by incoming messages or calls. Upon one of these events, Plivo makes an HTTP request (POST or GET) to an endpoint URL you’ve configured for the webhook. In the callback, you can send all the information related to the message either in the POST request’s body or the GET request’s query parameters. To handle a webhook, you must create a listener (web app) that can accept these HTTP requests from Plivo.

    Webhooks for outbound SMS

    Here’s how to use Plivo APIs to send SMS messages from your web application and include a callback URL. Before you get started, you must buy an SMS-enabled Plivo phone number to send messages to the US and Canada. You can purchase numbers from Phone Numbers > Buy Number section of the Plivo console, or by using the Numbers API.

    Buy a New Plivo Number

    For Plivo to invoke your webhook and send HTTP requests, you must configure the URL parameter with your webhook URL and set the method as either POST or GET, then specify this URL for message status-related callbacks.

    See the send SMS usage guide for more information about how to send SMS messages on a two-way SMS-enabled Plivo phone number.

    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='https://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: "https://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(
            "+14151234567", //src
            "+14157654321", // dst
            "Hello, this is a sample text from Plivo", // text
            {
                method: "GET",
                url: "https://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"=>"https://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("+14151234567", Collections.singletonList("+14151112222"),
                        "Hello, this is test message").url(new URL("https://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
    26
    27
    28
    
    package main
    
    import (
    	"fmt"
    
    	"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:  "+14151234567",
    			Dst:  "+14151112222",
    			Text: "Hello, this is a sample text",
    			URL:  "https://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: "+14151234567",
                    dst: new List<String> { "+14151112222" },
                    text: "Hello, this is sample text",
                    url: "https://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": "+14151234567","dst": "+14152223333", "text": "Hello, this is a sample text.", "url":"https://foo.com/sms_status/"}' \
    https://api.plivo.com/v1/Account/{auth_id}/Message/
    
    Notes:
    • Replace the auth_id and auth_token placeholders with your authentication credentials, which you can find on the Overview screen of the Plivo console.
    • Replace the src placeholder with the phone number you purchased and dst with the phone number you’ll be sending SMS messages to. Both should be in E.164 format.
    • Replaces http://foo.com/sms_status/ with the webhook URL you’ve set up.
    • If you’re using a Plivo trial account, you can send SMS messages only to phone numbers that have been verified with Plivo. You can verify phone numbers through the Phone Numbers > Sandbox Numbers page.

    Webhooks for inbound SMS

    See the receive SMS usage guide for more information about how to receive SMS messages 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’ve defined for the URL) and respond with a 200 OK response. You can store the callback data to your database.

    Note: Plivo automatically retries webhooks three times if an HTTP 200 status code is not returned:
    • First at 60 seconds after the original attempt.
    • Second at 120 seconds after the first retry attempt.
    • Third at 240 seconds after the second retry attempt.

    Test and validate

    Let’s take a look at an example. Typically, you would include a URL that points to your web app, but we’ll use a URL from RequestBin, a service that lets you collect, analyze, and debug HTTP requests, so we can check the callbacks.

    • Create a new bin in RequestBin.
    • Replace the “url” placeholder with the URL of the new bin.
    • Run the code that appear above. You should receive the SMS message on the phone number defined in destination field, and see callback requests in RequestBin similar to the screenshots below for callback events such as queued, sent, and delivered.

    Queued status callback

    Queued status event

    Sent status callback

    Sent status event

    Delivered status callback

    Delivered status event

    Note:
    • Callbacks for incoming messages work in the same manner as outbound messages.
    • You should also receive statuses such as undelivered or failed, and some messages may remain in the sent state. See more information about our different SMS statuses.

    Validating callbacks

    To avoid spoof attacks, you can validate the callbacks that your server URL receives. All requests made by Plivo to your server URLs include X-Plivo-Signature-V2, X-Plivo-Signature-Ma-V2, and X-Plivo-Signature-V2-Nonce HTTP headers. You can use them to validate that a request is from Plivo, as we discuss in our signature validation guide.

    Conversion feedback to Plivo

    You can store the data from the message status callbacks in your database for analytics. You can also choose to provide the data to Plivo as message delivery feedback. Plivo’s Conversion Feedback API lets you update Plivo on conversions for your critical two-factor authentication (2FA) and one-time password (OTP) messages. Your feedback helps us ensure consistently high delivery rates in countries where carrier networks may be unstable. Plivo’s machine-learning-based dynamic routing engine uses all of our customers’ feedback to ensure that your messages are delivered over the best-performing carrier route to the destination mobile network.