AfricasTalkingLtd / africastalking.Net

Africa's Talking API Wrapper for C#
https://developers.africastalking.com
MIT License
18 stars 38 forks source link
payments shortcode sms-api ussd voice

Official Africa's Talking C# API wrapper

Build Status

NuGet

The Africa's Talking C# API wrapper provides convenient access to the Africa's Talking API from applications written in C#. With support for .NET45, .NET46 and .NET Core 2 +

Documentation

Take a look at the API docs here for more information.

Installation Options

  1. Using Visual Studio IDE

For .NET Standard 2.0 projects warngings may appear on your solution items,note that these are warnings due to deprecated support for some packages used by the wrapper.These will be reviewed in future release. These can be safely ignored.

For more info on this follow this thread and this link .

Install Package

  1. Using .NET CLI

  1. Using Nuget Package Manger Console

Usage

The package needs to be configured with your Africa's Talking username and API key (which you can get from the dashboard).


 const string username = "sandbox"; // substitute with your username if mot using sandbox
 const string apikey = "mySandboxKey"; // substitute with your production API key if not using sandbox

 var gateway = new AfricasTalkingGateway(username, apiKey);

Important:

If you register a callback URL with the API, always remember to acknowledge the receipt of any data it sends by responding with an HTTP 200; Here's a sample application you can use to test a call-back url

For example in an ASP.NET Core or ASP.NET MVC Project

[HttpPost]
[Consumes("application/x-www-form-urlencoded")]
public ActionResult SomeCoolMethod([FromForm] SMSResponse smsResponse)
{
    // Your awesome logic
    return Ok();
}

We also have a class SMSResponse as part of the controller that makes getters and setters for the payload we receive from the server. It should look as so

    public class SMSResponse
    {
        public string Date { get; set; }
        public string From { get; set; }
        public string Id { get; set; }
        public string LinkId { get; set; }
        public string Text { get; set; }
        public string NetworkCode { get; set; }
        public string To { get; set; }

    }

SMS

            try
            {
                var sms = gateway.SendMessage(recepients, msg);
                foreach (var res in sms["SMSMessageData"]["Recipients"])
                {
                    Console.WriteLine((string)res["number"] + ": ");
                    Console.WriteLine((string)res["status"] + ": ");
                    Console.WriteLine((string)res["messageId"] + ": ");
                    Console.WriteLine((string)res["cost"] + ": ");
                }
            }
            catch (AfricasTalkingGatewayException exception)
            {
                Console.WriteLine(exception);
            }

Sending Bulk SMS

Sending Premium SMS

Retrieving SMS

You can register a callback URL with us and we will forward any messages that are sent to your account the moment they arrive. Read more

Premium Subscriptions

Example - Creating Premium SMS subscription

            var username = "sandbox";
            var apikey = "KEY";
            var gateway = new AfricasTalkingGateway(username, apikey);
            var shortCode = "NNNNN";
            var keyword = "keyword";
            var phoneNum = "+254XXXXXXXXX";
            try
            {
                var response = gateway.CreateSubscription(phoneNum, shortCode, keyword);
                Console.WriteLine(response);
            }
            catch (AfricasTalkingGatewayException e)
            {
                Console.WriteLine("We hit a snag: " + e.StackTrace + ". " + e.Message);
                throw;
            }

Example -Sending Premium SMS

            var username = "sandbox";
            var apikey = "KEY";
            var gateway = new AfricasTalkingGateway(username, apikey);
            var opts = new Hashtable { ["keyword"] = "mykeyword" }; // ....
            var from = "NNNNN";
            var to = "+2547XXXXX,+2547XXXXY";
            var message = "Super Cool Message";
            try
            {
                var res = gateway.SendPremiumMessage(to, message, from, 0, opts); 
                Console.WriteLine(res);
            }
            catch (AfricasTalkingGatewayException e)
            {
                Console.WriteLine("Error: " + e.Message);
                throw;
            }

