USSD purchase API

The WIG (Wallet Initiation Gateway) endpoints for USSD-driven payments, balance queries, and card lookups.

The WIG (Wallet Initiation Gateway) API is the set of endpoints your USSD application calls to initiate payments and balance checks from a USSD session. These endpoints are grouped under /purchase/network/* and tagged WIG API in the OpenAPI reference.

For the high-level integration overview, when-to-use, and customer flow, see USSD payment. This page is the endpoint reference.


Authentication and base URL

Value
Sandboxhttps://qa.scantopay.io/pluto
Productionhttps://scantopay.live/pluto
AuthBasic Auth or JWT Bearer, EXTERNAL role
Content-Typeapplication/json

Full auth setup is on Authentication.


Endpoint summary

OperationMethodPathUse when
Network code purchase — auto networkPOST/purchase/network/codeCustomer pays an existing Scan to Pay code via USSD; let the platform detect the customer's network from MSISDN
Network code purchase — specified networkPOST/purchase/network/{network}/codeSame as above but you already know which mobile network operator handles the customer
Network purchase — auto networkPOST/purchase/networkDirect purchase (e.g. airtime) without a pre-existing code; auto-detect network
Network purchase — specified networkPOST/purchase/network/{network}Direct purchase with explicit network
Network balance — auto networkPOST/purchase/network/balanceCustomer's wallet balance check; auto-detect network
Network balance — specified networkPOST/purchase/network/{network}/balanceBalance check with explicit network
Card lookupGET/purchase/network/cardsList the cards the customer has linked to their MSISDN — used to populate "which card?" menu in your USSD app
Strike purchasePOST/purchase/strikeRe-attempt a previous transaction using its originalTxId (failure-recovery pattern)

Auto-detect vs network-specified — pick one

The Harbour-suffixed endpoints (auto-detect) determine the customer's network from the supplied MSISDN. Use these when:

  • You don't already know the customer's network operator
  • You're operating through a USSD aggregator that doesn't surface the network identity to your application

The {network}-path endpoints take an explicit network value (e.g. MTN, VODACOM, CELLC, TELKOM). Use these when:

  • You already have the network identity from your USSD gateway integration
  • You're routing through a network-specific USSD short code
  • You want to fail fast if the customer is on an unexpected network

Both end in the same TxState machine — the difference is purely in routing.


Two payment patterns

Pattern A — Pay an existing code

Your backend has already created a Scan to Pay code (via the standard POST /code/create — see Dynamic QR). The customer's USSD session quotes that code and the API initiates payment.

curl -X POST "https://qa.scantopay.io/pluto/purchase/network/code" \
  -u "$USERNAME:$PASSWORD" \
  -H 'Content-Type: application/json' \
  -d '{
    "msisdn": "27831234567",
    "code": "0123456789"
  }'

The platform looks up the code, pushes a PIN-entry request to the customer's phone, processes the resulting authorisation, and ends with the standard webhook.

Pattern B — Direct network purchase

For airtime, data bundles, or other immediate-fulfilment products where you don't want to round-trip through /code/create first, call the network purchase endpoint directly with the basket details.

curl -X POST "https://qa.scantopay.io/pluto/purchase/network/MTN" \
  -u "$USERNAME:$PASSWORD" \
  -H 'Content-Type: application/json' \
  -d '{
    "msisdn": "27831234567",
    "amount": 50.00,
    "merchantReference": "topup-2025-05-14-00037",
    "cartItems": [
      {
        "description": "R50 airtime",
        "quantity": "1",
        "value": 50.00,
        "destination": "27831234567",
        "itemType": "AIRTIME"
      }
    ]
  }'

The cartItems array enables the platform's limit-checking machinery — see the airtime / airtime-bundle limits in the QR Code Payments business rules.


Card lookup

Before triggering a purchase, your USSD app often needs to ask the customer "which card?" — present the list of cards they've linked to their MSISDN.

curl -X GET "https://qa.scantopay.io/pluto/purchase/network/cards?msisdn=27831234567" \
  -u "$USERNAME:$PASSWORD"

Response includes the customer's linked cards with masked BIN + last 4 (no full PAN ever crosses the wire). Use the returned card IDs to drive your USSD menu, and pass the chosen card on the subsequent purchase call.


Balance check

Provides the customer's wallet balance — useful for "how much do I have left?" menus before initiating a purchase.

curl -X POST "https://qa.scantopay.io/pluto/purchase/network/balance" \
  -u "$USERNAME:$PASSWORD" \
  -H 'Content-Type: application/json' \
  -d '{
    "msisdn": "27831234567"
  }'

Strike purchase

A strike re-runs a previously-failed transaction. Use it to recover from transient failures (network blip, bank timeout) by replaying against the same originalTxId rather than creating a new transaction from scratch.

curl -X POST "https://qa.scantopay.io/pluto/purchase/strike" \
  -u "$USERNAME:$PASSWORD" \
  -H 'Content-Type: application/json' \
  -d '{
    "originalTxId": 81234,
    "msisdn": "27831234567"
  }'

The platform retains the original transaction's amount, merchant reference, and basket; only the underlying card auth attempt is re-run. The webhook fires with the new TxState as if it were a fresh attempt.


What you get back

Every USSD payment ends in the same TransactionNotificationV3 webhook payload your other channels produce. The status field uses the NotificationStatus enum, mapping from the richer USSD-specific timeout TxState values (e.g. END_TIMEOUT_PURCHASETIMEOUT_PURCHASE). See Webhooks and Transaction states.


Errors specific to USSD

CodeMeaning
433 INVALID_NETWORKThe network in the path (or auto-detected) isn't recognised. Common with unusual MNOs.
434 CLIENT_SUSPENDEDThe customer's account is suspended.
465 MISSING_MSISDNMSISDN required but not provided.
468 WIG_CNP_PURCHASE_FAIL_CARD_EXPIRY_BIN_NOT_WHIELISTUSSD CNP purchase failed: card expiry or BIN not whitelisted.
469 WIG_3DS_PURCHASE_FAIL_CARD_EXPIRY_BIN_NOT_WHIELISTUSSD 3DS purchase failed: same reasons.

Plus all the generic 4xx codes from Errors.


STK API — for MNO partners only

A separate endpoint group at /stk/* is reserved for Mobile Network Operator partners doing direct integration. It requires the STK role rather than EXTERNAL and isn't relevant for most merchants or PSPs. Endpoints include /stk/code, /stk/cards/list, /stk/cards/link, /stk/cards/delink, /stk/cards/binInfo, /stk/purchase, /stk/balance.

If you're an MNO and need access, contact [email protected].


What's next