Dola — virtual USD card platform for Africa. Fund in cedis, spend in dollars. Next.js 16 sandbox card-issuer demo with swappable IssuerService.
# Dola — Virtual Dollar Cards for Africa 💳
**virtual-dollar-card.vercel.app**
Fund a wallet in **cedis**, spend in **dollars**. Users verify their identity, top
up with mobile money, and issue a virtual USD card to pay any online merchant —
subscriptions, ads, cloud bills, APIs.
The cards are **real**. Dola issues virtual USD Visa/Mastercards through
Sudo, reveals the true PAN and CVV from Sudo's PCI vault,
and — the part that matters — **authorizes its own card spends**. When the card is
charged, the network doesn't decide whether the money moves. Dola does.
> Runs against Sudo's **sandbox** and Paystack's **test mode**. The architecture is
> the production one; only the keys are test keys.
## The interesting part: Dola is the authorizer
Most card-API integrations stop at `POST /cards`. The issuer holds the money, the
issuer approves the spend, and your app is a dashboard over someone else's ledger.
Dola inverts that. Cards are issued against a Sudo **gateway funding source** with
a JIT (just-in-time) endpoint pointing at `/api/issuer/webhook`. So when the card
is swiped, the card network calls **us** and waits up to 4 seconds for a verdict:
```
merchant → card network → Sudo → POST /api/issuer/webhook
│
│ authorization.request ($2.50 at Spotify?)
▼
check the card's balance in Neon
│
approve "00" │ decline "51" (insufficient funds)
│ "62" (frozen card)
▼ "14" (unknown card)
Sudo → network → merchant
│
│ transaction.created (settled)
▼
debit the ledger, idempotent on reference
```
Those are **ISO 8583 response codes** — the language card networks have spoken
since the 1980s. Your Postgres row is the source of truth for whether a real card
works at a real merchant.
Three details that make it safe:
- **`authorizeByDefault: false`** — if we time out, the spend is declined, not waved through.
- **An unreadable payload declines with `96`.** A missing amount once parsed as `$0`, and `$0 ≤ balance` *approved*. Fail closed, always.
- **Sett …