Skip to content
iSmartPay Developers
Esc
↑↓navigate↵open⌘Jpreview

Buy airtime or data

Buys an airtime or data product for a mobile number. With wallet funding the total is taken from your wallet and given back if the sale fails. With collection funding the payer first approves a mobile money prompt, nothing is sold until they pay, and they are refunded in full if the sale fails.

A 202 means the purchase was accepted, not that it was delivered. Read GET /v1/utility-purchases/{reference} for the outcome. outcome_unknown means the result was not clear: the money is held, nothing is sold again, and iSmartPay resolves it.

The reference is yours and must be unique for each purchase. Send a required Idempotency-Key header and repeat it unchanged when you retry. After a timeout or a 5xx, retry with the same key and body: never start a second purchase with a new reference, or you may buy twice. Requires the disbursements.write permission.

POST/v1/utility-purchases
Authorization
AuthorizationBearer token (JWT) · headerrequired

A token from POST /v1/oauth/token on the iSmartPay identity service, obtained with an API credential's client id and secret.

Header parameters
Idempotency-Keystringrequired

A unique value you generate for this attempt, at most 255 characters. Send the same value when you retry the same request: it is answered once, however many times you send it. Reusing a value with a different body is refused with 409 idempotency_key_reused.

min length 1 · max length 255
Request body
requiredapplication/json
referencestringrequired

Your own identifier for this purchase, 1 to 64 letters, digits, underscores or hyphens, starting with a letter or digit. It must be unique for each purchase.

matches ^[A-Za-z0-9][A-Za-z0-9_-]{0,63}$
productIdstringrequired

The product's id from GET /v1/utility-products.

amountstringrequired

The amount to buy. For a fixed product, its price. A decimal string in major units.

currencystringrequired

Three-letter currency code. Only GHS is sold.

matches ^[A-Z]{3}$
beneficiaryobjectrequired
Show properties
msisdnstringrequired

The number that receives the airtime or data. In international format without the plus, for example 233244123456.

fundingobjectrequired

How the purchase is paid for. wallet takes the total from your wallet and needs no payer. collection asks the payer to approve a mobile money prompt first, and needs one.

Show properties
typestringrequired
Allowed:walletcollection
payerobject
Show properties
providerstringrequired

The payer's mobile money provider.

Allowed:mtntelecel
msisdnstringrequired

The payer's mobile money number. In international format without the plus, for example 233244123456.

Responses
202

Accepted. The product has not been delivered yet.

referencestringrequired

The reference you chose.

statusstringrequired

Where the purchase stands, reported as it is: accepted, awaiting_payment, vending, delivered, failed, refunding, refunded, refund_failed or outcome_unknown. delivered, failed and refunded are final. outcome_unknown and refund_failed are resolved by iSmartPay: do not buy again with a new reference.

productobject
Show properties
idstring
categorystring
networkstring
namestring
beneficiaryobject
Show properties
msisdnstring
amountstring

The amount bought. A decimal string in major units.

currencystring

Three-letter currency code. Only GHS is sold.

matches ^[A-Z]{3}$
feestring

The fee charged. Left out when none was recorded. A decimal string in major units.

grossstring

The amount plus the fee. Left out when no fee was recorded. A decimal string in major units.

fundingobject
Show properties
typestring
Allowed:walletcollection
payerobject
Show properties
providerstring
msisdnstring
failureReasonstring

Why the purchase failed, for example vend_failed or insufficient_balance. Left out otherwise.

createdAtstring<date-time>
400

The request is not valid. message says which field.

errorobjectrequired
Show properties
codestringrequired

A stable, machine-readable code. Branch on this, not on the message. Codes include invalid_input, unauthenticated, forbidden, environment_mismatch, not_found, rate_limited, idempotency_key_reused, request_in_flight, limits_missing, limits_unusable, tier_ineligible, transaction_limit_exceeded, daily_limit_exceeded, monthly_limit_exceeded, business_suspended, business_deactivated, environment_unknown, duplicate_reference, provider_error, provider_timeout, destination_not_verified, destination_verification_unavailable, upstream_timeout and internal.

messagestringrequired

Readable detail for a person. For any 5xx it is always the fixed text internal server error.

401

The token is missing, expired or not valid. Get a new one from the token endpoint.

errorobjectrequired
Show properties
codestringrequired

A stable, machine-readable code. Branch on this, not on the message. Codes include invalid_input, unauthenticated, forbidden, environment_mismatch, not_found, rate_limited, idempotency_key_reused, request_in_flight, limits_missing, limits_unusable, tier_ineligible, transaction_limit_exceeded, daily_limit_exceeded, monthly_limit_exceeded, business_suspended, business_deactivated, environment_unknown, duplicate_reference, provider_error, provider_timeout, destination_not_verified, destination_verification_unavailable, upstream_timeout and internal.