Voice

Call

Important

Take a look at the voice sample application here VoiceCallbackSample

UploadMediaFile

            const string username    = "UserName";
            const string apikey      = "APIKEY";
            const string fileLocation = "http(s)://<url>.mp3||wav";
            const string phoneNumber = "callerID";

            var gateway = new AfricasTalkingGateway(username, apikey);

            try
            {
                var results = gateway.UploadMediaFile(fileLocation, phoneNumber);
                Console.WriteLine(results);

            }
            catch (AfricasTalkingGatewayException exception)
            {
                Console.WriteLine("Something went horribly wrong: " + exception.Message + ".\nCaused by :" + exception.StackTrace);
            }

FetchCallQueue

This feature allows you to get number of queued calls from the service. Ideally for this to work you should have a virtual number whose dialplan is set to <Enqueue>.

const string queueNumber = "+2ABCXYYYYYY";
const string queueName = "myQueue";
var results = gateway.GetNumberOfQueuedCalls(queueNumber,queueName); 

Airtime

var airtimeTransaction = gateway.SendAirtime(airtimerecipients);

            class AirtimeUsers {
                    [JsonProperty("phoneNumber")]
                    public string PhoneNumber { get; set; }

                    [JsonProperty("amount")]
                    public string Amount { get; set; }
            }
            const string username = "UserName";
            const string apikey = "MyAPIKEY";
            var airtimeUser = new AirtimeUsers();
            airtimeUser.PhoneNumber = "+2547XXYYYYYY";
            airtimeUser.Amount = "KES 100";
            var airtimeRecipient = JsonConvert.SerializeObject(airtimeUser);
            var gateway = new AfricasTalkingGateway(username, apikey);
            try
            {
                var airtimeTransaction = gateway.SendAirtime(airtimeRecipient);
                Console.WriteLine(airtimeTransaction);
            }
            catch (AfricasTalkingGatewayException e)
            {
                Console.WriteLine("We ran into issues: " + e.StackTrace + ": " + e.Message);
            }

Payments

Mobile Consumer To Business (C2B) functionality allows your application to receive payments that are initiated by a mobile subscriber. This is typically achieved by disctributing a PayBill or BuyGoods number (and optionally an account number) that clients can use to make payments from their mobile devices. Read more

Checkout

B2C

Example

 // Suppose a superhero unknowingly paid for a suit they did not like,and we want to refund them
            // or you want to pay your employees,staff etc...
            // Note::
            /*
             * Remember: In a live account ensure you have registered a credible B2C product and a callback url else these transactions will fail
             */

            // Developer Details
            string username = "sandbox";
            string apiKey = "apikey";
            string productName = "coolproduct";
            string currencyCode = "KES";

            // Recepient details,these can be retrieved from a db..or somewhere else then parsed...we'll keep it simple
            string hero1PhoneNum = "+254xxxxxxx";
            string hero2PhoneNum = "+254xxxxxxx";
            string hero1Name = "Batman";
            string hero2Name = "Superman";
            decimal hero1amount = 15000M;
            decimal hero2amount = 54000M;

            // We invoke our gateway
            var gateway = new AfricasTalkingGateway(username, apiKey);

            // Let's create a bunch of people who'll be receiving the refund or monthly salary etc...
            var hero1 = new MobileB2CRecepient(hero1Name, hero1PhoneNum, currencyCode, hero1amount);

            // we can add metadata...like why we're paying them/refunding them etc...
            hero1.AddMetadata("reason", "Torn Suit");
            var hero2 = new MobileB2CRecepient(hero2Name, hero2PhoneNum, currencyCode, hero2amount);
            hero2.AddMetadata("reason", "Itchy Suit");

            // ....etc

            // Next we create a recepients list
            IList<MobileB2CRecepient> heroes = new List<MobileB2CRecepient>
            {
                hero1,
                hero2
            };

            // let's refund them so that they can keep saving the planet
            try
            {
                var response = gateway.MobileB2C(productName, heroes);
                Console.WriteLine(heroes);
                Console.WriteLine(response);
                // The response type is of type DataResult.
                // You can query : 
                // 1 - DataResult.NumQueued (type int)
                // 2 - DataResult.Entries (type IList)
                // 3 - DataResult.TotalValue (type string)
                // 4 - DataResult.TotalTransactionFee (type string)
                // You also have a DataResult.ToString() method available

            }
            catch (AfricasTalkingGatewayException e)
            {
                Console.WriteLine("We ran into problems: " + e.StackTrace + e.Message);
            }
            Console.ReadLine();
        }

