Appearance
Create a checkout
Opens a hosted checkout for a fixed amount. The payment goes to the account that owns the key.
POST /v1/payments/merchant/checkoutsHost: the payments host for the key's country.
Headers
| Header | Required | |
|---|---|---|
Authorization | Yes | Bearer mkp_…. See Authentication |
Idempotency-Key | Yes | 1 to 128 characters. The same key returns the same checkout. See Idempotency |
Content-Type | Yes | application/json |
Body
Unknown fields are refused.
| Field | Type | Required | |
|---|---|---|---|
amount | integer | Yes | Minor units. 150000 is 1,500.00. Minimum 1, inside the rail limits |
reference | string | No | Your order id. 1 to 64 characters. Returned to you and added to return_url. Not shown to the payer |
description | string | No | Shown to the payer. 1 to 140 characters |
return_url | string | No | Where the payer goes after a completed payment. 1 to 2048 characters. https only. Off production, http://localhost and http://127.0.0.1 are allowed |
phone | string | No | Fills the payer phone field. 9 to 15 digits, country code, no +. Example: 254712345678 |
There is no currency field. Kenya is KES. Uganda is UGX.
Example
sh
curl -X POST https://payments-ke-staging.salimia.me/v1/payments/merchant/checkouts \
-H "Authorization: Bearer $MOOKHPAY_SECRET_KEY" \
-H "Idempotency-Key: order-1042" \
-H "Content-Type: application/json" \
-d '{
"amount": 150000,
"reference": "order-1042",
"description": "2× Latte, 1× Mandazi",
"return_url": "https://yourshop.example/paid",
"phone": "254712345678"
}'js
const res = await fetch(
"https://payments-ke-staging.salimia.me/v1/payments/merchant/checkouts",
{
method: "POST",
headers: {
Authorization: `Bearer ${process.env.MOOKHPAY_SECRET_KEY}`,
"Idempotency-Key": "order-1042",
"Content-Type": "application/json",
},
body: JSON.stringify({
amount: 150000,
reference: "order-1042",
description: "2× Latte, 1× Mandazi",
return_url: "https://yourshop.example/paid",
}),
},
);python
requests.post(
"https://payments-ke-staging.salimia.me/v1/payments/merchant/checkouts",
headers={
"Authorization": f"Bearer {os.environ['MOOKHPAY_SECRET_KEY']}",
"Idempotency-Key": "order-1042",
},
json={"amount": 150000, "reference": "order-1042"},
)Response
201 Created for a new checkout. 200 OK when that Idempotency-Key already exists. The 200 body is the checkout as it is now.
json
{
"ok": true,
"description": "Checkout created",
"data": {
"id": "cs_ke_3f9a1c7e5b2d4a8e6c0b91d7",
"url": "https://…/checkout/cs_ke_3f9a1c7e5b2d4a8e6c0b91d7",
"status": "open",
"amount": "150000",
"currency": "KES",
"reference": "order-1042",
"description": "2× Latte, 1× Mandazi",
"return_url": "https://yourshop.example/paid",
"expires_at": "2026-09-30T09:30:00.000Z",
"created_at": "2026-09-30T09:00:00.000Z",
"payment": null
}
}data is the checkout object. phone is not in this object. The payer page receives it.
Errors
| HTTP | Code | When |
|---|---|---|
400 | 1701 | A field is invalid, unknown, or missing. Idempotency-Key is missing. return_url is not a URL or is not https |
401 | 2781 | Missing, malformed, unknown, or revoked key |
409 | 2709 | The wallet is not provisioned |
422 | 2702 | amount is outside the limits, or not a whole unit where required |
422 | 2721 | Collection is off on this deployment |
429 | 1804 | More than 120 requests in one minute |
503 | 2752 | The ledger did not answer the wallet check. Retry |
503 | 2782 | The key service did not answer. Retry |
Validation (400) runs before the key check. A bad key on a bad body still returns 400. A failed validation does not open a checkout.