Omni Way developer docs v1.0.0
Products Β· Hosted Checkout

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 β†’ your cancel_url.
β—†
The URL is the capability

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);

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>
β–²
No iframes

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.

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 pageWhat happens
Payment settlesGreen 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 / failsFailure state with a β€œback to merchant” link to cancel_url (if provided); popup message pos:expired / pos:failed.
No URLs providedThe page simply shows the terminal state β€” fine for payment links.
β›”
The redirect is a UX signal, not proof of payment

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.

Omni Way is the financial core; your storefront or till is the surface it powers. Integrate once and the same ledger, payouts and reporting work across every product you adopt.

omniway.online Β· InnBucksPowered by InnBucks (MicroBank Limited) Β· USD & ZWG.