This blog post of how to connect any text message service provider to SAP Marketing Cloud, consists of 2 chapter:

    1. SMS Send Scenario

 

    1. Get Bounces Scenario

 

Integration Flow – Sms: Get Bounces Scenario

 

Overview

To give a feedback whether a sent SMS has successfully reached its destination, messaging services provide the opportunity to return status updates to an URL specified by the user. Like most messaging services, like SAP Digital Interconnect sends a HTTP GET request containing the SMS status information stored in the query parameters. Usually this HTTP GET request is sent without any authentication information, which leads to problems if the specified destination needs incoming request to provide at least basic authentication. For this reason, SMS status information, e.g. provided by SAP Digital Interconnect, cannot be sent directly to SAP Marketing Cloud and neither to SAP Cloud Integration.

That’s why we need an additional middleware layer to implement the bounce scenario for SMS, that does not need any authentication for incoming requests and is able to buffer the SMS status information until it is collected by SAP Marketing Cloud. In this example, a Cloud Foundry Servlet running on the SAP Cloud Platform is being implemented to do this job.

The graphic above shows how the different technologies work together in our example with SAP Digital Interconnect as service provider and illustrates the different processing steps:

    1. After the message has been processed by SAP Digital Interconnect, a status update is sent via HTTP GET to the URL of the Cloud Foundry Servlet.

 

    1. The Cloud Foundry Servlet provides a specific endpoint for incoming status updates. It checks if the incoming request has the correct format and stores the data persistently in a Postgres database provided by SCP.

 

    1. SAP Marketing Cloud sends a request to fetch all bounces occurred within a specific timeframe. Since the URL that SAP Marketing contacts for picking up bounces is standardized, SAP Cloud Integration is needed to redirect the request to the CF Servlet.

 

    1. SAP Cloud Integration receives the incoming requests und redirects it to the URL of the CF Servlet. The CF Servlet provides another endpoint for retrieving persisted status updates, which invokes a method that queries the Postgres database for the given timeframe and returns the result.

Depending on the developer’s preferences, the essential logic for picking up bounces (like querying a timeframe, setting up pagination etc.) can be either implemented within SAP Cloud Platform Integration or within the Cloud Foundry Servlet. In this example, the complete logic has been implemented within the Cloud Foundry Servlet while SAP Cloud Integration only serves as redirection tool.

Interface definitions

In this section, a short overview of the status interface of the generic SMS SP adapter and the structure of status updates sent by SAP Digital Interconnect, as example, will be given. A full interface definition can be found in Integration Guide: Generic Text Message Integration.

SAP Marketing Cloud generic SMS SP adapter

 

GET Request

The generic SMS SP adapter of SAP Marketing Cloud sends a HTTP GET request to the endpoint /status with the following URL parameters:

    • startTimeUTC:
      Describes the start time of a time frame in which the bounces to retrieve have occurred.

 

    • endTimeUTC:
      Describes the end time of a time frame in which the bounces to retrieve have occurred.

 

    • page:
      For very long result lists, most ESPs do not send back all results in a single response but in multiple pages of about 100 results. This parameter determines which page of the result list should be retrieved. The first page is always queried by sending a page value of 0.

 

    • sourceSystem:
      Identifies the system which send the HTTP request.

After all, a complete GET request send by SAP Marketing Cloud could look like this:

<HCI Tenant URL>/status?startTimeUTC=20171014132922&endTimeUTC=20171024142000&page=0&sourceSystem=TestSystem1

Expected response

The response to the request defined above should have the following structure:

{
    "page": "0",
    "lastPage": true,
    "status": [
        {
            messageId: "1634731244",
            recipient: "+49123456789",
            statusCode: "0x4503",
            statusText: "Message 1 of the order 1634731244 at destination of +49123456789 is out of coverage",
            type: "Permanent",
            timestamp: "20180424092754"
        },
        {
            messageId: "1635204329",
            recipient: "+49123456789",
            statusCode: "0x4503",
            statusText: "Message 1 of the order 1635204329 at destination of +49123456789 is out of coverage",
            type: "Permanent",
            timestamp: "20180424095555"
        },
        {
            messageId: "1636010434",
            recipient: "+49123456789",
            statusCode: "0x4503",
            statusText: "Message 1 of the order 1636010434 at destination of +49123456789 is out of coverage",
            type: "Permanent",
            timestamp: "20180424103504"
        }
    ]
}

Remark: Status code will not be processed in SAP Marketing Cloud system. Hence it is not required to map this to JSON.

While the property ‘page’ serves as identifier of the current package of bounces, the property ‘lastPage’ indicates whether there are some more packages that can be retrieved by sending further requests. Thus, the last package for the given timeframe provides the value true for property ‘lastPage’

SAP Digital Interconnect

If an incoming text message request contains the parameters MobileNotificationAckType and AckReplyAddress, an update about the delivery status of the message is sent to the URL specified by parameter AckReplyAddress. This update is send as HTTP GET request and contains the following query parameter:

    • orderID:
      Represents the internal order ID from SAP Digital Interconnect (which corresponds to message ID of SAP Marketing Cloud)

 

    • time:
      Time of the status update.

 

    • date:
      Date of the status update.

 

    • msisdn:
      Phone number to which the corrensponding message has been sent to.

 

    • status:
      Status code and status text combined. In case of successful message delivery, this parameter contains only a generic string.

