Logo Lanfrica

kjdartaugust/virtual-dollar-card

Domain:

digital infrastructuresocioeconomic

Record type:

software
Creator:
kjd
Host:
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 …