Skip to content

Quickstart ​

Create a checkout on your server. Send the payer to url. Read the checkout back before you fulfill.

Get a key ​

  1. Open the hub.
  2. Open API Integrations.
  3. Open the Keys tab.
  4. Choose Create Key.
  5. Enter your PIN.
  6. Copy the key. The hub shows it once.
  7. Store it in a server secret.

The key looks like mkp_test_ plus 52 characters. See Authentication.

These examples use Kenya staging. Keep the key in an environment variable.

sh
export MOOKHPAY_API=https://payments-ke-staging.salimia.me/v1/payments/merchant
export MOOKHPAY_SECRET_KEY=mkp_test_…

1. Create the checkout ​

amount is an integer in minor units. 100 is 1.00. 150000 is 1,500.00. Idempotency-Key is required.

sh
curl -X POST "$MOOKHPAY_API/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"
  }'
js
const res = await fetch(`${process.env.MOOKHPAY_API}/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",
  }),
});
const { ok, data, description } = await res.json();
if (!ok) throw new Error(description);
python
import os, requests

res = requests.post(
    f"{os.environ['MOOKHPAY_API']}/checkouts",
    headers={
        "Authorization": f"Bearer {os.environ['MOOKHPAY_SECRET_KEY']}",
        "Idempotency-Key": "order-1042",
    },
    json={
        "amount": 150000,
        "reference": "order-1042",
        "description": "2× Latte, 1× Mandazi",
        "return_url": "https://yourshop.example/paid",
    },
    timeout=15,
)
body = res.json()
if not body["ok"]:
    raise RuntimeError(body["description"])

A new checkout returns 201 Created:

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
  }
}

The same Idempotency-Key later returns 200 OK and the same checkout. See Idempotency.

Read amount as a string

You send an integer. The response amount is a string of minor units, such as "150000".

Store data.id with the order.

2. Send the payer to url ​

Redirect the browser to data.url. Do not edit the URL.

The page shows the amount and description. The payer cannot change the amount. They enter a phone number and approve the prompt on that phone.

On Kenya, the page can also show M-Pesa Pay Bill numbers. The payer pays the same amount from the M-Pesa menu. See How a checkout works.

When status becomes completed, the page waits 3 seconds. It then opens return_url:

https://yourshop.example/paid?checkout=cs_ke_3f9a…&reference=order-1042&status=completed

A failed payment does not redirect. A closed tab does not redirect.

3. Confirm before you fulfill ​

Anyone can open your return URL. Read the checkout with your key. Fulfill only when status is "completed".

sh
curl "$MOOKHPAY_API/checkouts/cs_ke_3f9a1c7e5b2d4a8e6c0b91d7" \
  -H "Authorization: Bearer $MOOKHPAY_SECRET_KEY"
js
const id = new URL(request.url).searchParams.get("checkout");
const res = await fetch(`${process.env.MOOKHPAY_API}/checkouts/${id}`, {
  headers: { Authorization: `Bearer ${process.env.MOOKHPAY_SECRET_KEY}` },
});
const { data } = await res.json();
if (res.ok && data.status === "completed") {
  // fulfill the order once
}
python
res = requests.get(
    f"{os.environ['MOOKHPAY_API']}/checkouts/{checkout_id}",
    headers={"Authorization": f"Bearer {os.environ['MOOKHPAY_SECRET_KEY']}"},
    timeout=15,
)
data = res.json().get("data", {})
if res.ok and data.get("status") == "completed":
    ...  # fulfill the order once

On a completed mobile-money payment, payment.provider_receipt is the receipt.

Kahawa is this flow on Cloudflare Pages.

Next ​

Staging documentation. Staging charges real money. See Environments.