CubePay docs
Accept crypto payments on Cube Chain
CubePay is a hosted payment gateway: you create an invoice over HTTPS, send the buyer to the returned checkout page, and get a signed webhook when the payment confirms on-chain. Flat 1% — no chargebacks, no card networks.
Introduction
Everything runs against a single base URL. All request and response bodies are JSON.
Base URL
https://cubepay.gocube.orgThe flow: create an invoice server-side → redirect the buyer to checkout_url → the buyer pays on Cube Chain → you receive invoice.paid on your webhook → funds are swept to your payout address (invoice.completed).
Authentication
Authenticate every API call with your secret key in the Authorization header:
Authorization: Bearer ck_live_…Your key is shown once at signup and can be rotated from the dashboard (Settings → API keys). It is stored hashed on our side and can never be retrieved — keep it in an environment variable on your server and never ship it to a browser or mobile bundle. The dashboard itself signs in with email + password, which issues a 24-hour session token with the same permissions.
Currencies & settlement tokens
Invoices are priced in fiat (price_currency) and the pricing currency pins the on-chain token — there is nothing for the buyer to choose:
Passing a mismatched pay_token (e.g. USDT on an NGN invoice) returns 422. The quote rate is locked when the invoice is created and the exact token amount appears inpay_amount.
One account can also run the two currencies separately: the dashboard (Settings → Currency profiles) issues an NGN-scoped and a USD-scoped API key, each with its own webhook URL and settlement wallet. A scoped key defaults to its currency — price_currency can be omitted — and may not create invoices in the other one.
Create an invoice
One call creates the invoice, derives a unique deposit address, locks the quote and returnscheckout_url. Pick your stack:
curl -X POST https://cubepay.gocube.org/api/v1/invoices \
-H "Authorization: Bearer ck_live_…" \
-H "Content-Type: application/json" \
-d '{
"price_amount": "25000",
"price_currency": "NGN",
"order_id": "order_1042",
"description": "Cube Phone case",
"success_url": "https://store.com/thank-you"
}'
# → { "id": "inv_…", "checkout_url": "https://cubepay.gocube.org/checkout/inv_…", … }Optional fields: ttl_minutes (payment window, 5 min – 7 days, default 15),metadata (arbitrary JSON echoed back in webhooks), order_id,description, success_url and cancel_url.
Hosted checkout & drop-in SDK
checkout_url serves a mobile-friendly hosted page with the amount, a QR code and live payment status — nothing to build. To keep buyers on your site, load the drop-in SDK and open the checkout in a modal:
<script src="https://cubepay.gocube.org/sdk/cubepay.js"></script>
<script>
CubePay.open({
checkoutUrl: invoice.checkout_url,
onPaid: (invoiceId) => { window.location = "/thank-you"; },
});
</script>The checkout's “paid” screen is buyer UX only — fulfil orders exclusively on the signedinvoice.paid webhook.
In-app payments — direct charge (no redirect)
To charge a user entirely inside your app — no hosted-checkout redirect — resolve the invoice's on-chain deposit address and exact amount, then have the user's wallet send the funds straight to it. CubePay's watcher detects the deposit and fires your invoice.paid webhook, exactly as for hosted checkout.
1. Create an invoice with your merchant key to get an invoice_id.
2. Quote it in the settlement token to get the deposit address + exact amount (public, no auth — NGN invoices are payable only in XNGN, USD in USDT):
curl -X POST https://cubepay.gocube.org/api/v1/public/invoices/{invoice_id}/select-token \
-H "Content-Type: application/json" \
-d '{"pay_token":"XNGN"}'
# → { "pay_token": "XNGN", "pay_amount": "5000", "pay_address": "0x…" }3. Send pay_amount of the token to pay_address from the user's wallet (any signer). That's the whole payment — CubePay confirms it on-chain.
The Cube super-app ships a tiny Kotlin SDK that does steps 2–3 against the signed-in self-custodial wallet, gated by the user's spend password:
// server: create the NGN invoice with your merchant key → invoiceId
// authorize in-app and pay from the user's xNGN balance:
val txHash = CubePaySdk.payNairaInvoice(invoiceId, walletPassword).getOrThrow()
// → CubePay's invoice.paid webhook fires once it settles; credit the user server-side.
// lower level, to pay with your own wallet/signer:
val q = CubePaySdk.selectToken(invoiceId, payToken = "XNGN")
yourWallet.send(to = q.payAddress, token = "XNGN", amount = q.payAmount)Treat the client result as UX only — credit the user (mint pool shares, mark the order paid…) strictly on the signed invoice.paid webhook.
Payment links
A payment link is a reusable URL for a fixed price — share it in chats, invoices or social bios. Each visit to /l/{id} spawns a fresh invoice and redirects to its checkout, so one link serves unlimited buyers. Create and manage them in the dashboard (Payment links) or via the API:
curl -X POST https://cubepay.gocube.org/api/v1/payment-links \
-H "Authorization: Bearer ck_live_…" \
-H "Content-Type: application/json" \
-d '{ "title": "Cube Phone case", "price_amount": "25000", "price_currency": "NGN" }'
# → { "id": "plk_…", "url": "https://cubepay.gocube.org/l/plk_…", … }Webhooks
Set your endpoint in the dashboard (Settings → Integration). Every delivery is an HTTP POST with these headers; failed deliveries retry with backoff (30s → 6h, 8 attempts). Respond 2xx within 10 seconds and process each X-CubePay-Delivery id once.
X-CubePay-Event: invoice.paid
X-CubePay-Delivery: evt_… # idempotency key — process each once
X-CubePay-Timestamp: 1760000000
X-CubePay-Signature: hex(HMAC_SHA256(webhook_secret, "{timestamp}." + raw_body))invoice.pendingPayment seen on-chain, awaiting confirmationsinvoice.paidConfirmed in full — fulfil the order on this eventinvoice.underpaidConfirmed amount below the quote (outside tolerance)invoice.expiredTTL elapsed with no paymentinvoice.completedFunds swept to your payout addressVerify the signature with your webhook secret (Settings → API keys → Reveal) before trusting a delivery:
import crypto from "crypto";
function verifyCubePay(req, rawBody) {
const ts = req.headers["x-cubepay-timestamp"];
const sig = req.headers["x-cubepay-signature"];
const expected = crypto.createHmac("sha256", process.env.CUBEPAY_WEBHOOK_SECRET)
.update(`${ts}.`).update(rawBody).digest("hex");
const fresh = Math.abs(Date.now() / 1000 - Number(ts)) < 300;
return fresh && crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(sig));
}
// process each X-CubePay-Delivery id once; respond 2xx within 10sAPI reference
/api/v1/auth/loginEmail + password → 24h session token/api/v1/merchants/meYour merchant profile/api/v1/merchants/meUpdate webhook URL / payout address/api/v1/merchants/me/rotate-keyRotate API key (shown once)/api/v1/merchants/me/rotate-webhook-secretRotate webhook secret/api/v1/merchants/me/reveal-webhook-secretReveal the current webhook secret/api/v1/merchants/me/currency-profilesPer-currency keys, webhooks & settlement wallets/api/v1/merchants/me/currency-profiles/{ccy}/rotate-keyCreate/rotate the NGN- or USD-scoped key/api/v1/merchants/me/currency-profiles/{ccy}Set per-currency webhook URL / settlement wallet/api/v1/invoicesCreate invoice (price_amount, price_currency, ttl_minutes?, metadata?)/api/v1/invoices · /{id}List / fetch invoices/api/v1/invoices/{id}/settleSweep a paid invoice to your payout address/api/v1/payment-linksCreate a reusable payment link/api/v1/payment-linksList links with visit & paid stats/api/v1/payment-links/{id}Pause / activate a link/l/{id}Public: spawns a fresh invoice and redirects to checkout/checkout/{id}Public: hosted checkout pageErrors
Errors return a JSON body with a human-readable detail message:
{ "detail": "NGN invoices are payable only in XNGN" }401Missing, invalid or expired credentials404Resource not found (or owned by another merchant)409Conflict — e.g. settling an unpaid invoice422Validation failed — the detail message says which field5xxGateway problem — retry with backoffQuestions or stuck on an integration? Reach out from your dashboard — or open the Developers tab for keys and live examples.
