The Top-up API lets your own app, website or system add credits to your Yoola SMS account without logging in to Yoola SMS. Your system asks us to start a Mobile Money payment on a phone, the person approves it with their PIN, and the credits are added to your account automatically.
POST /topup with the amount and the paying phone.GET /topup-status and sees successful.Base URL: https://yoolasms.com/api/v1. Works for Uganda (UGX) accounts with MTN and Airtel Mobile Money.
The Top-up API is switched on for approved accounts only. Send a request with your account email and a few details about your business. We review it and email you the decision, usually within 1 to 2 working days. Until it is switched on, the API replies topup_api_not_enabled.
Your API key is the same key you already use to send SMS. Find it on the API page of your account.
api_key inside a mobile app, a web page or any JavaScript that people can open.client_ref, your own unique reference for the payment (for example your invoice number). If your system retries, the same client_ref never sends a second prompt.successful. A prompt being sent does not mean the person paid.amount is what is added to your balance. Sending 50,000 charges the phone 50,252.https://yoolasms.com/api/v1/topup — send JSON (Content-Type: application/json) or normal form fields.
| Field | Required | Description |
|---|---|---|
api_key | Yes | Your Yoola SMS API key. |
amount | Yes | Whole UGX to add to your balance. Minimum 2,500. Maximum 2,000,000 per payment unless we set a different limit for you. |
phone | Yes | MTN or Airtel number that will pay, for example 0771234567. The forms +256771234567 and 256771234567 also work. |
client_ref | Recommended | Your reference, up to 40 characters: letters, numbers and - _ . |
curl -X POST https://yoolasms.com/api/v1/topup \
-H "Content-Type: application/json" \
-d '{"api_key":"YOUR_KEY","amount":50000,"phone":"0771234567","client_ref":"INV-1001"}'
Success (HTTP 200):
{
"status": "success",
"message": "Payment prompt sent to 0771***567. Approve it on the phone to receive the credits. Check /topup-status for the result.",
"ref": "YOOLA-1762345678-4821",
"payment_status": "pending",
"amount": 50000,
"currency": "UGX",
"charge_amount": 50252,
"fee": 252,
"client_ref": "INV-1001",
"created_at": "2026-11-05T09:30:12+00:00",
"code": 200
}
Keep ref (ours) and your client_ref. Either one works with /topup-status. If you send a client_ref you already used, nothing new is sent: you get the original payment back with "duplicate": true.
unconfirmed: we could not confirm the prompt was sent. Do not send it again. Check /topup-status after a minute: if the person received and approved a prompt, it still credits.https://yoolasms.com/api/v1/topup-status — send your api_key and one of ref or client_ref.
curl "https://yoolasms.com/api/v1/topup-status?api_key=YOUR_KEY&client_ref=INV-1001"
{
"status": "success",
"message": "OK",
"ref": "YOOLA-1762345678-4821",
"payment_status": "successful",
"amount": 50000,
"currency": "UGX",
"client_ref": "INV-1001",
"created_at": "2026-11-05T09:30:12+00:00",
"credits_balance": 2778,
"money_balance": 50000,
"code": 200
}
payment_status | Meaning |
|---|---|
pending | Waiting for the person to approve on their phone. |
successful | Paid, and the credits are added. |
failed | Declined, cancelled, or not enough money. Start a new payment with a new client_ref. |
expired | Nobody approved within 30 minutes. If it is approved later it still credits and changes to successful. |
With no ref or client_ref you get your most recent API top-ups (default 10; add limit=1 to 20). created_at is in UTC.
How often to check: every 5 to 10 seconds for about 2 minutes after you start the payment, then every few minutes, with a final check at 30 minutes. Do not check faster.
Every reply has status, message and code. Read the status word in your code, and show the message to a person if you need to.
| HTTP | status | What to do |
|---|---|---|
| 200 | success | Done. If "duplicate": true, this client_ref was used before. |
| 202 | unconfirmed | Do not resend. Check /topup-status after a minute. |
| 400 | missing | api_key is missing. |
| 403 | invalidkey | Wrong API key. |
| 403 | not_active | The account is not active. Contact support. |
| 403 | topup_api_not_enabled | The Top-up API is not switched on for your account. Request access. |
| 403 | not_available | Only Uganda (UGX) accounts can use it. |
| 404 | not_found | No top-up with that reference on your account. |
| 405 | method_not_allowed | Use POST for /topup. |
| 409 | duplicate_in_progress | That client_ref is being processed right now. Wait a few seconds and check /topup-status. |
| 422 | invalid_amount, amount_too_low, amount_too_high, invalid_phone, invalid_client_ref | Fix the input. min or max is returned where it applies. |
| 429 | rate_limit, too_many_pending, phone_busy | Too many requests, too many unanswered prompts, or that phone was just prompted. Wait, then try again. |
| 500 | error | We could not record the payment, so nothing was sent. Safe to retry. |
| 502 | provider_error | The mobile money network refused the prompt (for example a wrong number). Safe to retry with the same client_ref. |
| 503 | not_configured | Not ready. Contact support. |
These protect your account and ours.
| Limit | Value |
|---|---|
| Amount per payment | UGX 2,500 to 2,000,000 (your own maximum may differ) |
Calls to /topup | 10 per minute |
| Payment prompts started | 6 per hour and 20 per day |
| Prompts waiting for approval at once | 2 |
| Same phone prompted again | after 2 minutes |
Calls to /topup-status | 30 per minute |
Need to add a very large amount? Ask us for a bank transfer instead. It avoids mobile money limits and fees.
$ch = curl_init('https://yoolasms.com/api/v1/topup');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
CURLOPT_POSTFIELDS => json_encode([
'api_key' => getenv('YOOLA_KEY'),
'amount' => 50000,
'phone' => '0771234567',
'client_ref' => 'INV-1001',
]),
]);
$res = json_decode(curl_exec($ch), true);
if (($res['status'] ?? '') === 'success') {
// save $res['ref'], then poll /topup-status until payment_status is successful
}
const r = await fetch('https://yoolasms.com/api/v1/topup', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
api_key: process.env.YOOLA_KEY,
amount: 50000,
phone: '0771234567',
client_ref: 'INV-1001',
}),
});
const data = await r.json();
if (data.status === 'success') { /* poll /topup-status */ }
import os, requests
r = requests.post('https://yoolasms.com/api/v1/topup', json={
'api_key': os.environ['YOOLA_KEY'],
'amount': 50000,
'phone': '0771234567',
'client_ref': 'INV-1001',
})
print(r.json())
async function waitForPayment(clientRef) {
for (let i = 0; i < 20; i++) { // about 2 minutes
await new Promise(ok => setTimeout(ok, 6000));
const u = `https://yoolasms.com/api/v1/topup-status?api_key=${process.env.YOOLA_KEY}&client_ref=${clientRef}`;
const d = await (await fetch(u)).json();
if (d.payment_status === 'successful') return true;
if (d.payment_status === 'failed') return false;
}
return null; // still pending: check again later
}
Within seconds of the person approving the prompt, once the mobile money network confirms it.
Wait a minute and check again. If it is still pending after a few minutes, email support@yoolasms.com with the ref and we will check it with the mobile money network.
Any MTN or Airtel Mobile Money number can pay into your account. Make sure the person agrees to the amount before you send the prompt.
Not yet. It is for Uganda (UGX) accounts.
Mobile money has per-payment and daily limits and a 0.5% fee. For very large amounts, ask us for a bank transfer instead.
Write to support@yoolasms.com or call +256 704 487 563. Don't have access yet? Request it here.