Skip to content

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/checkouts

Host: the payments host for the key's country.

Headers ​

HeaderRequired
AuthorizationYesBearer mkp_…. See Authentication
Idempotency-KeyYes1 to 128 characters. The same key returns the same checkout. See Idempotency
Content-TypeYesapplication/json

Body ​

Unknown fields are refused.

FieldTypeRequired
amountintegerYesMinor units. 150000 is 1,500.00. Minimum 1, inside the rail limits
referencestringNoYour order id. 1 to 64 characters. Returned to you and added to return_url. Not shown to the payer
descriptionstringNoShown to the payer. 1 to 140 characters
return_urlstringNoWhere 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
phonestringNoFills 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 ​

HTTPCodeWhen
4001701A field is invalid, unknown, or missing. Idempotency-Key is missing. return_url is not a URL or is not https
4012781Missing, malformed, unknown, or revoked key
4092709The wallet is not provisioned
4222702amount is outside the limits, or not a whole unit where required
4222721Collection is off on this deployment
4291804More than 120 requests in one minute
5032752The ledger did not answer the wallet check. Retry
5032782The 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.

Staging documentation. Staging charges real money. See Environments.