Skip to content

kwiikpay/partner-sample-app

Repository files navigation

KwiikPay — Partner Sample App

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 golden rule

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.

Quick start

cp .env.example .env        # then edit .env — set your key + brand (see below)

With Docker:

docker compose up --build
# open http://localhost:3000

Local dev:

npm install
npm run dev                 # http://localhost:3000

Configuration (.env)

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.

The customer lifecycle this demonstrates

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

How the local ↔ KwiikPay mapping works

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.tssignupAction) we create the KwiikPay customer and the local user in one step, then remember the id.

Good to know

  • legal_name needs ≥ 2 words, or fiat won't unlock. Sign-up enforces it.
  • vIBANs are asynchronous. POST /accounts returns a pending account with a null IBAN; 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 pending until the webhook flips it.
  • Money-moving POSTs are idempotent. Payouts send an Idempotency-Key header (see createPayoutAction) so a retry never sends twice.

Layout

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

Going live

This repo runs against the sandbox out of the box. To take it live for your program, edit .env:

  1. KWIIKPAY_PARTNER_KEY — set it to your own program's key.
  2. APP_NAME — set it to your brand name.
  3. SESSION_SECRET — set a random secret (e.g. openssl rand -hex 32).
  4. 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.

About

Reference customer-facing app for KwiikPay partners, demonstrates the partner API end to end (sign-up, KYC/KYB, virtual IBANs, conversions, payouts). Fork it to get started.

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors