Skip to main content

USSD API guide

General overview of USSD API

Qrios USSD API, just like Qrios API, allows developers to create own, feature-rich applications using integrations implemented by Qrios. It allows them to move beyond WWW and reach customers with GSM access only. USSD API can be used to create USSD applications which can be run from a feature phone without Internet connection.

How does it work?

In reference to diagram, a customer is going to use USSD application developed using Qrios USSD API. He dials *425*055# to start USSD session. The session is handled by network operator which passes an initiation request related to the session to the Qrios' infrastructure. 425 is a Qrios API short code and the following part, 055, can be considered as a sub short code indicating which USSD app can be used. Let's assume that 055 is the already registered developer's USSD app. Qrios platform knows that and also knows a URL of externally created USSD app. In the next step, the app is being called using REST API. As a response, Qrios USSD API receives instructions what should be done next, e.g. a message which should be sent to the user. Our 055 application returns message Hello world. The message is passed to the network operator's infrastructure and back to the user's feature-phone.

qrios_platform

Developer USSD application on Qrios API

Client profile

To use USSD API, a developer should be onboarded. A developer, which is already registered on the Qrios platform, should own client identifier and client secret. These two strings are used to authenticate a developer's request.

Creating a USSD application

When developers are registered on deep.qrios.com, they are allowed to create USSD applications. After the creation of USSD application, the unique USSD shortcode will be assigned to the application. The application is de facto only a profile that connects customers with the developer's system that implements Qrios USSD API. During the USSD application profile creation, a developer is supposed to configure the HTTP address of his system which is going to receive USSD session requests from deep.qrios.com and is supposed to respond in a strictly defined manner. The service will be hosted on the developer's side.

Implementing USSD API service

When the application is registered on the Qrios platform, the developer is able to receive requests related to a USSD session initiated by his customer. It's worth mentioning that the developer's application is NOT going to call Qrios USSD API, but it rather has to implement endpoints, according to Qrios' documentation, which will then be called by Qrios platform when different events from USSD channel are received. All request and response body contents are defined in JSON format.

All further instructions assume that the developer has created and configured the USSD app.

New session initiated by customer

Customer, dialing *425*023#, initiates a USSD session. Each session has a unique identifier which is going to be used in every request called during the session's lifetime.

Example request, which is going to be sent to the developer's application, may look like this:

POST https://example-developer-ussd-app.com/ussdSessionEvent/new
Headers:
  Authorization: e7457445-1998-4846-9254-117dd5eb122d

{
  "clientId": "x97uJ23b",
  "appId": "a12u3ui",
  "sessionId": "8a444af8-4b03-4545-8677-2a6c924bdddb",
  "msisdn": "2341234512345",
  "operator": "mtn",
  "input": {
    "type": "Dial",
    "shortcodeString": "*425*023#"
  }
}

What we have here:

  • clientId - a developer's profile identifier
  • appId - a developer's USSD application identifier on the Qrios platform
  • sessionId - a unique identifier of current USSD session (it stays unchanged from the beginning of the session to its end)
  • msisdn - a customer phone number
  • operator - a network operator of customer's phone number
  • input - this is a type of user's input. In the example above, it means that the customer dialed string *425*023#

When the developer's application receives a request like the one above, it's required to handle it and return a response with instructions what the Qrios platform should send to the customer. The response can look like this:

  1. First option - InputView
HTTP 200 (OK)
{
  "action": {
    "type": "ShowView",
    "view": {
      "type": "InputView",
      "message": "Hello world! Please enter your name:"
    }
  },
  "contextData": "devCorrelationId:12345"
}

What does the response mean? Here, we'd like to instruct Qrios Platform to:

  • send user a message ("type": "ShowView") - the message content is defined in "message": "Hello world! Please enter your name:"
  • wait for user input and then continue USSD session ("type": "InputView")
  • pass on developer's data, which will be shipped with next request ("contextData": "devCorrelationId:12345")

The customer, on his phone, should be able to see the response in formatted like this: Hello world! Please enter your name:

Moreover, he will be able to continue USSD session by providing further input and hitting send button.

  1. Second option - ChooserView
HTTP 200 (OK)
{
  "action": {
    "view": {
      "type": "ChooserView",
      "title": "Select one of the account numbers:",
      "items": [
        {
          "accessKey": "1",
          "label": "1230000123"
        },
        {
          "accessKey": "2",
          "label": "4560000456"
        },
        {
          "accessKey": "3",
          "label": "9999999999"
        }
      ],
      "separator": ">",
    },
    "type": "ShowView"
  },
  "contextData": "devCorrelationId:12345"
}

What does the response mean? Here, we'd like to instruct the Qrios platform to:

  • send user a message ("type": "ChooserView") that will be displayed as a chooser menu (ChooserView)
Select one of the account numbers:
1>1230000123
2>4560000456
3>9999999999
  • the title field is a text that will be displayed at the beginning, before the chooser items (here it is Select one of the account numbers:)
  • the items field is a list of chooser items, there must be at least one chooser item,
  • each of the items must contain:
    • accessKey field - user will have to input that value in order to choose the item, accessKey's must be unique
    • label field - the description of the item, as shown in the example above
  • for each of the items, accessKey and label will be separated by some text value called separator:
    • separator value may be provided in the optional separator field (> in the example above)
    • default will be used if not defined
  • the customer must choose one of the chooser items by providing text input equal to one of the accessKey's
  • if the customer provides some invalid input (not corresponding to any of the chooser items), then the Qrios platform will ask the customer to retry
  • the input retries will be handled internally by the Qrios platform, without sending any requests to the developer's app
  • developer's app will receive the user input - the accessKey of the selected chooser item
  • pass on developer's data, which will be shipped with next request ("contextData": "devCorrelationId:12345")

Continue existing session

Let's assume that the customer wants to continue the session. He enters: Kelechi Iheanacho and hits enter/confirm button. This is what is going to be sent to the developer's application:

POST https://example-developer-ussd-app.com/ussdSessionEvent/continue
Headers:
  Authorization: e7457445-1998-4846-9254-117dd5eb122d

{
  "clientId": "x97uJ23b",
  "appId": "a12u3ui",
  "sessionId": "8a444af8-4b03-4545-8677-2a6c924bdddb",
  "result": {
    "type": "InputResult",
    "value": "Kelechi Iheanacho"
  }
}

It will work very similarly if there was a ChooserView:

Select one of the account numbers:
1>1230000123
2>4560000456
3>9999999999

In that case if the customer wants to continue the session, then he must enter one of the options: 1, 2 or 3.\ This is what is going to be sent to the developer's application if the customer has chosen option 2:

POST https://example-developer-ussd-app.com/ussdSessionEvent/continue
Headers:
  Authorization: e7457445-1998-4846-9254-117dd5eb122d

{
  "clientId": "x97uJ23b",
  "appId": "a12u3ui",
  "sessionId": "8a444af8-4b03-4545-8677-2a6c924bdddb",
  "result": {
    "type": "InputResult",
    "value": "2"
  }
}

As we can see, the request is a little bit different from the one we saw in the context of the new session. Here we also see sessionId parameter and its value is the same as on new session. Input type is InputResult, which means that under value field we should expect string entered by the customer.

Also here, the developer's application is expected to handle it and send a response. The response format is the same as for the new session request. But let's see another example of it:

HTTP 200 (OK)
{
  "action": {
    "type": "ShowView",
    "view": {
      "type": "InfoView",
      "message": "Welome Kelechi Iheanacho! You rock!!!"
    }
  },
  "contextData": "devCorrelationId:12345"
}

It looks almost the same with one exception - "type": "InfoView". It means that USSD application doesn't expect customer to provide further input. There will be no other interaction with the customer within current (8a444af8-4b03-4545-8677-2a6c924bdddb) session and the session is going to be closed.

Closing session

In the last response our example USSD application, the Qrios platform was instructed to send Welome Kelechi Iheanacho! You rock!!! to the customer with expectation of no further interaction. Qrios platform sends the message and then closes the 8a444af8-4b03-4545-8677-2a6c924bdddb session. The developer's application will be notified about the fact of session closing using request like below:

POST https://example-developer-ussd-app.com/ussdSessionEvent/close
Headers:
  Authorization: e7457445-1998-4846-9254-117dd5eb122d

{
  "clientId": "x97uJ23b",
  "appId": "a12u3ui",
  "sessionId": "8a444af8-4b03-4545-8677-2a6c924bdddb",
  "reason": {
    "type": "End"
  },
  "contextData": "devCorrelationId:12345"
}

There is no requirement for body response expected to be sent. Response to the request can look like this:

HTTP 204 (No content)

Field reason contains the type of session close. We can distinguish 3 types - different reasons of session closing:

  • End - it is sent when the session is closed naturally (there is no further customer input needed)
  • Abandon - a customer received a message but instead of providing an input, he pressed cancel. We interpret it that he abandoned the session.
  • Timeout - duration of a USSD session is limited by a network operator. You should assume that after 2 minutes, a session will be forced to close by the operator.

Session aborting

In exceptional cases, a session could be aborted. We distinguish the following reasons of session aborting:

  • MissingPrivilege - there are no required privileges to run a USSD operation
  • InsufficientBalanceInVirtualPurse - developer's balance is too low to run a USSd operation
  • DuplicatedOperation - operation, e.g. Merchant Payment, was previously invoked with given identifier
  • UnexpectedUssdAppResponse - the previous USSD app response was malformed or not expected
  • InternalError - there was some internal error in Qrios API or USSD app is not achievable or responded too long

In general, this request means that Qrios platform cannot continue the session any more, so it was exceptionally closed.

POST https://example-developer-ussd-app.com/ussdSessionEvent/abort
Headers:
  Authorization: e7457445-1998-4846-9254-117dd5eb122d

{
  "clientId": "x97uJ23b",
  "appId": "a12u3ui",
  "sessionId": "8a444af8-4b03-4545-8677-2a6c924bdddb",
  "reason": {
    "type": "MissingPrivilege"
    "privilege": "USSD API"
  },
  "contextData": "devCorrelationId:12345"
}
POST https://example-developer-ussd-app.com/ussdSessionEvent/abort
Headers:
  Authorization: e7457445-1998-4846-9254-117dd5eb122d

{
  "clientId": "x97uJ23b",
  "appId": "a12u3ui",
  "sessionId": "8a444af8-4b03-4545-8677-2a6c924bdddb",
  "reason": {
    "type": "InsufficientBalanceInVirtualPurse"
  },
  "contextData": "devCorrelationId:12345"
}
POST https://example-developer-ussd-app.com/ussdSessionEvent/abort
Headers:
  Authorization: e7457445-1998-4846-9254-117dd5eb122d

{
  "clientId": "x97uJ23b",
  "appId": "a12u3ui",
  "sessionId": "8a444af8-4b03-4545-8677-2a6c924bdddb",
  "reason": {
    "type": "DuplicatedOperation",
    "operationId": "535bdec5-ea1c-4737-b9e2-04a9743d4227"
  },
  "contextData": "devCorrelationId:12345"
}
POST https://example-developer-ussd-app.com/ussdSessionEvent/abort
Headers:
  Authorization: e7457445-1998-4846-9254-117dd5eb122d

{
  "clientId": "x97uJ23b",
  "appId": "a12u3ui",
  "sessionId": "8a444af8-4b03-4545-8677-2a6c924bdddb",
  "reason": {
    "type": "UnexpectedUssdAppResponse"
  },
  "contextData": "devCorrelationId:12345"
}
POST https://example-developer-ussd-app.com/ussdSessionEvent/abort
Headers:
  Authorization: e7457445-1998-4846-9254-117dd5eb122d

{
  "clientId": "x97uJ23b",
  "appId": "a12u3ui",
  "sessionId": "8a444af8-4b03-4545-8677-2a6c924bdddb",
  "reason": {
    "type": "InternalError"
  },
  "contextData": "devCorrelationId:12345"
}

Expected response:

HTTP 204 (No content)

New session initiated by USSD push

In the USSD flow described above, the customer was the one, who initiated USSD session by dialing application short code *425*023# on his phone. But sometimes a developer would like to send a message to one of their customers. This is called USSD push - the message is pushed to the customer's phone. In this case session is initiated by a developer's USSD application.

In Qrios API, there is an endpoint which should be called to do it:

POST https://qrios-api.com/ussd/app/push

Headers:
  X-Client-Id: x97uJ23b
  X-Client-Secret: [secret]

{
  "appId": "a12u3ui",
  "msisdn": "2341234512345",
  "contextData": "devCorrelationId:12345"
}