Thus, an incoming status update from SAP Digital Interconnect could look like this:

<URL_specified_in_AckReplyAddress>?orderid=123456789&time=155423&date=14032018&msisdn=+49123456789&status=’0x4503 Message 1 of the order 1636010434 at destination of +49123456789 is out of coverage’

SCP Servlet

For the reasons described in Overview section, status updates from SAP Digital Interconnect cannot be sent directly to SAP Marketing Cloud. That’s why we need a middleware that buffers incoming status updates and provides an API for SAP Marketing Cloud to pick them up. In this example, a respective middleware is implemented on SAP Cloud Platform as Cloud Foundry Servlet written in NodeJS and with a PostgresDB for data persistency.

In the following section, the most important aspect of the servlet will be described.

Endpoints

The Notification Collector Servlet provides three endpoints that can be addressed by HTTP GET requests:

    • <SCP Servlet URL>/api/v1/notifications/get: A request to this endpoint returns the status notifications persisted in the PostgresDB. If it is requested without any parameter, all available notifications are given back. If the parameters startTimeUTC, endTimeUTC and page are specified, only the respective datasets are returned. Please note that this API exactly matches the specifications for GET requests coming from SAP Marketing Cloud described in section GET Request above.

 

    • <SCP Servlet URL>/api/v1/notifications/set: A request to this endpoint triggers the creation of a new dataset in PostgresDB. A dataset is only created if all the necessary information is given via the query parameters orderID, time, date, msisdn and status. Please note again that these parameters match the ones included in HTTP GET requests sent by SAP Digital Interconnect, as mentioned in section SAP Digital Interconnect.

 

    • <SCP Servlet URL>/api/v1/notifications/clear: This endpoint has only been implemented for testing purposes and triggers a complete deletion of all database contents.

 

Data model

The Notification Collector Servlet uses only one table on the PostgresDB whose fields exactly match the expected response structure for status updates from SAP Marketing Cloud (see section Expected response):

    • messageId: { type: DataTypes.STRING(30), allowNull: false, primaryKey: true }

 

    • recipient: { type: DataTypes.STRING(25), allowNull: false }

 

    • statusCode: { type: DataTypes.STRING(10), allowNull: false }

 

    • statusText: { type: DataTypes.STRING(250), allowNull: false }

 

    • type: { type: DataTypes.STRING(20), allowNull: true }

 

    • timestamp: { type: DataTypes.STRING(20), allowNull: false }

This means that status updates sent by SAP Digital Interconnect must be processed and mapped to the respective table fields before an INSERT operation can be performed.

Data mapping

The following graphic shows how the incoming status updates from SAP Digital Interconnect are being mapped to the table fields of the servlet:

While some fields like orderId and msisdn can be transferred without any changes, some others must be calculated:

    • time & date values are just rearranged and concatenated to fit the structure expected by SAP Marketing Cloud.

 

    • status is being split up into two different fields. This is done by a regular expression that matches the status code which always has the form 0x<4 numbers>. Since status updates are also sent if the message delivery was successful, all datasets whose status does not start with an error code are filtered out.

 

    • type describes whether a status marks a temporary or a permanent problem in message delivery. Since there is only one status code (0xDBF3) regarded as temporary by SAP Digital Interconnect, datasets with this status code get type “Temporary”. In all other cases, type “Permantent” is written to database.

 

SAP Cloud Platform Integration

Since the HTTP endpoint where SAP Marketing Cloud picks up status updates is defined as <Endpoint URL>/hybris_sms/status and cannot be changed by customer, it is not possible to request status updates directly from the SCP servlet presented above. Therefore, SAP Cloud Platform Integration is used as generic endpoint that refers the incoming requests to our SCP servlet. As mentioned in Overview section, some of the necessary data transformation steps in this example (like splitting status or merging date and time) could also have been performed by SAP Cloud Platform Integration instead of implementing them into the SCP servlet.

In this example, the SCP servlet is designed in a way that all data transformation is already done when picking up status updates. For this reason, a very simple iFlow without any data processing is sufficient to complete the scenario:

Endpoint configuration

Definition of incoming URL endpoint:

Definition of endpoint for outgoing HTTP request:

Keystore

In order to send a HTTP request from SAP Cloud Platform Integration to any endpoint secured with HTTPS, the endpoint’s domain alias must have a valid security certificate. This certificate must be included into the internal keystore of SAP Cloud Platform Integration to ensure a smooth communication. If the certificate is not available, all requests to the respective iFlow will return an error. To include the certificate, it must be uploaded in SAP Cloud Platform Integration’s Web Interface under Operations View → Keystore:

More information about how to obtain a valid certificate for a specific URL and how to upload it into SAP Cloud Platform Integration can be found in SAP Cloud Platform Integration: Deploying a Keystore.

Sara Sampaio

Sara Sampaio

Author Since: March 10, 2022

0 0 votes
Article Rating
Subscribe
Notify of
0 Comments
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x