Hosted Checkout & pos.js
The fastest integration on the platform: create a payment, redirect to its
checkout_url, get the customer back when it's paid. We host the page, carry the InnBucks
branding requirements, run the countdown and detect settlement.
What the customer sees
- InnBucks-branded header β official logo and palette (a hard requirement from InnBucks for payment surfaces; the hosted page keeps you compliant automatically).
- The amount and the 9-digit code in large type, plus a scannable QR.
- βPay using InnBucks Appβ deep-link button on mobile devices.
- USSD instructions β dial
*569#for customers without the app or data. - A 10-minute countdown matching the code's life, and automatic state changes: paid β green check β redirect to your
success_url?payment_id=β¦; expired β retry message β yourcancel_url.
checkout_url contains the payment's unguessable id and needs no session or login β safe to
send by email, WhatsApp or SMS as a payment link. It exposes only the payment's status, never your account
data.
Integration 1 β full redirect
// after creating the payment server-side:
res.redirect(payment.checkout_url);
// customer pays β lands on success_url?payment_id=β¦
// ALWAYS confirm server-side before fulfilling:
const fresh = await getPayment(req.query.payment_id);
if (fresh.status === "paid" && fresh.merchant_ref === order.ref) fulfil(order);
Integration 2 β pos.js popup
Keep the customer on your page; the checkout opens in a centered popup and reports back via
postMessage. Falls back to a full redirect when popups are blocked.
<script src="https://omniway.online/static/pos.js"></script>
<button id="pay">Pay with InnBucks</button>
<script>
document.getElementById("pay").onclick = async () => {
// 1. ask YOUR server to create the payment (your secret key stays server-side)
const { checkout_url } = await fetch("/api/checkout", { method: "POST" }).then(r => r.json());
// 2. open the hosted checkout in a popup
POS.pay({
checkoutUrl: checkout_url,
onSuccess({ payment_id }) { location.href = "/thanks?p=" + payment_id; },
onCancel({ reason }) { console.log("not paid:", reason); } // "expired" | "failed" | "closed"
});
};
</script>
Don't embed the checkout in an <iframe> β InnBucks deep links and app switching break
inside frames. The popup/redirect pattern exists for exactly this reason.
Integration 3 β payment links (no code at all)
For invoices and remote payment, create the payment from anywhere (even a script) and send the
checkout_url itself:
# create a $25 invoice payment and copy the link into WhatsApp/email
curl -s https://omniway.online/v1/payments \
-H "Authorization: Bearer sk_live_..." -H "Content-Type: application/json" \
-H "Idempotency-Key: invoice-2026-0042" \
-d '{"amount_cents":2500,"merchant_ref":"invoice-2026-0042","narration":"Invoice 0042"}' \
| jq -r .checkout_url
Pair it with a payment.paid webhook to mark the invoice settled
automatically.
The redirect contract
| Event on the page | What happens |
|---|---|
| Payment settles | Green confirmation, then redirect to success_url with ?payment_id=<id> appended (after ~1.2 s). If a pos.js popup opened the page, it also posts {source:"bytecraft-pos", type:"pos:paid", payment_id} to the opener. |
| Code expires / fails | Failure state with a βback to merchantβ link to cancel_url (if provided); popup message pos:expired / pos:failed. |
| No URLs provided | The page simply shows the terminal state β fine for payment links. |
Anyone can type your success_url into a browser. Fulfil only after your server confirms
status === "paid" via GET /v1/payments/:id or a verified webhook.