A clean REST interface, signed requests and signed webhooks — the same for sandbox and production. Card, wallet, iDEAL and Sentoo, settled locally in USD, ANG and EUR.
From a two-line payment link to a full API integration — card data never touches your servers.
Create a session and redirect. We handle the payment page, 3-D Secure and PCI scope.
POST cp-api?action=payments.create-link
Generate a shareable link or QR with an amount, expiry and usage cap — send via WhatsApp or e-mail.
Portal → Payment links, or payments.create-link
Tap-to-Pay on iPhone/Android and PAX/Ingenico terminals through one session endpoint.
Tap to Pay app (coming)
Tokenize cards with setup intents and charge later for subscriptions and no-shows.
Coming: saved cards via the gateway wallet
Drop-in modules for WooCommerce, Shopify, Magento, PrestaShop, Wix and BigCommerce.
Connect your PMS or booking platform for pre-auths, deposit holds and check-in links.
Create a payment link server-side with your API key, then send the customer to the returned URL. Base URL: https://unwowmvqapfqyowzqbzn.supabase.co/functions/v1/cp-api
// create a payment link (server-side; never expose your key in a browser) const res = await fetch("https://unwowmvqapfqyowzqbzn.supabase.co/functions/v1/cp-api?action=payments.create-link", { method: "POST", headers: { "Authorization": "Bearer ku_live_…", "Content-Type": "application/json" }, body: JSON.stringify({ amount_minor: 12500, // $125.00, in cents currency: "USD", description: "Dinner for two — table 8", customer_email: "guest@demo.kuentoo.com", expires_days: 30 }) }); const link = await res.json(); // send the customer to the payment page redirect(link.url);
{
"ok": true,
"id": "6f1c…-…",
"reference": "CP-MFZK3Q9A1B2C3D",
"url": "https://kuentoo.com/pay.html?k=…",
"expires_at": "2026-10-24T18:00:00Z"
}
// other actions (GET unless noted):
// payments.get?id=… payments.list?status=&from=&to=&q=
// refunds.create (POST) { payment_id, amount_minor, reason }
// payments.create-link also accepts send_email: true (mails the link to customer_email)
// Idempotency-Key: <your unique id> on POSTs — same key within 24 h returns the same result (header Idempotent-Replayed: true)
// payouts.list statements.list (scope payouts:read)
// disputes.list disputes.get?id=… (scope payments:read)Authenticate with a scoped API key over TLS. Card data never reaches your servers: the customer pays on a PCI DSS Level 1 hosted page, so you stay out of PCI scope.
Authorization: Bearer ku_live_… (or ku_test_… in the sandbox)api:ku_live_…# fetch one payment curl "https://unwowmvqapfqyowzqbzn.supabase.co/functions/v1/cp-api?action=payments.get&id=6f1c…" \ -H "Authorization: Bearer ku_live_…" # refund $50.00 of it curl -X POST "https://unwowmvqapfqyowzqbzn.supabase.co/functions/v1/cp-api?action=refunds.create" \ -H "Authorization: Bearer ku_live_…" \ -H "Content-Type: application/json" \ -d '{"payment_id":"6f1c…","amount_minor":5000,"reason":"Two guests did not show"}'
Signed, retried event deliveries keep your systems in sync. Verify X-Kuentoo-Signature before you trust a payload: t=<unix>,v1=HMAC-SHA256(secret, t + "." + body).
| Event | Fires when |
|---|---|
| payment.succeeded | A payment is confirmed by the gateway |
| payment.failed | A payment is declined or errors |
| refund.succeeded | A refund is processed |
| payout.paid | A payout to your bank account is sent |
| dispute.opened | A customer disputed a payment (chargeback) |
| dispute.closed | A chargeback was won, lost or accepted |
| statement.ready | Your monthly statement is available |
| test.ping | You press “Send test” in the portal |
data.reference — the same event may arrive twice// Node.js — verify X-Kuentoo-Signature const crypto = require('crypto'); function verify(secret, header, rawBody) { const [t, v1] = header.split(',').map(p => p.split('=')[1]); if (Math.abs(Date.now()/1000 - Number(t)) > 300) return false; // replay window 5 min const expected = crypto.createHmac('sha256', secret).update(t + '.' + rawBody).digest('hex'); return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(v1)); } // PHP [$t, $v1] = array_map(fn($p) => explode('=', $p, 2)[1], explode(',', $_SERVER['HTTP_X_KUENTOO_SIGNATURE'])); $ok = abs(time() - (int)$t) <= 300 && hash_equals(hash_hmac('sha256', $t . '.' . file_get_contents('php://input'), $secret), $v1);
Use a ku_test_… key. In the sandbox the amount decides the outcome; use Visa 4929 4212 3460 0821 with any CVC. No real money moves.
| Amount | Expiry month | Result |
|---|---|---|
| 1.00 – 24.99 | any | Approved |
| 25.00 – 49.99 | any | Approved, settlement rejected |
| 50.00 – 74.99 | any | Referral |
| 100.00 – 149.99 | any | Declined |
| any | 01 | 3-D Secure: authenticated |
| any | 12 | 3-D Secure: challenge |
| any | 06 | 3-D Secure: rejected |
ku_live_… key when you go live — nothing else changes.Tell us what you’re building and we’ll issue test keys and the signing helpers. Same-day testing is typical.