messagestringrequired

Readable detail for a person. For any 5xx it is always the fixed text internal server error.

403

The request was understood and refused. Common causes: the token is not an API credential's (forbidden); the credential is for the other environment (environment_mismatch); it does not have the permission this operation needs (forbidden); a limit was reached (limits_missing, limits_unusable, tier_ineligible, transaction_limit_exceeded, daily_limit_exceeded, monthly_limit_exceeded); or iSmartPay has suspended or deactivated the business (business_suspended, business_deactivated). A suspended business's API credentials stop exchanging for tokens, so a request made with a token issued just before the suspension is refused with business_suspended.

errorobjectrequired
Show properties
codestringrequired

A stable, machine-readable code. Branch on this, not on the message. Codes include invalid_input, unauthenticated, forbidden, environment_mismatch, not_found, rate_limited, idempotency_key_reused, request_in_flight, limits_missing, limits_unusable, tier_ineligible, transaction_limit_exceeded, daily_limit_exceeded, monthly_limit_exceeded, business_suspended, business_deactivated, environment_unknown, duplicate_reference, provider_error, provider_timeout, destination_not_verified, destination_verification_unavailable, upstream_timeout and internal.

messagestringrequired

Readable detail for a person. For any 5xx it is always the fixed text internal server error.

404

Nothing was found with that reference or number. For utilities, product_not_found means no product has that productId.

errorobjectrequired
Show properties
codestringrequired

A stable, machine-readable code. Branch on this, not on the message. Codes include invalid_input, unauthenticated, forbidden, environment_mismatch, not_found, rate_limited, idempotency_key_reused, request_in_flight, limits_missing, limits_unusable, tier_ineligible, transaction_limit_exceeded, daily_limit_exceeded, monthly_limit_exceeded, business_suspended, business_deactivated, environment_unknown, duplicate_reference, provider_error, provider_timeout, destination_not_verified, destination_verification_unavailable, upstream_timeout and internal.

messagestringrequired

Readable detail for a person. For any 5xx it is always the fixed text internal server error.

409

idempotency_key_reused: the key was used before with a different body. request_in_flight: a request with this key is still being processed, so retry shortly. duplicate_reference: the reference is already used by a different request, so choose a new one; sending the same body again under a new key replays the first answer.

errorobjectrequired
Show properties
codestringrequired

A stable, machine-readable code. Branch on this, not on the message. Codes include invalid_input, unauthenticated, forbidden, environment_mismatch, not_found, rate_limited, idempotency_key_reused, request_in_flight, limits_missing, limits_unusable, tier_ineligible, transaction_limit_exceeded, daily_limit_exceeded, monthly_limit_exceeded, business_suspended, business_deactivated, environment_unknown, duplicate_reference, provider_error, provider_timeout, destination_not_verified, destination_verification_unavailable, upstream_timeout and internal.

messagestringrequired

Readable detail for a person. For any 5xx it is always the fixed text internal server error.

422

