Appearance
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=completedAnyone 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.referenceis the order you will fulfill.data.amountis 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.
openafterexpires_atmeans an attempt is still in flight.- On Kenya, an exact Pay Bill payment can set
completedafterexpires_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.