Skip to content

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
After the lookup
Paid. Your token is 4417-2096-5531-0082.
When the caller dials back after paying
StepTypeWhat it does
WelcomeEntry PointOffers Pay a bill or Exit.
Meter numberAsk a QuestionSaves the answer as meter.
Look up billSend DataGets the customer’s name and the amount due.
Anything to pay?Smart RouterSeparates a bill to pay, nothing due, and an unknown meter.
ConfirmChoice MenuShows the bill; Pay now or Cancel.
Take paymentCollect PaymentAsks your provider to charge the caller.
Issue tokenSend DataTells your billing system the bill is paid.
Closing screensEnd SessionOne 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

GET https://api.example.com/meters/04172290188
{
  "found": true,
  "customer": "Kofi Boateng",
  "amountDue": "84.50"
}

For an unknown meter, answer { "found": false }.

2. Record the payment and issue a token

POST https://api.example.com/meters/04172290188/payments
{
  "amount": "84.50",
  "phone": "233241234567",
  "reference": "the-session-id"
}
Reply
{ "token": "4417-2096-5531-0082" }
Watch out: Treat 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

  1. Set up the welcome screen

    On the Entry Point, set the text to PowerPay and the options to Pay a bill and Exit.
  2. Ask for the meter number

    Add Ask a Question with the text Enter your meter number:. Set Save the answer as to meter and Answer type to Numeric.
  3. Look up the bill

    Add Send Data, choose GET, and enter:
    Address
    https://api.example.com/meters/{{meter}}
    Under Save From Response add three pairs:
    Path in the replySave as
    $.foundmeterFound
    $.customercustomerName
    $.amountDueamountDue
  4. Branch 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.
    An unknown meter matches neither and leaves by ELSE. Write branches so that only one can be true for any caller, as these are, and their order never matters.
  5. Show the bill and ask to confirm

    Add a Choice Menu with the options Pay now and Cancel, and the text:
    What the phone shows
    {{customerName}}
    Meter {{meter}}
    Amount due: GHS {{amountDue}}
Tip: Always show the name and the amount before charging. A caller who mistyped one digit sees a stranger's name and cancels.

Add the payment

  1. Add Collect Payment

    Click Collect Payment. In What the phone shows, tell the caller what to do next:
    What the phone shows
    Approve the GHS {{amountDue}} prompt on your phone, then dial again for your token.
  2. Fill in the Payment section

    SettingEnter
    Payment providerYour provider.
    API URLYour provider’s charge address, from its documentation.
    API keyYour provider’s test key for now.
    Amount{{amountDue}}
    CurrencyGHS
    Callback URLLeave empty, so Asterisks receives the result.
  3. 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}}"
    }
WriteBecomes
{{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.

  1. Issue the token

    Add a second Send Data. Choose POST and enter:
    Address
    https://api.example.com/meters/{{meter}}/payments
    Request body
    {
      "amount": "{{amountDue}}",
      "phone": "{{MobileNumber}}",
      "reference": "{{SessionId}}"
    }
    Save $.token → token.
  2. 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

FromTo
Welcome, option Pay a billMeter number
Welcome, option ExitGoodbye.
Meter numberLook up bill
Look up bill, bottom dotThe Smart Router
Look up bill, FAILWe cannot look up bills right now.
Router, first branchConfirm menu
Router, second branchNothing is owed on this meter.
Router, ELSEWe could not find that meter.
Confirm, option Pay nowTake payment
Confirm, option CancelGoodbye.
Take payment, PAIDIssue token
Take payment, FAILThe payment was not completed.
Issue token, bottom dotPaid. Your token is…
Issue token, FAILWe have your payment. Your token will arrive by SMS.
Watch out: Mind the wording on the last row. That caller has paid. Never tell them to try again, or they will pay twice.

Test it

  1. Open the phone preview

    Press Test in the top bar. In Dial from, type the number the test should call from, such as 0241234567. Your app receives it as {{MobileNumber}}.
  2. Look up a bill

    Reply 1, then a meter number your API knows. Check the name and amount on the confirm screen.
  3. Pay

    Reply 1. 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.
  4. 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.
  5. Try the other branches

    An unknown meter, a meter that owes nothing, and Cancel on the confirm screen.
Good to know: In the preview, Send Data calls your API from your browser, so the API must be on 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 reference twice.
  • 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.