A clean, Dockerized reference app for partners who have registered a program with KwiikPay. It demonstrates, end to end, how to consume the KwiikPay partner API to build a real customer-facing product — sign-up, KYC/KYB, virtual IBANs, balances, conversions, beneficiaries and payouts.
Use it as a starting point: fork it, point it at your program, and you have a working customer portal you can build on. Every screen maps directly to a part of the partner API, with short, commented code so you can see exactly how each call is made.
An end-customer signs up / logs in locally (this app's own auth). Behind the scenes the app uses your KwiikPay key to create and manage that person's KwiikPay customer.
Browser ──▶ This app (Next.js)
├── local auth (email/password) ← authenticates the human
└── server-side BFF ──▶ KwiikPay partner API
(holds kp_pub_… key) Authorization: Bearer kp_pub_…
The partner key can move money. It must never reach the browser.
Every KwiikPay call goes through a server-side BFF (lib/kp.ts,
imported with server-only) and the server actions. The browser
only ever talks to this app; only this app's server talks to KwiikPay. The key
lives in one server-side env var and is never shipped to the client.
cp .env.example .env # then edit .env — set your key + brand (see below)With Docker:
docker compose up --build
# open http://localhost:3000Local dev:
npm install
npm run dev # http://localhost:3000| Variable | What it is |
|---|---|
APP_NAME |
Your product's brand, shown to end-customers (title bar, login, dashboard). |
KWIIKPAY_API_BASE |
Partner API base URL. Defaults to the sandbox, https://api-staging.kwiikpay.io. |
KWIIKPAY_PARTNER_KEY |
Your program's partner key, kp_pub_…. Server-side only — never commit it. |
SESSION_SECRET |
Random string used to sign the local session cookie. |
DATA_DIR |
Where the demo's local user store (a JSON file) is written. |
The UI brand comes entirely from APP_NAME, and the app never displays the
KwiikPay program name returned by the API — so nothing identifies the underlying
program to your end-customers.
Walk the sidebar top to bottom; each step maps to part of the partner API:
| Step | UI | API |
|---|---|---|
| Sign up | /signup |
POST /v1/partner/customers |
| Verify (KYC/KYB) | /dashboard/verify |
POST /verifications, GET /verification-link, GET /verifications |
| Complete profile | /dashboard/profile |
PATCH /profile, GET /readiness |
| Open vIBAN + balance | /dashboard/accounts |
POST /accounts (async), GET /accounts, GET /balance, …/crypto-wallets |
| Convert | /dashboard/convert |
POST /conversions (quote) → POST /conversions/{id}/approve |
| Beneficiaries | /dashboard/beneficiaries |
POST /beneficiaries, GET /beneficiaries |
| Send a payout | /dashboard/payout |
POST /payouts (with Idempotency-Key) |
| Statement | /dashboard/statement |
GET /transactions, GET /statement |
The full API spec is at GET {KWIIKPAY_API_BASE}/openapi.json (rendered at /docs).
KwiikPay customers have no KwiikPay login. This app owns the human's login and
stores the mapping local user → kpCustomerId:
lib/db.ts— the local user store (a JSON file; scrypt-hashed passwords). Demo only — replace with your real database when you fork.lib/session.ts— signed, httpOnly session cookie holding only the local user id.- On sign-up (
app/actions.ts→signupAction) we create the KwiikPay customer and the local user in one step, then remember the id.
legal_nameneeds ≥ 2 words, or fiat won't unlock. Sign-up enforces it.- vIBANs are asynchronous.
POST /accountsreturns apendingaccount with anullIBAN; the real IBAN/BIC arrives via webhook. The Accounts page shows the pending state and a Refresh button to poll for it. - KYC approval is driven by a webhook. With the partner key you can initiate
and read verification status, but approval happens after review — expect
pendinguntil the webhook flips it. - Money-moving POSTs are idempotent. Payouts send an
Idempotency-Keyheader (seecreatePayoutAction) so a retry never sends twice.
app/
actions.ts server actions = the write half of the BFF
page.tsx redirect → /dashboard or /login
login/ signup/ local auth pages
dashboard/ auth-guarded customer area (one page per lifecycle step)
lib/
kp.ts the KwiikPay partner API client (server-only) ← the BFF core
db.ts local user store (demo)
session.ts signed session cookie
config.ts brand / config (APP_NAME)
format.ts minor-unit / currency helpers
components/ small UI primitives + the client forms
This repo runs against the sandbox out of the box. To take it live for your
program, edit .env:
KWIIKPAY_PARTNER_KEY— set it to your own program's key.APP_NAME— set it to your brand name.SESSION_SECRET— set a random secret (e.g.openssl rand -hex 32).KWIIKPAY_API_BASE— point it at the production API when you're ready.
Then, before shipping to real customers, harden the parts marked demo only:
swap the JSON user store (lib/db.ts) for a real database, tighten
the auth, and add handling for the KwiikPay webhooks your program receives.
This is sample/scaffolding code, kept deliberately small and well-commented so it's easy to read and adapt.