Tutorial: bill payment
Look up a bill from your system, take a mobile money payment, and issue a token when the provider confirms it.
What you will build
An electricity bill payment. The caller enters a meter number, your billing system returns what is owed, the caller pays by mobile money, and a second call to your system issues the token. It uses three outside systems: your billing API twice and your payment provider once.
Kofi Boateng Meter 04172290188 Amount due: GHS 84.50 1. Pay now 2. Cancel
Paid. Your token is 4417-2096-5531-0082.
| Step | Type | What it does |
|---|---|---|
| Welcome | Entry Point | Offers Pay a bill or Exit. |
| Meter number | Ask a Question | Saves the answer as meter. |
| Look up bill | Send Data | Gets the customer’s name and the amount due. |
| Anything to pay? | Smart Router | Separates a bill to pay, nothing due, and an unknown meter. |
| Confirm | Choice Menu | Shows the bill; Pay now or Cancel. |
| Take payment | Collect Payment | Asks your provider to charge the caller. |
| Issue token | Send Data | Tells your billing system the bill is paid. |
| Closing screens | End Session | One for each way the session can end. |
Before you start
- An account with a payment provider (Paystack, Hubtel, Flutterwave, MTN MoMo or another), and its test key.
- A plan that includes Collect Payment for going live. You can build and test on any plan.
- You have read Payments, which explains each setting used here.
What your API needs
1. Look up a bill
{
"found": true,
"customer": "Kofi Boateng",
"amountDue": "84.50"
}For an unknown meter, answer { "found": false }.
2. Record the payment and issue a token
{
"amount": "84.50",
"phone": "233241234567",
"reference": "the-session-id"
}{ "token": "4417-2096-5531-0082" }reference as the payment's identity. If the same reference arrives twice, return the same token and credit the meter once. A request can be repeated by a retry, or arrive both from this step and from your provider's notification.Build the bill lookup
Set up the welcome screen
On the Entry Point, set the text toPowerPayand the options toPay a billandExit.Ask for the meter number
Add Ask a Question with the textEnter your meter number:. Set Save the answer as tometerand Answer type to Numeric.Look up the bill
Add Send Data, choose GET, and enter:Under Save From Response add three pairs:Addresshttps://api.example.com/meters/{{meter}}Path in the reply Save as $.foundmeterFound$.customercustomerName$.amountDueamountDueBranch on what came back
Add a Smart Router with two branches:meterFound == true AND amountDue > 0: there is a bill to pay.meterFound == true AND amountDue <= 0: the meter exists and nothing is owed.
Show the bill and ask to confirm
Add a Choice Menu with the optionsPay nowandCancel, and the text:What the phone shows{{customerName}} Meter {{meter}} Amount due: GHS {{amountDue}}
Add the payment
Add Collect Payment
Click Collect Payment. In What the phone shows, tell the caller what to do next:What the phone showsApprove the GHS {{amountDue}} prompt on your phone, then dial again for your token.Fill in the Payment section
Setting Enter Payment provider Your provider. API URL Your provider’s charge address, from its documentation. API key Your provider’s test key for now. Amount {{amountDue}}Currency GHSCallback URL Leave empty, so Asterisks receives the result. Write the request body
A new Collect Payment step already charges the dialler. Add a reference and the address the provider should report to, in the field names your provider uses:Request body{ "amount": "{{PaymentAmount}}", "currency": "{{PaymentCurrency}}", "phone": "{{MobileNumber}}", "reference": "{{SessionId}}", "callback_url": "{{PaymentCallbackUrl}}" }
| Write | Becomes |
|---|---|
{{PaymentAmount}} | What you put in Amount, here the amount due. |
{{PaymentCurrency}} | What you put in Currency. |
{{MobileNumber}} | The number that dialled. To charge a different number, ask for it in a question and use that name here. |
{{PaymentCallbackUrl}} | The address where Asterisks receives this payment’s result. |
After the payment
Collect Payment has two routes besides its usual end: PAID and FAIL. Once PAID is connected, the session is kept. The caller approves the prompt, dials your shortcode again, and carries on from here. If the provider has not reported yet, they see "We have not received your payment yet" with 1. Check again and 2. Cancel.
Issue the token
Add a second Send Data. Choose POST and enter:Addresshttps://api.example.com/meters/{{meter}}/paymentsSaveRequest body{ "amount": "{{amountDue}}", "phone": "{{MobileNumber}}", "reference": "{{SessionId}}" }$.token→token.Add the closing screens
Paid. Your token is {{token}}.We have your payment. Your token will arrive by SMS shortly.The payment was not completed. You have not been charged.Nothing is owed on this meter. Thank you.We could not find that meter. Check the number and dial again.We cannot look up bills right now. Please try again later.Goodbye.
Join the steps
| From | To |
|---|---|
| Welcome, option Pay a bill | Meter number |
| Welcome, option Exit | Goodbye. |
| Meter number | Look up bill |
| Look up bill, bottom dot | The Smart Router |
| Look up bill, FAIL | We cannot look up bills right now. |
| Router, first branch | Confirm menu |
| Router, second branch | Nothing is owed on this meter. |
| Router, ELSE | We could not find that meter. |
| Confirm, option Pay now | Take payment |
| Confirm, option Cancel | Goodbye. |
| Take payment, PAID | Issue token |
| Take payment, FAIL | The payment was not completed. |
| Issue token, bottom dot | Paid. Your token is… |
| Issue token, FAIL | We have your payment. Your token will arrive by SMS. |
Test it
Open the phone preview
Press Test in the top bar. In Dial from, type the number the test should call from, such as0241234567. Your app receives it as{{MobileNumber}}.Look up a bill
Reply1, then a meter number your API knows. Check the name and amount on the confirm screen.Pay
Reply1. The preview shows your closing message and, under the phone, the amount and the number that would be charged. Nothing is sent to your provider and nobody is charged.Choose the outcome
Press Paid to follow the PAID route: your API is called and the token appears. Dial again and press Failed to see the other ending.Try the other branches
An unknown meter, a meter that owes nothing, and Cancel on the confirm screen.
https:// and allow requests from the dashboard (CORS). On a real phone the call comes from Asterisks' servers and CORS does not apply. Testing against your laptop? An ngrok address works: the preview adds the header ngrok asks for.The preview cannot test your provider. For that, deploy the app with your provider's test key and pay from a real phone, as described in Testing.
Before you go live
- A test payment from a real phone reached PAID and produced a token.
- A declined test payment reached FAIL.
- Your billing API returns the same token when it receives the same
referencetwice. - Your provider also notifies your own system, and that system issues the token by SMS. Some callers will pay and never dial back.
- The API key is switched to your live key, and the API URL to the live address.