What do we have in the request?

  • X-Client-Id header - a developer's identifier in Qrios API
  • X-Client-Secret header - a developer's authorization secret (generated together with developer's identifier during an onboarding process)
  • appId - a developer's USSD application identifier
  • msisdn - an MSISDN of customer who is going to receive the push message
  • contextData - as explained before (developer's correlation data - can be empty)

The response will be as follows:

HTTP 200 (OK)
{
  "sessionId": "8a444af8-4b03-4545-8677-2a6c924eeaa1",
  "recoveryShortcode": "*425*023*12345#"
}

Developer is going to receive a newly initiated session's identifier. What happens next? The Qrios platform is going to call POST /ussdSessionEvent/new endpoint of the developer's application. Then the application can produce any message with or without expected input. So, the further handling of push session is the same as the handling of dialed session. The only difference is at the beginning - developer's application sends a request to initiate it.

Recovery token

Push messages may not be delivered to a customer because of the operator's infrastructure failures. Recovery tokens are solution to make pushes more reliable. Recovery token is a short code string generated for a given push message, which can be dialled by the customer if the push didn't come. Recovery tokens are valid only for 5 minutes and are invalidated when:

  • the user receives a push message and responds to it
  • the user dials recovery token

Recovery token has 3 parts (eg. *425*023*34562#):

  • main short code 425
  • USSD application short code eg. 023
  • random 5 digit number eg. 34562

To be able to receive recovery tokens, a developer should have granted a proper permission by Qrios API admin.

Session redirection

Two (or more) USSD applications, created by different developers, can redirect to each other. Redirection is a kind of linking between these applications. Let's assume there is an external USSD application which would like to "link" our application. It could request to redirect to our application and a customer, who dialed in the other application, will be redirected seamlessly to our application within the same USSD session. This is an analogy to web linking - external website can link our site.

Redirecting from our USSD application to an external one

Redirection from our app to external one should be requested by using Redirect action type. The request for redirection can be returned as a response for request on ussdSessionEvent/new or ussdSessionEvent/continue.

Here is an example of session continue request and redirect response:

POST https://example-developer-ussd-app.com/ussdSessionEvent/continue
Headers:
  Authorization: e7457445-1998-4846-9254-117dd5eb122d

{
  "clientId": "x97uJ23b",
  "appId": "a12u3ui",
  "sessionId": "8a444af8-4b03-4545-8677-2a6c924bdddb",
  "result": {
    "type": "InputResult",
    "value": "Kelechi Iheanacho"
  }
}

Redirect to transfer process of external USSD app with ID b56r455:

HTTP 200 (OK)
{
  "action": {
    "type": "Redirect",
    "destinationAppId": "b56r455",
    "process": {
      "id": "transfer",
      "params": {
        "from": "2341001001001",
        "to": "2341001001002",
        "amount": "100"
      }
    }
  },
  "contextData": "devCorrelationId:12345"
}

Here we see that now type of our action is Redirect. Additionally, there are the following
parameters which describe USSD application and its process which we'd like to redirect to:

  • destinationAppId - an ID of USSD application which we'd like to redirect to
  • process - (optional) here we define redirect process and its input parameters
    • id - an ID of the process which we'd like to run
    • params - params of the process (name of the param is JSON object field, value of the param is the JSON field's value)

Note:
Process is something which is not defined at USSD API's level, but it's defined by developer in his application. So, process names and their params have to be provided by the developer of the application which we want to redirect our app to.

The description above is from the perspective of a developer who wants to redirect to the other developer's application. In the next section, we'll see how the other developer can handle such requests.

Handling session redirected from a different USSD application

As we saw in previous sections, a USSD session can be started/initiated directly by a customer who dials shortcode string or USSD push by the developer itself. But the session can be also redirected - started in different USSD API application, which passes it on the other application. It was mentioned earlier that redirecting is similar to web URL linking, but with one difference - USSD app developer doesn't have to allow redirecting to his app. With redirect response, he can just return e.g. a message that the operation is not available.

Example request, which represents the redirect described above and which is going to be sent to the developer's application, may look like this:

POST https://example-developer-ussd-app.com/ussdSessionEvent/new
Headers:
  Authorization: e7457445-1998-4846-9254-117dd5eb122d

{
  "clientId": "x97uJ23b",
  "appId": "a12u3ui",
  "sessionId": "8a444af8-4b03-4545-8677-2a6c92445rfd",
  "msisdn": "2341234512345",
  "operator": "mtn",
  "input": {
    "type": "Redirect",
    "processId": "transfer"
    "process": {
      "id": "transfer",
      "params": {
        "from": "2341001001001",
        "to": "2341001001002",
        "amount": "100"
      }
    }
  }
}

What we have here:

  • clientId - a developer's profile identifier
  • appId - a developer's USSD application identifier on the Qrios platform
  • sessionId - a unique identifier of current USSD session (it stays unchanged from the beginning of the session to its end)
  • msisdn - a customer phone number
  • operator - a network operator of customer's phone number
  • input - this is a type of user's input. In the example above, it means that one external USSD application requested to redirect its session to our USSD application.
  • processId - (DEPRECATED) use process.id instead (described below). It Will be removed in the future.
  • process - this is an optional section. It describes the process which session is redirected to:
    • id - this is an identifier of requested process. A USSD application's developer can use it to return proper screen or take proper action.
    • params - it is a map of process parameters - JSON key defines a name of the parameter, and its value represents the parameter value. Note that this is a dynamic part of the JSON - could be different depending on id value. Could be also empty

When the developer's application receives a request like the one above, it's required to handle it and return a response with instructions what the Qrios platform should send to the customer. The response can look like this:

HTTP 200 (OK)
{
  "action": {
    "type": "ShowView",
    "view": {
      "type": "InputView",
      "message": "Hello from my application! You are about to do a payment. Please enter an amount:"
    }
  },
  "contextData": "devCorrelationId:12345"
}

Note:
There are benefits of handling redirects. Your application can be accessed from other USSD applications, so you expand your reach. See also Billing section.

When the session is being closed, both applications will be notified by the fact with request described in Close session section.

Using Qrios API specific USSD processes

We've seen so far that a developer's app can ask the Qrios platform to show a message to the user with or without the possibility of continuing session. But the Qrios platform also allows developers to use predefined Qrios USSD processes. So, applications can instruct the Qrios platform to call one of the mentioned processes.

What is a Qrios USSD process? It is a part of the USSD flow, which is expected to deliver some action, which can be seamlessly included in a USSD flow defined by developer. Qrios USSD process provides some well-defined functionality and at the end of it, notifies the developer's application about the process result. The application can then decide how to continue the session. It's worth noting that the process may need one or more interactions with your customer. From the customer perspective, he won't notice that he left the USSD app he had initiated, because the process is executed within the same USSD session.

Let's take a look at what processes developer can use at the moment.

Merchant payment

Merchant payment process provides the ability to order payment for merchant. From a developer's USSD application perspective, it orders payment for merchant code and a given amount, and as a result of action completion, the application should be notified about the success or failure of the payment. Between the order and the notification, the customer will be asked about credentials and the payment will be executed.

[todo:] figure - diagram how it works

How to initiate this process? Let's assume we are in the middle of the session and the developer's application has just received continue request:

POST https://example-developer-ussd-app.com/ussdSessionEvent/continue
Headers:
  Authorization: e7457445-1998-4846-9254-117dd5eb122d

{
  "clientId": "x97uJ23b",
  "appId": "a12u3ui",
  "sessionId": "8a444af8-4b03-4545-8677-2a6c924bdddb",
  "result": {
    "type": "InputResult",
    "value": "Kelechi Iheanacho"
  }
}

Now, we'd like to instruct the Qrios platform to make a payment:

HTTP 200 (OK)
{
  "action": {
    "type": "RunProcess",
    "process": {
      "type": "MerchantPaymentProcess",
      "operationId": "535bdec5-ea1c-4737-b9e2-04a9743d4227",
      "merchantCode": "89440477",
      "amount": 1320.50,
      "paymentMode": {
        "type": "Flexible"
      }
    }
  },
  "contextData": "devCorrelationId:12345"
}

Here we see that now type of our action is RunProcess and type of the process is MerchantPaymentProcess. It delivers same functionality like POST /merchant/payment from Qrios API and like it requires the following parameters:

  • operationId - an unique payment operation identifier generated by developer
  • merchantCode - a code of the merchant registered in NIBSS
  • amount - an amount which should be paid to the merchant

Additionally, it requires mode of the payment (paymentMode):

  • Flexible - Qrios platform process will ask user about bank and account which is going to be used in payment
  • FixedBank - Qrios platform process will ask about an account only, because a bank is delivered in the request. Payment mode in this case looks like this:
    "paymentMode": {
      "type": "FixedBank",
      "bank": "023"
    }
    
  • FixedAccount - both, a bank and an account will be provided in request:
    ```
    "paymentMode": {
      "type": "FixedAccount",
      "account": "1234567890",
      "bank": "023"
    }
    ```
    
    How is the developer's application supposed to know what banks and accounts of the customer are available? It can use Qrios API GET /merchant/accounts endpoint do to so.

OK, what about the process result? How is it going to be delivered?

The developer's USSD application should expect that after initiation of the process, on the next continue request, it's going to receive an input of type MerchantPaymentResult. The operationId field of the input contains identifier of the payment previously ordered and result.

We can distinguish 3 types of results:

  • Success - the payment was done. The Merchant received the payment, the customer was debited. Example response:

    POST https://example-developer-ussd-app.com/ussdSessionEvent/continue
    Headers:
      Authorization: e7457445-1998-4846-9254-117dd5eb122d
    
    {
      "clientId": "x97uJ23b",
      "appId": "a12u3ui",
      "sessionId": "8a444af8-4b03-4545-8677-2a6c924bdddb",  
      "result": {
        "type": "MerchantPaymentResult",
        "operationId": "535bdec5-ea1c-4737-b9e2-04a9743d4227",
        "status": {
          "type": "Success"
        }
      }
    }
    
  • Failure - the payment cannot be done. The customer was not debited because of an error. The cause of the error will be find in cause field. Example response:

    POST https://example-developer-ussd-app.com/ussdSessionEvent/continue 
    Headers:
      Authorization: e7457445-1998-4846-9254-117dd5eb122d
    
    {
      "clientId": "x97uJ23b",
      "appId": "a12u3ui",
      "sessionId": "8a444af8-4b03-4545-8677-2a6c924bdddb",  
      "result": {
        "type": "MerchantPaymentResult",
        "operationId": "535bdec5-ea1c-4737-b9e2-04a9743d4227",
        "status": {
          "type": "Failure",
          "cause": {
            "type": "InsufficientBalance"
          }
        }
      }
    }
    

    There are several possible causes:

    • AuthenticationFailed - a customer provided wrong secret
    • InsufficientBalance - a customer doesn't have funds in their account
    • InvalidMerchant - a requested merchant code is invalid
    • NoAccounts - a customer doesn't have accounts (only in Flexible mode)
    • SwitchUnavailable - an external payment gateway doesn't work
    • Other - an unspecified error
  • Unknown - the payment result cannot be established during USSD session. The final result will be delivered together with developer's callback (defined during onboarding on Qrios API). Example response:

    POST https://example-developer-ussd-app.com/ussdSessionEvent/continue
    Headers:
      Authorization: e7457445-1998-4846-9254-117dd5eb122d
    
    {
      "clientId": "x97uJ23b",
      "appId": "a12u3ui",
      "sessionId": "8a444af8-4b03-4545-8677-2a6c924bdddb",  
      "result": {
        "type": "MerchantPaymentResult",
        "operationId": "535bdec5-ea1c-4737-b9e2-04a9743d4227",
        "status": {
          "type": "Unknown"
        }
      }
    }
    

Embedded process

An embedded process is a service provided by the Qrios platform that exposes a redirect to application managed by Qrios and returns the result via redirect back to the developer application. Developer with required privileges and fee rule configured can initiate an embedded process by returning a response with instruction like the following:

HTTP 200 (OK)
{
  "action": {
    "type": "RunProcess",
    "process": {
      "type": "EmbeddedProcess",
      "processId": "process-id-value",
      "params": {
        "key": "value"
      }
    }
  },
  "contextData": "devCorrelationId:12345"
}

The processId value determines what process to be invoked. The params json object contains embedded process specific key-value pairs. All values in params object are of type JSON string. This action causes the Qrios system to hand over control of the USSD session to an application managed by Qrios. The user may be prompted to provide credentials during the embedded process. After the embedded process is complete, control is handed over back to the calling application within the same USSD session. The developer's USSD application should expect that after initiation of the process, on the next continue request, it's going to receive an input of type EmbeddedProcessResult. The resultParams field of the input contains results of the ordered embedded process. All values in resultParams object are of type JSON string. Example request:

POST https://example-developer-ussd-app.com/ussdSessionEvent/continue
Headers:
  Authorization: e7457445-1998-4846-9254-117dd5eb122d

{
  "clientId": "x97uJ23b",
  "appId": "a12u3ui",
  "sessionId": "8a444af8-4b03-4545-8677-2a6c924bdddb",
  "result": {
    "type": "EmbeddedProcessResult",
    "resultParams": {
      "key": "value"
    }
  }
}

Qrios API callback notification

Even though the result of the action is returned in the context of USSD session, there is always the second, more reliable, method of notification - Qrios API callback. During onboarding, a developer is required to provide a callback URL which will be invoked to notify his application about an asynchronous result of an action he invoked.

Example:

Let's assume a developer has configured URL https://developer.example.com/callback as a main callback. When the merchant payment result is delivered, the following callback should also be invoked:

  • for success case:

    POST https://developer.example.com/callback
    {
      "clientId": "x97uJ23b",
      "operationId": "535bdec5-ea1c-4737-b9e2-04a9743d4227",
      "result": "Success" 
    }
    
  • for failure case:

    POST https://developer.example.com/callback
    {
      "clientId": "x97uJ23b",
      "operationId": "535bdec5-ea1c-4737-b9e2-04a9743d4227",
      "result": "Failure",
      "cause": "InsufficientBalance"
    }
    
  • for unknown case:

    POST https://developer.example.com/callback
    {
      "clientId": "x97uJ23b",
      "operationId": "535bdec5-ea1c-4737-b9e2-04a9743d4227",
      "result": "Unknown"
    }
    

Billing

Every USSD session is going to be billed. A total fee charged for the session handling depends on the session length. A session will be divided into 20 seconds ticks. Every started 20 seconds of session will be counted as a tick. A developer has configured a custom fee per tick. So, the charge can be calculated using the simple formula: total fee = ceil(session length / 20 seconds) * fee per tick.

History of the operations could be checked by developer using GET /operation/history endpoint from Qrios API.

Billing vs redirection

Application can handle redirection explicitly to be allowed to be used by external USSD apps. To encourage developers to handle redirect requests, a billing model was designed to be free for them. So, only the caller of the redirection is charged for the whole session, from the beginning of the session to its end.

Example application #1

Let's assume that our developer wants to create an USSD application for one of NIBSS' merchants, who is a fuel retailer and wants to give their customers the possibility to pay for fuel with USSD channel.

How could the business flow look?

  • a customer drives up to the fuel station distributor
  • he dials a USSD app short code
  • he provides required data like:
    • a distributor number and
    • an amount for which he would like to buy gasoline
  • then he picks a debit account and enters pin to confirm
  • a payment is done, and he sees confirmation on his phone
  • the payment confirmation is also sent with SMS
  • the distributor is ready for use
  • the customer is allowed to fill his tank with the quantity of fuel purchased

How Qrios API is going to be used to deliver such USSD flow?

Registration on Qrios platform

The developer should be registered on the Qrios platform. He should also have the USSD app registered. To do so, the developer should contact Qrios support. After registration, he should own the following data: client ID, client secret and USSD app ID.

To check this profile, he could call:

GET /client/info
Headers: 
  X-Client-Id: XXXXXXXXX
  X-Client-Secret: XXXXXXXXXXXXXXXX

The response could look like this:

HTTP 200 (OK)
{
  "msisdn": "2341010101010",
  "callback": "https://fuel.example.com/notify",
  "name": "NIGERIA FUEL STATION",
  "emailAddress": "fuel@example.com",
  "country": "Nigeria"
}

To check USSD application profile, he could call:

GET /ussd/app/XXXXXXXX
Headers: 
  X-Client-Id: XXXXXXXXX
  X-Client-Secret: XXXXXXXXXXXXXXXX

The response could look like this:

HTTP 200 (OK)
{
  "appId": "XXXXXXXX",
  "url": "https://fuel.example.com/ussd",
  "shortcode": "425*023"
}

USSD fuel payment flow definition

As we see in examples above, our developer registered his USSD app under https://fuel.example.com/ussd . This URL will be used as a base address for Qrios USSD. Qrios platform is going to call it to deliver information about an USSD session state. Responses sent back to the Qrios platform are the instructions what to do next.

The Fuel USSD app will be accessible in USSD channel under 425*023 short code. It means that a customer can access is by dialing *425*023# (or other short code string the developer can imagine, like *425*023*100#, *425*023*100*2341001001001#).

Let's assume that our fuel payment flow will be accesses under *425*023#. A customer, with MTN's MSISDN: 2341234567890, dials it and the developer's application should be notified with a request:

POST https://fuel.example.com/ussd/ussdSessionEvent/new
Headers:
  Authorization: d3745982-6b72-4e1e-b778-a620e29e5c35

{
  "clientId": "XXXXXXXXXX",
  "appId": "XXXXXXXXXXX",
  "sessionId": "8a444af8-4b03-4545-8677-2a6c924bdddb",
  "msisdn": "2341234567890",
  "operator": "mtn",
  "input": {
    "type": "Dial",
    "shortcodeString": "*425*023#"
  }
}

Referring to our plan described above, our application should ask user for distributor number, so a response should be as follows:

HTTP 200 (OK)
{
  "action": {
    "type": "ShowView",
    "view": {
      "type": "InputView",
      "message": "Welcome to FUEL app.\n\nPlease, provide distributor number:"
    }
  }
}

User should see on his phone message like this:

Welcome to FUEL app.

Please, provide distributor number:

He enters: 1234554321

A result of this action will be the next request handled by developer's app:

POST https://fuel.example.com/ussd/ussdSessionEvent/continue
Headers:
  Authorization: d3745982-6b72-4e1e-b778-a620e29e5c35

{
  "clientId": "XXXXXXXXXX",
  "appId": "XXXXXXXXXXX",
  "sessionId": "8a444af8-4b03-4545-8677-2a6c924bdddb",
  "result": {
    "type": "InputResult",
    "value": "1234554321"
  }
}

Here we have information that our customer continues USSD session with ID = 8a444af8-4b03-4545-8677-2a6c924bdddb and he sends 1234554321. The developer's application could validate this data, save it and ask for more:

HTTP 200 (OK)
{
  "action": {
    "type": "ShowView",
    "view": {
      "type": "InputView",
      "message": "Enter amount (in N):"
    }
  }
}

User should see on his phone message like this: Enter amount (in N):

He enters: 10000

Now, the application receives request:

POST https://fuel.example.com/ussd/ussdSessionEvent/continue
Headers:
  Authorization: d3745982-6b72-4e1e-b778-a620e29e5c35

{
  "clientId": "XXXXXXXXXX",
  "appId": "XXXXXXXXXXX",
  "sessionId": "8a444af8-4b03-4545-8677-2a6c924bdddb",
  "result": {
    "type": "InputResult",
    "value": "10000"
  }
}

We have all we needed, so there is a time for payment. Let's assume that our fuel station is a registered merchant in NIBSS. Its merchant code is 89440000. So, what we'd like the Qrios platform to do is to ask the customer to pay N10000 to merchant 89440000. To do so, we return:

HTTP 200 (OK)
{
  "action": {
    "type": "RunProcess",
    "process": {
      "type": "MerchantPaymentProcess",
      "operationId": "535bdec5-ea1c-4737-b9e2-04a9743d4227",
      "merchantCode": "89440000",
      "amount": 10000,
      "paymentMode": {
        "type": "Flexible"
      }
    }
  }
}

As a result of the response Qrios platform starts merchant payment USSD subprocess. The customer will be asked to pick an account and after that to enter pin to confirm. So, the customer is going to see at least 2 screens, and he is going to enter 2 values.

What happens next? The payment is called and then the result comes the developer's application (let's assume that the payment has finished with success):

POST https://fuel.example.com/ussd/ussdSessionEvent/continue
Headers:
  Authorization: d3745982-6b72-4e1e-b778-a620e29e5c35

{
  "clientId": "XXXXXXXXXX",
  "appId": "XXXXXXXXXXX",
  "sessionId": "8a444af8-4b03-4545-8677-2a6c924bdddb",
  "result": {
    "type": "MerchantPaymentResult",
    "operationId": "535bdec5-ea1c-4737-b9e2-04a9743d4227",
    "status": {
      "type": "Success"
    }
  }
}

It means that our transaction, identified by 535bdec5-ea1c-4737-b9e2-04a9743d4227, has finished with success. Now, when we are sure that our customer paid N10000, we could e.g. unblock the distributor calling internal API and send him SMS with confirmation.

There is nothing more to do during the USSD session, so now we instruct the Qrios platform to return the last message, without a required input:

HTTP 200 (OK)
{
  "action": {
    "type": "ShowView",
    "view": {
      "type": "InfoView",
      "message": "Thanks for you payment. You can fill your tank now."
    }
  }
}

User will see: Thanks for you payment. You can fill your tank now.

And the flow ends here.

Our application is going to be informed about the session end with a request:

POST https://fuel.example.com/ussd/ussdSessionEvent/close
Headers:
  Authorization: d3745982-6b72-4e1e-b778-a620e29e5c35

{
  "clientId": "XXXXXXXXXX",
  "appId": "XXXXXXXXXXX",
  "sessionId": "8a444af8-4b03-4545-8677-2a6c924bdddb",
  "reason": {
    "type": "End"
  }
}

But in our business scenario, there is nothing to do in this step, so our app just returns:

HTTP 204 (No content)

And this is it. In the example above, we have shown what kind of requests our application should handle and what responses it should send back to the Qrios platform to realize fictive USSD flow for fuel retailer.

Example application #2

The second example is an application for another merchant who has a web store and would like to provide his customers ability to pay for goods with USSD channel.

How could the business flow look?

  • a customer picks some product in online store and trying to buy it
  • the customer would like to pay using his account, and the transaction should be done in USSD channel, so he clicks the proper option
  • store application initiates USSD session
  • the customer receives USSD push message with information that he is supposed to pay for the product e.g. N10000.
  • the customer authorizes the transaction with his PIN
  • after successful payment, the online store receives proper info
  • the customer bought the product and the merchant can ship it

Registration on Qrios platform

Obviously, a developer should register a new USSD application on Qrios API. The registration was shown in the first example, so now, we just assume that the developer has registered application like this:

GET /ussd/app/XXXXXXXX
Headers: 
  X-Client-Id: XXXXXXXXX
  X-Client-Secret: XXXXXXXXXXXXXXXX

The response could look like this:

HTTP 200 (OK)
{
  "appId": "XXXXXXXX",
  "url": "https://store-payment.example.com/ussd",
  "shortcode": "425*020"
}

Online shopping payment USSD flow definition

In this scenario, a developer's USSD app doesn't expose any shortcode string for a customer to dial but rather wants to push the message to his phone.

To initiate USSD session, the developer's app should send a push request with the customer's msisdn, who is supposed to receive a USSD message. Obviously the developer should use his Qrios API credentials to authorize.

POST /ussd/app/push
Headers: 
  X-Client-Id: XXXXXXXXX
  X-Client-Secret: XXXXXXXXXXXXXXXX

{
  "appId": "XXXXXXXXXXX",
  "msisdn": "2341234567890",
  "contextData": ""
}

The response could be as follows:

HTTP 200 (OK)
{
  "sessionId": "22444af8-4b03-4545-8677-2a6c924bdddb",
  "recoveryShortcode": "*425*020*55555#"
}

The response contains:

  • sessionId - identifier of new USSD session
  • recoveryShortcode - optional recovery shortcode (if the developer has proper grant on the Qrios API platform), which should be shown to the user e.g. on payment summary page

Then the Qrios API platform is going to send request to the developer's app with initiated session.

POST https://store-payment.example.com/ussd/ussdSessionEvent/new
Headers:
  Authorization: 07284bae-08ba-40fc-8194-d4fe4e1fabec

{
  "clientId": "XXXXXXXXXX",
  "appId": "XXXXXXXXXXX",
  "sessionId": "22444af8-4b03-4545-8677-2a6c924bdddb",
  "msisdn": "2341234567890",
  "operator": "mtn",
  "input": {
    "type": "Push"
    "contextData": ""
  }
}

The input.type field indicates that the session was initiated by push, not user himself. Now, the app is supposed to describe what user should see.

HTTP 200 (OK)
{
  "action": {
    "type": "ShowView",
    "view": {
      "type": "InputView",
      "message": "Online store XXX\nYou'll pay N10000 for YYY\nPress 1 to continue"
    }
  }
}

The customers will see a message like this:

Online store XXX
You'll pay N10000 for YYY
Press 1 to continue

When he enters 1 (or whatever), a request like below will be sent to the application:

POST https://store-payment.example.com/ussd/ussdSessionEvent/continue
Headers:
  Authorization: 07284bae-08ba-40fc-8194-d4fe4e1fabec

{
  "clientId": "XXXXXXXXXX",
  "appId": "XXXXXXXXXXX",
  "sessionId": "22444af8-4b03-4545-8677-2a6c924bdddb",
  "result": {
    "type": "InputResult",
    "value": "1"
  }
}

Now, the developer's application can instruct Qrios API to provide merchant payment functionality. Let's assume that our store has a registered merchant in NIBSS. Its merchant code is 89440000. So, what we'd like the Qrios platform to do is to ask the customer to pay N10000 to merchant 89440000. To do so, we return:

HTTP 200 (OK)
{
  "action": {
    "type": "RunProcess",
    "process": {
      "type": "MerchantPaymentProcess",
      "operationId": "666bdec5-ea1c-4737-b9e2-04a9743d4227",
      "merchantCode": "89440000",
      "amount": 10000,
      "paymentMode": {
        "type": "Flexible"
      }
    }
  }
}

As a result of the response Qrios platform starts merchant payment USSD subprocess. The customer will be asked to pick an account and after that to enter pin to confirm. So, the customer is going to see at least 2 screens, and he is going to enter 2 values.

What happens next? The payment is called and then the result comes the developer's application (let's assume that the payment has finished with success):

POST https://store-payment.example.com/ussd/ussdSessionEvent/continue
Headers:
  Authorization: 07284bae-08ba-40fc-8194-d4fe4e1fabec

{
  "clientId": "XXXXXXXXXX",
  "appId": "XXXXXXXXXXX",
  "sessionId": "22444af8-4b03-4545-8677-2a6c924bdddb",
  "result": {
    "type": "MerchantPaymentResult",
    "operationId": "666bdec5-ea1c-4737-b9e2-04a9743d4227",
    "status": {
      "type": "Success"
    }
  }
}

It means that our transaction, identified by 666bdec5-ea1c-4737-b9e2-04a9743d4227, has finished with success. Now, we are sure that our customer paid N10000.

There is nothing more to do during the USSD session, so now we instruct the Qrios platform to return the last message, without a required input:

HTTP 200 (OK)
{
  "action": {
    "type": "ShowView",
    "view": {
      "type": "InfoView",
      "message": "Thanks for you payment. We're preparing your order. It'll be shipped as soon as possible."
    }
  }
}

User will see: Thanks for you payment. We're preparing your order. It'll be shipped as soon as possible.

And the flow ends here. The developer should show the same info on his order summary page.

Our USSD application is going to be informed about the session end with a request:

POST https://store-payment.example.com/ussd/ussdSessionEvent/close
Headers:
  Authorization: 07284bae-08ba-40fc-8194-d4fe4e1fabec

{
  "clientId": "XXXXXXXXXX",
  "appId": "XXXXXXXXXXX",
  "sessionId": "22444af8-4b03-4545-8677-2a6c924bdddb",
  "reason": {
    "type": "End"
  }
}

But in our business scenario, there is nothing to do in this step, so our app just returns:

HTTP 204 (No content)

And this is it. In the example above, we have shown what kind of requests the application should handle and what responses it should send back to the Qrios platform to realise fictive USSD flow with PUSH for online shop.

I hope this basic tutorial shows how it works and allows you to deliver much more complicated flows and reach your customers also through USSD channel.