Skip to content

Confirming a payment ​

Read the checkout with your key before you fulfill. Do this on every order.

The redirect is not proof ​

After a completed payment the payer can land on:

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

Anyone can open that URL. Read checkout from the query. Ignore status.

js
const id = new URL(request.url).searchParams.get("checkout") ?? "";

if (!/^cs_[a-z]{2}_[0-9a-f]{24}$/.test(id)) return notPaid();

const res = await fetch(`${MOOKHPAY_API}/checkouts/${id}`, {
  headers: { Authorization: `Bearer ${MOOKHPAY_SECRET_KEY}` },
});
const { data } = await res.json();

if (!res.ok || data?.status !== "completed") return notPaid();

GET returns 404 for an id your key did not create.

Also check:

  • data.reference is the order you will fulfill.
  • data.amount is the price of that order.
  • You did not already fulfill this checkout id. A reload must not ship the order twice.

No webhooks ​

MOOKHPay does not send webhooks. The hub Webhooks and Deliveries tabs do not send payment.succeeded or payment.failed.

Use the return URL for payers who come back. Poll the checkouts you still wait on.

js
for (const order of pendingOrders) {
  const res = await fetch(`${MOOKHPAY_API}/checkouts/${order.checkoutId}`, { headers });
  const { data } = await res.json();
  if (data.status === "completed") await fulfillOnce(order);
}
  • Poll every 10 to 30 seconds. You share 120 requests per minute with creates.
  • open after expires_at means an attempt is still in flight.
  • On Kenya, an exact Pay Bill payment can set completed after expires_at. If a customer says they paid from the menu, read the checkout again.
  • Fulfill each checkout id once.

A later webhook will tell you to call GET. GET stays the check.

Receipts ​

On a completed mobile-money payment, show or store payment.provider_receipt. Kahawa prints it on /paid.

Staging documentation. Staging charges real money. See Environments.