Skip to main content

Buying airtime and data bundles

Buy airtime with one POST to /purchases. For a data bundle, list the bundles first and buy one by its id. The response says whether the purchase succeeded, failed or is pending.

You need

  • An API key with the Airtime API turned on under Subscribed APIs, on Settings › Developers › API Keys. See API keys and base URLs.
  • Money on your balance: your test balance in the sandbox, or funds you added in live.

Buy airtime​

curl -X POST $PONITOR_BASE_URL/airtime/v1/purchases \
-H "apiKey: $PONITOR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"msisdn": "231880000000",
"amount": 5,
"externalId": "order-8842"
}'
FieldWhat to send
msisdnAn Orange or Lonestar Cell MTN number: 231880000000 or 0880000000.
amountThe airtime the number gets, in US dollars. At least 1, and at most your team's limit per recipient ($50 unless agreed otherwise).
externalIdYour own reference, unique within your team. See Retries and externalId.

Or buy a data bundle​

List the bundles on sale for the number's network:

curl "$PONITOR_BASE_URL/airtime/v1/products?carrier=LONESTAR" \
-H "apiKey: $PONITOR_API_KEY"

Then send the bundle's id as productId, instead of amount:

{
"msisdn": "231880000000",
"productId": "prod_p4nzx9xp335h",
"externalId": "order-8843"
}

You can send the bundle's code as productCode instead. See List data bundles.

Read the response​

201 Created means Ponitor accepted the purchase. Check its status: it can still be FAILED.

{
"id": "6f1c2a3e-8b4d-4c1a-9e2f-3a4b5c6d7e8f",
"externalId": "order-8842",
"type": "AIRTIME",
"msisdn": "231880000000",
"carrier": "LONESTAR",
"product": null,
"amount": 5,
"cost": 5,
"status": "SUCCESS",
"failureReason": null,
"instructions": null,
"createdAt": "2026-10-20T19:40:00.000Z"
}

Check status. A FAILED purchase also returns 201, because the request was valid but the network declined it. Its failureReason says why, and the cost is refunded. 200 OK instead means you already used this externalId, and the body is the original purchase.

What happens to a purchase​

POST /purchasesSUCCESScost chargedPENDINGcost held, settles within an hourFAILEDcost refunded
Most purchases return SUCCESS or FAILED straight away. A PENDING purchase settles when the network confirms it.
StatusMeaningYour account
SUCCESSThe airtime or bundle reached the number.Charged the cost
PENDINGThe network accepted it but hasn't confirmed it. Ponitor checks for up to an hour.cost held
FAILEDThe purchase didn't happen. failureReason says why.Refunded in full

To learn when a PENDING purchase settles, use a team webhook. It gets airtime.purchase.delivered or airtime.purchase.failed. Or call Get a purchase every 30 to 60 seconds. If a purchase is still PENDING after an hour, contact support with its id.

Why a purchase failed​

failureReason tells you what went wrong, in words: a failed purchase has no error code. The three reasons that end in "Refunded." are Ponitor's and don't change. The network's wording can change, so don't match on it exactly.

Problem withfailureReasonWhat to do
The numberThe network's wording, such as Destination is barred, Destination is inactive, Daily limit exceeded or Invalid destinationFix the number or amount. Send a new request with a new externalId.
The number already has the bundleThe network's wording, such as Already purchasedDon't retry. Choose a different bundle, or try again after the current bundle runs out.
The bundleProduct not available right now. Refunded.The network refused the bundle. It's off sale while we check it. List the bundles again and choose another.
The networkNetwork temporarily unavailable. Refunded.Try again in a few minutes.
PonitorService temporarily unavailable. Refunded.Try again later. We're alerted automatically.

Ponitor refunds the cost of every failed purchase: in its answer, or when a PENDING purchase settles as FAILED.

When a request is refused​

Ponitor refuses a request before charging anything or creating a purchase:

StatusWhyFix
400It has amount and a bundle, or neither. Or productId and productCode name different bundles.Send amount for airtime, or one bundle.
400The bundle is unknown, withdrawn, or for the other network.List the bundles again, and pick one for the number's network.
400The amount or the bundle's price is over your team's limit per recipient.Buy less, or ask us to raise the limit.
400Your balance can't cover the cost.Add funds under Billing. In the sandbox, set your test balance.
401The key is wrong, or it doesn't match the base URL.See API keys and base URLs.
403The Airtime API isn't turned on, or your team isn't approved.Check Subscribed APIs and Settings › Compliance.
500Something failed on our side. Nothing was charged.Send it again with the same externalId.

Buy airtime or data lists each message.

Try it in the sandbox​

With a sandbox key, every purchase is simulated and paid from your test balance:

Buy forWhat happens
A number ending 0001, such as 231770000001It ends as FAILED, and the cost is refunded.
A number ending 0002, such as 231770000002It stays PENDING.
Any other numberIt ends as SUCCESS.