Skip to main content

Common Issues & Solutions

The top issues integrators run into and how to fix them.

1. 401 Unauthorized After A Few Minutes

Cause: Access tokens expire after 30 minutes. If you cache a token longer than that, every subsequent call returns 401.

Fix: Refresh the token before expiry, or refresh on the first 401 and retry. See Bearer Token Management.

2. 403 Forbidden On /purchase

Cause: Only Merchant and Sub-Merchant users may call /purchase. Partner and Vendor accounts get 403.

Fix: Use Merchant-level credentials. See Access & Permissions.

3. responseCode: "1009" — Product Not Available

Cause: The product you're trying to purchase is not active under your merchant account.

Fix: Re-fetch your scoped catalog (GET /merchants/{merchantId}/products or GET /sub-merchants/{subMerchantId}/products) to confirm what's available. If the product should be active, contact your account manager. See Product Availability.

4. responseCode: "1005" — Invalid Phone Number

Cause: Mobile number not in +27... format.

Fix:

0821234567   ❌
27821234567 ❌
+27821234567 ✅

5. responseCode: "1103" — Insufficient Balance (Sandbox)

Cause: Sandbox accounts have a daily test credit cap (R10,000). Once exhausted, purchases fail until reset.

Fix: Wait for the daily reset, or contact support to top up your sandbox balance.

6. 429 Too Many Requests

Cause: You exceeded the per-endpoint rate limit (5/min for login, 10/min for refresh, 10/min for purchase).

Fix: Implement exponential backoff with jitter. See Rate Limiting.

7. Duplicate Transactions After A Network Retry

Cause: You generated a new merchantReference for each retry instead of reusing the original.

Fix: Use the same merchantReference for retries. The API will return the original transaction's result. See Idempotency & Retries.

8. Lost Track Of A Transaction's Outcome

Cause: Network timeout, app crash, or exhausted retries before receiving a terminal response.

Fix: Do not assume the transaction failed. Query POST /transactions using your merchantReference or the returned transactionId. Treat the API's status as the source of truth.


Last updated: April 2026