The purchase cannot be made as asked: product_not_sellable (the product is not on sale now), amount_out_of_range (outside the product's price, min or max), currency_not_supported (only GHS is sold), beneficiary_invalid (the product cannot be sold to this number) or fee_unpriceable (the fee cannot be worked out right now; retry later).

errorobjectrequired
Show properties
codestringrequired

A stable, machine-readable code. Branch on this, not on the message. Codes include invalid_input, unauthenticated, forbidden, environment_mismatch, not_found, rate_limited, idempotency_key_reused, request_in_flight, limits_missing, limits_unusable, tier_ineligible, transaction_limit_exceeded, daily_limit_exceeded, monthly_limit_exceeded, business_suspended, business_deactivated, environment_unknown, duplicate_reference, provider_error, provider_timeout, destination_not_verified, destination_verification_unavailable, upstream_timeout and internal.

messagestringrequired

Readable detail for a person. For any 5xx it is always the fixed text internal server error.

429

Too many requests for this credential. Wait the number of seconds in the Retry-After header, then try again.

errorobjectrequired
Show properties
codestringrequired

A stable, machine-readable code. Branch on this, not on the message. Codes include invalid_input, unauthenticated, forbidden, environment_mismatch, not_found, rate_limited, idempotency_key_reused, request_in_flight, limits_missing, limits_unusable, tier_ineligible, transaction_limit_exceeded, daily_limit_exceeded, monthly_limit_exceeded, business_suspended, business_deactivated, environment_unknown, duplicate_reference, provider_error, provider_timeout, destination_not_verified, destination_verification_unavailable, upstream_timeout and internal.

messagestringrequired

Readable detail for a person. For any 5xx it is always the fixed text internal server error.

500

Something failed on our side. The message is fixed. If the request was a POST, retry with the same Idempotency-Key and body.

errorobjectrequired
Show properties
codestringrequired

A stable, machine-readable code. Branch on this, not on the message. Codes include invalid_input, unauthenticated, forbidden, environment_mismatch, not_found, rate_limited, idempotency_key_reused, request_in_flight, limits_missing, limits_unusable, tier_ineligible, transaction_limit_exceeded, daily_limit_exceeded, monthly_limit_exceeded, business_suspended, business_deactivated, environment_unknown, duplicate_reference, provider_error, provider_timeout, destination_not_verified, destination_verification_unavailable, upstream_timeout and internal.

messagestringrequired

Readable detail for a person. For any 5xx it is always the fixed text internal server error.

502

A service behind the API did not answer usably. If the request was a POST, retry with the same Idempotency-Key and body. A party lookup the provider rejects is provider_error.

errorobjectrequired
Show properties
codestringrequired

A stable, machine-readable code. Branch on this, not on the message. Codes include invalid_input, unauthenticated, forbidden, environment_mismatch, not_found, rate_limited, idempotency_key_reused, request_in_flight, limits_missing, limits_unusable, tier_ineligible, transaction_limit_exceeded, daily_limit_exceeded, monthly_limit_exceeded, business_suspended, business_deactivated, environment_unknown, duplicate_reference, provider_error, provider_timeout, destination_not_verified, destination_verification_unavailable, upstream_timeout and internal.

messagestringrequired

Readable detail for a person. For any 5xx it is always the fixed text internal server error.

503

The API is temporarily unable to tell which environment it serves (environment_unknown), utility purchases are not available right now (utilities_unavailable), a settlement destination could not be name-checked just now (destination_verification_unavailable; retry the same request), or hosted checkout is not set up on this deployment (checkout_unavailable). Retry shortly, except for checkout_unavailable, which lasts until the deployment is configured.

errorobjectrequired
Show properties
codestringrequired

A stable, machine-readable code. Branch on this, not on the message. Codes include invalid_input, unauthenticated, forbidden, environment_mismatch, not_found, rate_limited, idempotency_key_reused, request_in_flight, limits_missing, limits_unusable, tier_ineligible, transaction_limit_exceeded, daily_limit_exceeded, monthly_limit_exceeded, business_suspended, business_deactivated, environment_unknown, duplicate_reference, provider_error, provider_timeout, destination_not_verified, destination_verification_unavailable, upstream_timeout and internal.

messagestringrequired

Readable detail for a person. For any 5xx it is always the fixed text internal server error.

504

The request took too long. If it was a POST, its outcome is unknown: retry with the same Idempotency-Key and body, or read it back by reference. A party lookup the provider does not answer is provider_timeout: check again before relying on it.

errorobjectrequired
Show properties
codestringrequired

A stable, machine-readable code. Branch on this, not on the message. Codes include invalid_input, unauthenticated, forbidden, environment_mismatch, not_found, rate_limited, idempotency_key_reused, request_in_flight, limits_missing, limits_unusable, tier_ineligible, transaction_limit_exceeded, daily_limit_exceeded, monthly_limit_exceeded, business_suspended, business_deactivated, environment_unknown, duplicate_reference, provider_error, provider_timeout, destination_not_verified, destination_verification_unavailable, upstream_timeout and internal.

messagestringrequired

Readable detail for a person. For any 5xx it is always the fixed text internal server error.

Request
curl -X POST 'https://api.example.com/v1/utility-purchases' \
  -H 'Authorization: Bearer YOUR_TOKEN' \
  -H 'Idempotency-Key: string' \
  -H 'Content-Type: application/json' \
  -d '{
  "reference": "string",
  "productId": "string",
  "amount": "10.00",
  "currency": "GHS",
  "beneficiary": {
    "msisdn": "233244123456"
  },
  "funding": {
    "type": "wallet",
    "payer": {
      "provider": "mtn",
      "msisdn": "233244123456"
    }
  }
}'
Response
{
  "reference": "string",
  "status": "string",
  "product": {
    "id": "string",
    "category": "string",
    "network": "string",
    "name": "string"
  },
  "beneficiary": {
    "msisdn": "string"
  },
  "amount": "10.00",
  "currency": "GHS",
  "fee": "10.00",
  "gross": "10.00",
  "funding": {
    "type": "wallet",
    "payer": {
      "provider": "string",
      "msisdn": "string"
    }
  },
  "failureReason": "string",
  "createdAt": "2019-08-24T14:15:22Z"
}