Hosted checkouts
Create a payment link your customer opens to pay you by mobile money.
A hosted checkout is a payment page iSmartPay runs for you. You create it, send its link to the customer, and they pay on the page by mobile money.
Hosted checkout belongs to the iSmartPay merchant console. The API passes your requests on to it.
Before you start
- Your business needs a profile on the merchant console.
- An owner must turn on hosted checkout there. Until then, creating a checkout is refused with
409 checkout_not_enabled. - Your business needs verification tier 2.
Create
POST /v1/checkouts
Idempotency-Key: inv-2210
{
"reference": "inv-2210",
"amountType": "fixed",
"amount": "250.00",
"currency": "GHS",
"usage": "single",
"description": "Invoice 2210",
"successUrl": "https://shop.example.com/paid",
"cancelUrl": "https://shop.example.com/cart",
"expiresInMinutes": 60
}
referenceis yours, and unique for each checkout. A reference already taken is409 checkout_reference_taken.currencyisGHS. Amounts have two decimal places.descriptionis at most 140 characters.environmentis optional. Leave it out. If you send one that is not this API’s, you get422 environment_mismatch.
Amount
fixed(the default). Sendamount. The customer pays exactly that.open. The customer picks the amount. Leaveamountout. You can setminAmount,maxAmountand up to foursuggestedAmounts.
Usage and expiry
usage |
Behaviour | expiresInMinutes |
|---|---|---|
single (default) |
Closes after one payment. | 5 to 10080. Defaults to 60. null is refused. |
reusable |
Stays open and takes many payments. | 5 to 525600, or leave it out for no expiry. |
A 201 returns the checkout:
{
"id": "6f0c2d4e-8a1b-4c3d-9e5f-1a2b3c4d5e6f",
"reference": "inv-2210",
"amountType": "fixed",
"amount": "250.00",
"minAmount": null,
"maxAmount": null,
"suggestedAmounts": [],
"usage": "single",
"currency": "GHS",
"description": "Invoice 2210",
"environment": "test",
"status": "open",
"url": "https://pay.example.com/c/...",
"successUrl": "https://shop.example.com/paid",
"cancelUrl": "https://shop.example.com/cart",
"expiresAt": "2026-10-05T11:00:00Z",
"paidAt": null,
"collectionReference": null,
"paymentsCount": 0,
"totalCollected": "0.00",
"createdAt": "2026-10-05T10:00:00Z"
}
Share the url with the customer. It carries a secret, so send it only to the payer.
Statuses
| Status | Meaning |
|---|---|
open |
Waiting for payment. |
paid |
Paid. Single checkouts only. |
expired |
Not paid in time. |
cancelled |
You cancelled it. |
A checkout becomes paid only when the payment succeeds. A reusable checkout stays open after each payment and is never paid. Watch paymentsCount and totalCollected instead. totalCollected counts settled payments only.
Read and list
GET /v1/checkouts/{checkoutId} returns one checkout with its attempts: each payment attempt, with the payer’s number masked. A checkoutId that is not a UUID is 400. Another business’s checkout is 404.
GET /v1/checkouts lists your checkouts in this environment, newest first.
statusfilters by status.limitis 1 to 50. It defaults to 20.- Pass
nextCursorback unchanged ascursorfor the next page. HerenextCursoris an empty string on the last page.
Cancel
POST /v1/checkouts/{checkoutId}/cancel
Idempotency-Key: inv-2210-cancel
You can cancel an open checkout that has no payment in progress. Otherwise you get 409 checkout_not_open.
Knowing when it is paid
There are no checkout webhooks. A paid checkout shows up as a collection: in collection.* webhooks, in GET /v1/events and in GET /v1/transactions. collectionReference on the checkout, and on each attempt, names that collection. You can also poll the checkout.
Permissions
| To | The key needs |
|---|---|
| Create or cancel | collections.write |
| List or read | collections.read |
Errors
The checkout service’s 4xx answers come back unchanged. As well as the common errors, you may see:
| Status | Code | What to do |
|---|---|---|
| 409 | checkout_not_enabled |
Hosted checkout is off. An owner turns it on in the merchant console. |
| 409 | checkout_not_open |
The checkout is not open, or a payment is in progress. Read it to see its status. |
| 409 | checkout_reference_taken |
Use a new reference. |
| 422 | environment_mismatch |
Leave environment out, or send this API’s. |
| 502 | internal |
The checkout service failed or could not be reached. Retry with the same Idempotency-Key and body. |
| 503 | checkout_unavailable |
Hosted checkout is not available right now. Try again later. |
| 504 | upstream_timeout |
No answer within 30 seconds. Retry with the same Idempotency-Key and body, or list your checkouts to see if it was made. |