B2B

Example


// Suppose we want to move money from our *awesomeproduct* to *coolproduct*
/*
* Remember to register  B2B products and callback urls:else these trasactions will fail
*/
string username = "sandbox";
string apiKey = "APIKEY";
string productName = "awesomeproduct";
string currencyCode = "KES";
decimal amount = 15;
string provider = "Athena";
string destinationChannel = "mychannel"; // This is the channel that will be receiving the payment
string destinationAccount = "coolproduct";
dynamic metadataDetails = new JObject();
metadataDetails.shopName = "cartNumber";
metadataDetails.Info = "Stuff";
string transferType = "BusinessToBusinessTransfer";
var gateWay = new AfricasTalkingGateway(username, apiKey);
try
{
string response = gateWay.MobileB2B(
productName,
provider,
transferType,
currencyCode,
amount,
destinationChannel,
destinationAccount,
metadataDetails);
Console.WriteLine(response);
// This method avails the B2BResults object that can be unpacked to obtain:
// 1 - B2BResults.ProviderChannel
// 2 - B2BResults.TransactionId
// 3 - B2BResults.TransactionFee
// 4 - B2BResults.Status
}
catch (AfricasTalkingGatewayException e)
{
Console.WriteLine("Woopsies! We ran into issues: " + e.StackTrace + " : " + e.Message);
}

#### [Banking - Checkout](http://docs.africastalking.com/bank/checkout)

- `BankCheckout(productName,bankAccount,currencyCode,amount,narration,metadata)` : Bank Account checkout APIs allow your application to collect money into your Payment Wallet by initiating an OTP-validated transaction that deducts money from a customer's bank account. These APIs are currently only available in Nigeria.
    - `productName` :  This value identifies the Africa's Talking Payment Product that should be used to initiate this transaction. `REQUIRED`   
    - `bankAccount` :  This is a complex type whose structure is described below. It contains the details of the bank account to be charged in this transaction.  
        - `accountName` :  The name of the bank account. `Optional`
        - `accountNumber` : The account number. `REQUIRED` 
        - `bankCode` :  A 6-Digit Integer Code for the bank that we allocate. `REQURED`. See this [link](http://docs.africastalking.com/bank/checkout) for more details
        - `dateOfBirth` : Date of birth of the account owner. `Optional`/`Required` - for Zenith Bank NG.

    - `currencyCode` : This is the 3-digit ISO format currency code for the value of this transaction (e.g NGN, USD, KES etc). 
    - `amount` : This is the amount (in the provided currency) that the mobile subscriber is expected to confirm. 
    - `narration` : A short description of the transaction that can be displayed on the client's statement. 
    - `metadata` : This value contains a map of any metadata that you would like us to associate with this request. You can use this field to send data that will map notifications to checkout requests, since we will include it when we send notifications once the checkout is complete.

> Example  - For details on OTP see OTP
```c# 

        Console.WriteLine("Hello World!");
            const string Username = "sandbox";
            const string ApiKey = "Key";
            const string Otp = "1234";
            var gateway = new AfricasTalkingGateway(Username, ApiKey);
            string transId = "id";
            var productName = "coolproduct";
            var accountName = "Fela Kuti";
            var accountNumber = "1234567890";
            var bankCode = 234001;
            var currencyCode = "NGN";
            var amount = 1000.5M;
            var dob = "2017-11-22";
            var metadata = new Dictionary<string, string> { { "Reason", "Buy Vega Records" } };
            var narration = "We're buying something cool";
            var receBank = new BankAccount(accountNumber, bankCode, dob, accountName);
            try
            {
                // You get a BankCheckoutResponse object that contains the following properties
                // 1. BankCheckoutResponse.Status
                // 2. BankCheckoutResponse.TransactionId
                // 3. BankCheckoutResponse.Description
                // And a ToString() method
                BankCheckoutResponse res = gateway.BankCheckout(productName, receBank, currencyCode, amount, narration, metadata);
                Console.WriteLine(res);
                if (res.Status == "PendingValidation")
                {
                    transId = res.TransactionId;
                    Console.WriteLine("Validating...");
                }

                try
                {
                    var valid = gateway.OtpValidate(transId, Otp);
                    valid = JsonConvert.DeserializeObject(valid);
                    if (valid["status"] == "Success")
                    {
                        Console.WriteLine("Whoooohoo...");
                    }
                }
                catch (AfricasTalkingGatewayException e)
                {
                    Console.WriteLine("Yikes: " + e.Message + e.StackTrace);
                }

            } 
            catch (AfricasTalkingGatewayException e)
            {
                Console.WriteLine("Something odd happened: " + e.Message + e.StackTrace);
            }

        Console.ReadLine();

Banking - Transfer

Example

        const string username = "sandbox";
        const string apikey = "KEY";
        const string productname = "coolproduct";
        var gateway = new AfricasTalkingGateway(username, apikey);
        var currency_code = "NGN";
        var recipient1_account_name = "Alyssa Hacker";
        var recipient1_account_number = "1234567890";
        var recipient1_bank_code = 234001;
        decimal recipient1_amount = 1500.50M;
        var recipient1_narration = "December Bonus";
        var recipient2_account_name = "Ben BitDiddle";
        var recipient2_account_number = "234567891";
        var recipient2_bank_code = 234004;
        decimal recipient2_amount = 1500.50M;
        var recipient2_narration = "November Bonus";
        var recepient1_account = new BankAccount(recipient1_account_number, recipient1_bank_code, recipient1_account_name);
        var recepient1 = new BankTransferRecipients(recipient1_amount, recepient1_account, currency_code, recipient1_narration);
        recepient1.AddMetadata("Reason", "Early Bonus");
        var recipient2_account = new BankAccount(recipient2_account_number, recipient2_bank_code, recipient2_account_name);
        var recipient2 = new BankTransferRecipients(recipient2_amount, recipient2_account, currency_code, recipient2_narration);
        recipient2.AddMetadata("Reason", "Big Wins");
        IList<BankTransferRecipients> recipients = new List<BankTransferRecipients>
                                                       {
                                                           recepient1,
                                                           recipient2
                                                       };
        try
        {
            // Responds with BankTransferResults object that contans:
            // An IList object called Entries and a ToString() method
           BankTransferResults res = gateway.BankTransfer(productname, recipients);
            Console.WriteLine(res.Entries.ToString());
        }
        catch (AfricasTalkingGatewayException e)
        {
            Console.WriteLine("We had issues: " + e.Message);
        }

        Console.ReadLine();

#### OTP Validation [Banking](http://docs.africastalking.com/bank/validate) and [Card](http://docs.africastalking.com/card/validate) 
> Checkout Validation APIs allow your application to validate bank/card charge requests that deduct money from a customer's bank account.

 > Card Validation

- `ValidateCardOtp(transactionId, otp)` :  Payment Card Checkout Validation APIs allow your application to validate card charge requests that deduct money from a customer's Debit or Credit Card. [More info](http://docs.africastalking.com/card/validate) 

    - `transactionId` :This value identifies the transaction that your application wants to validate. This value is contained in the response  to the charge request. `REQUIRED`   
    - `otp` :  This contains the One Time Password that the card issuer sent to the client that owns the payment card. `REQUIRED`.  

 > Bank Validation

- `OtpValidate(transactionId, otp)`: Bank Account checkout Validation APIs allow your application to validate bank charge requests that deduct money from a customer's bank account. [More info](http://docs.africastalking.com/bank/validate).
     - `transactionId` :This value identifies the transaction that your application wants to validate. This value is contained in the response  to the charge request. `REQUIRED`   
     - `otp` :  This contains the One Time Password that the card issuer sent to the client that owns the payment card. `REQUIRED`.  

> Example 
```c#  
// ....CARD
   var gateway = new AfricasTalkingGateway(Username, ApiKey);
            try
            {
                var validate = gateway.ValidateCardOtp(TransactionId, Otp);
                var res = JsonConvert.DeserializeObject(validate);
                if (res["status"] == "Success")
                {
                    Console.WriteLine("Awesome");
                }
                else
                {
                    Console.WriteLine("We had an error " + res["status"]);
                }
            }
            catch (AfricasTalkingGatewayException e)
            {
                Console.WriteLine("Validation Error occured : " + e.Message);
            }
            // ...
// ....BANKING
   var gateway = new AfricasTalkingGateway(Username, ApiKey);

                try
                {
                    var valid = gateway.OtpValidate(transId, Otp);
                    valid = JsonConvert.DeserializeObject(valid);
                    if (valid["status"] == "Success")
                    {
                        Console.WriteLine("Whoooohoo...");
                    }
                }
                catch (AfricasTalkingGatewayException e)
                {
                    Console.WriteLine("Yikes: " + e.Message + e.StackTrace);
                }
            // ...

Card Checkout

Example


const string Username = "sandbox";
const string Otp = "1234";
const string ApiKey = "Key";
var transactionId = "id";
var gateway = new AfricasTalkingGateway(Username, ApiKey);
const string ProductName = "awesomeproduct";
const string CurrencyCode = "NGN";
const decimal Amount = 7500.50M;
const string Narration = "Buy Aluku Records";
var metadata = new Dictionary<string, string>
{
{ "Parent Company",  "Offering Records" },
{ "C.E.O", "Boddhi Satva" }
};
const short CardCvv = 123;
const string CardNum = "123456789012345";
const string CountryCode = "NG";
const string CardPin = "1234";
const int ValidTillMonth = 9;
const int ValidTillYear = 2019;
var cardDetails = new PaymentCard(CardPin, CountryCode, CardCvv, ValidTillMonth, ValidTillYear, CardNum);
        try
        {
            // 1. Perform a card Checkout, recive the Tranasaction ID then,
            // 2. validate against this OTP
            var checkout = gateway.CardCheckout(
                ProductName,
                cardDetails,
                CurrencyCode,
                Amount,
                Narration,
                metadata);
            /** Expect
             * {
                "status": "PendingValidation",
                "description": "Waiting for user input",
                "transactionId": "ATPid_SampleTxnId123"
                }
             * 
             */
            if (checkout.Status == "PendingValidation")
            {
                transactionId = resObject["transactionId"];
                // Go ahead and validate with the OTP
                Console.WriteLine(transactionId);
            }
        }
        catch (AfricasTalkingGatewayException e)
        {
            Console.WriteLine("We encountred issues : " + e.Message + e.StackTrace);
            throw;
        }

        Console.WriteLine("Attempting to Validate");

        try
        {
            var validate = gateway.ValidateCardOtp(transactionId, Otp);
            var res = JsonConvert.DeserializeObject(validate);
            if (res["status"] == "Success")
            {
                Console.WriteLine("Awesome");
            }
            else
            {
                Console.WriteLine("We had an error " + res["status"]);
            }
        }
        catch (AfricasTalkingGatewayException e)
        {
            Console.WriteLine("Validation Error occured : " + e.Message);
            throw;
        }

        Console.ReadLine();
#### [WalletTransfer](http://docs.africastalking.com/payments/wallettransfer) 
> This feature allows you to transfer money between Africas's Talking hosted products 

- `WalletTransfer( poductName, targetProductCode, currencyCode, amount, metadata)`:
    - `productName`: Your Africa's Talking Payment product to initiate this transaction. `REQUIRED`.
    - `targetProductCode`: Unique product code of the Africa's Talking Payment Product to transfer the funds to. `REQUIRED`.
    - `currencyCode`:  3-digit ISO format currency code for the value of this transaction (e.g KES, UGX, USD, ...). `REQUIRED`.
    - `amount`:  Amount - in the provided currency - that the application will be topped up with. `REQUIRED`.
    - `metadata`: A Map of any metadata that you would like us to associate with the request. `REQUIRED`.

```csharp 
StashResponse stashResponse = gateway.WalletTransfer(productName, productCode, currencyCode, amount, metadata);
// StashResponse is an object that contains the following properties:
// StashResponse.Status
// StashResponse.TransactionId
// StashResponse.Description
// And a ToString() method

TopUpStash

Topup stash APIs allow you to move money from a Payment Product to an Africa's Talking application stash. An application stash is the wallet that funds your service usage expences

FindTransaction

This functionality allows you to find a particular payment transaction by it's ID.

var findId = gateway.FindTransaction(transactionId); 

 // ... Unmarshall as so
JObject findIdObject = JObject.Parse(findId);
 // ...

FetchProductTransactions

This feature allows you to fetch transactions of a particular payment product.

Note, for the filters (except for startDate and endDate which can be passed simultaneously) you can only use one filter for any given query, otherwise your query will return an empty set. Pass null for those that you wont need.

// Without filters 
string fetchTransactionsResponse = gateway.FetchProductTransactions(productName, pageNumber,count);
JObject fetchTransactionsResponseJson = JObject.Parse(fetchTransactionsResponse); 
// With filters (Date)
const string productName = "coolproduct";
const string pageNumber = "1";
const string count = "3";
DateTime today = DateTime.Today;           
string startDate = today.ToString("yyyy-MM-dd");
string endDate = today.ToString("yyyy-MM-dd");
string fetchTransactionsResponse = gateway.FetchProductTransactions(productName, pageNumber,count, startDate, endDate);

FetchWalletTransactions

This feature allows you to fetch your wallet transactions.

Note, for the filters (except for startDate and endDate which can be passed simultaneously) you can only use one filter for any given query, otherwise your query will return an empty set. Pass null for those that you wont need.

// Without filters 
string fetchTransactionsResponse = gateway.FetchWalletTransactions(pageNumber,count);
JObject fetchTransactionsResponseJson = JObject.Parse(fetchTransactionsResponse); 
// With filters (Date)
const string productName = "coolproduct";
const string pageNumber = "1";
const string count = "3";
DateTime today = DateTime.Today;           
string startDate = today.ToString("yyyy-MM-dd");
string endDate = today.ToString("yyyy-MM-dd");
string fetchTransactionsResponse = gateway.FetchWalletTransactions(pageNumber,count, startDate, endDate);

FetchWalletBalance

This feature allows you to fetch your current wallet balance.

string fetchBalanceResponse = _atGWInstance.FetchWalletBalance();
JObject fetchBalanceResponseJson = JObject.Parse(fetchBalanceResponse);

USSD Push

A few things to note about USSD:


            const string Username = "sandbox";
            const string Apikey = "Key";
            var gateway = new AfricasTalkingGateway(Username, Apikey);
            string tokenId = "tkn";
            const string PhoneNumber = "+236XXXXXXXXX";
            const string Menu = "CON You're about to love C#\n1.Accept my fate\n2.No Never\n";

            // Let's create a checkout token  first
            try
            {
                var tkn = gateway.CreateCheckoutToken(PhoneNumber);
                if (tkn["description"] == "Success")
                {
                    tokenId = tkn["token"];
                }

                // Then send user menu...
                var prompt = gateway.InitiateUssdPushRequest(PhoneNumber, Menu, tokenId);
                if (prompt["errorMessage"] == "None")
                {
                    Console.WriteLine("Awesome");
                }
            }
            catch (AfricasTalkingGatewayException e)
            {
                Console.WriteLine("Woopsies : " + e.Message);
            }

            Console.ReadLine(); 

Expected Results

ussdPush

Building a USSD Application

  1. Start by creating a new Web ASP.NET project from any Visual Studio IDE instance Create Application

  2. Select an Empty ASP.NET template and Ensure you have selected WebAPI as part of project options Select Template

  3. On your newly created application, navigate to Solution Explorer and right-click on the Controllers folder to add/create a new Controller Create Controller

  4. From the resulting context menu, select Add>Controller Click to Add Controller

  5. Go ahead and select the Web API 2 Controller -Empty Controller template from the Controller scaffold menu Select Web API 2 Empty Controller

  6. Rename your Controller Name Your Controller

  7. Now, in our USSDServiceController , go ahead and paste the following code

    using System;
    using System.Net;
    using System.Net.Http;
    using System.Text;
    using System.Web.Http;
    
    namespace USSDDemo.Controllers
    {
       [RoutePrefix("application/services")] // Your Application will be served as http(s)://<host>:port/application/services/...
       public class USSDServiceController : ApiController
       {
           [Route("ussdservice")]  // http(s)://<host>:port/application/services/ussdservice
           [HttpPost,ActionName("ussdservice")]
    
           public HttpResponseMessage httpResponseMessage([FromBody] UssdResponse ussdResponse)
           {
               HttpResponseMessage responseMessage;
               string response;
    
               if (ussdResponse.text == null)
               {
                   ussdResponse.text = "";
               }
    
               if (ussdResponse.text.Equals("",StringComparison.Ordinal))
               {
                   response = "CON USSD Demo in Action\n";
                   response += "1. Do something\n";
                   response += "2. Do some other thing\n";
                   response += "3. Get my Number\n";
               }
               else if (ussdResponse.text.Equals("1",StringComparison.Ordinal))
               {
                   response = "END I am doing something \n";
               }else if (ussdResponse.text.Equals("2",StringComparison.Ordinal))
               {
                   response = "END Some other thing has been done \n";
               }else if (ussdResponse.text.Equals("3",StringComparison.Ordinal))
               {
                   response = $"END Here is your phone number : {ussdResponse.phoneNumber} \n";
               }
               else
               {
                   response = "END Invalid option \n";
               }
    
               responseMessage = Request.CreateResponse(HttpStatusCode.Created,response);
    
               responseMessage.Content = new StringContent(response, Encoding.UTF8, "text/plain");
    
               return responseMessage;
           }
       }
    }
    

    This code basically gives you 3 menus :, you can create more complex logic as you wish, also , as a hack, for deeper level menus use the * symbol to separate between levels and sub-levels (menus and submenus). Eg Level1>Sublevel1>Sub-sublevel1 can be represented as 1*1*1 e.t.c.

    We also have a class UssdResponse as part of our controllers that makes getters and setters for whatever payload we receive from the server. It should look as so:

    namespace USSDDemo.Controllers
    {
       public class UssdResponse
       {
           public string text { get; set; }
           public string phoneNumber { get; set; }
           public string sessionId { get; set; }
           public string serviceCode { get; set; }
    
       }
    }

    To wrap up our project, ensure you have at least

    Project Structure

  8. Build and Run

    1. Your application will be served as http(s)://<host>:port/application/services/ussdservice

    2. You can use Postman to test your USSD application as well Postman Sample

      In Postman request body, send "text":"1" for example and see the results.