What It Actually Takes to Ship a Consumer Credit Card
The first time our card actually worked, I spent $34.12 on burgers, hot dogs, and a milkshake.
It was a summer day, my wife and I were out, and I had the first test card in my wallet that I’d been carrying around unsure if it would work. I tapped it to pay. It cleared in about a second. Nothing happened, which was the point. No error, no decline, no awkward “let me try another card.”
Behind that one tap, an authorization request had traveled through a card network, hit our issuing processor, run against a balance, cleared a stack of risk and compliance checks, and come back approved, all before I’d finished paying. Behind that single second of seamlessness was over a year of engineering.
This is the reality of launching a consumer credit card that often goes unmentioned. The goal is to make something complicated feel like nothing at all. You are not building a card. You are integrating a financial system, a stack of vendors and networks and regulators who all have to agree to trust each other, and then hiding the complexity so the person tapping their phone feels none of it.
You don’t build a card, you integrate a financial system
Most lose sight of the project because of its scale. To understand the magnitude, you have to look at the number of moving parts we had to control simultaneously: provisioning and card issuance, the logic of credit underwriting, validating identities, the native mobile experience, the underlying data infrastructure, and navigating network certification and regulatory compliance. We were on the hook for the entire operation, not just a small piece.
The stack
Our architecture was a series of deliberate trade-offs designed to optimize for speed without sacrificing financial integrity. We anchored the core ledger to Highnote for card issuing because of its modern API, then layered DigiFi for loan origination to automate complex decisioning workflows. This system was fed by Experian for credit data and Plaid for bank connectivity, ensuring our underwriting was grounded in real-time liquidity. To deliver this to the user, we built the front end using React Native and Expo for cross-platform efficiency, powered by Cloudflare Workers and Workflows on the backend to minimize latency and enforce strict idempotency across all transaction flows. Finally, we tied the entire ecosystem together with a data layer built on Supabase, Snowflake, and PostHog, allowing us to treat every transaction and user interaction as a first-class analytical object.
Where the real risk lives
The true test of a financial system isn’t the happy path. It’s the weight of everything that can go wrong. This is where most card programs stumble. They are built to demo, not to survive the chaos of real-world scale. Risk here isn’t a theoretical concern; it’s the daily reality of managing compliance evidence like mandatory TLS configurations, AES-256 encryption standards, vulnerability scans, and rigorous antimalware protocols. It is navigating the labyrinthine demands of Mastercard certification, where compliance isn’t a checkbox but a foundational requirement. It is debugging the endless, granular edge cases of KYC failure modes, and realizing that the unglamorous reliability work, the invisible glue holding the system together, is actually the product. The gap between a demo that works and a system where money moves correctly every time is not a bridge; it’s an ocean.
Small team, ship fast
We built this from zero to launch in under twelve months, but the true metric wasn’t the speed of our commit logs. It was the leverage we applied. With a team that could fit in a single room, we maintained the operational capacity of an organization fifty times our size. We didn’t do this by just working harder; we did it by obsessively automating our infrastructure and adopting a modern developer stack to amplify our output. We used Cursor and Claude Code to accelerate our coding velocity, Figma MCP to translate designs into code instantly, and relied on Maestro for end-to-end testing to verify critical flows before a single user ever touched them. By focusing on these force multipliers, we could obsess over the complex edge cases that actually defined our users’ experience. We proved that massive scope doesn’t require massive headcount; it requires massive focus.
What I got wrong
The team built the happy path first. A user applies, gets approved, gets a card, taps it, sees the transaction. When that worked end to end, it felt like the hard part was behind me.
It wasn’t. In a card program the edge cases are the product. The applicant whose identity verification half-passes, clearing one check and failing another. The address that’s valid to the network but not to the bureau. The user who abandons onboarding at step four on a Tuesday and comes back weeks later to an incomplete account state I hadn’t designed for. None of these are special. They’re the norm for real people interacting with a financial system, and there are a lot more of them than you expect.
The deeper version of the same problem is that none of these flows lived inside one system. A single onboarding ran through KYC, credit data, the issuing processor, and our own backend, each of which could be slow, down, or subtly wrong, and each of which could fail on its own schedule. The bug was almost never in one integration. It was in the connection between several, in managing state between the independent systems and handling errors gracefully. Those are the hardest to reproduce and the easiest to ship.
What I’d do differently: build the test harness to account for the partial-failure paths before the happy path. Specifically, I’d simulate latency at each vendor, returning an error, and returning incomplete responses, and I’d assert the desired outcome for each state. I treated that as hardening work once things were stable. It should have been the scaffold I built everything else on.
Engineering was the fast part. That’s the thing I had backwards.
I sequenced the work the way an engineer naturally does: build the product, get it solid, then run it through bank approval and regulatory review at the end. Those reviews don’t move at engineering speed, and they aren’t supposed to. The team would finish something, hand it off, and wait. The engineering calendar and the bank calendar were running at completely different speeds, and I’d built our plan around the wrong one.
The mistake wasn’t that the external timelines were slow. They were always going to be slow, and that’s not a complaint, it’s the cost of moving real money under real regulations. The mistake was treating those timelines as a final gate instead of the thing that should have shaped the whole schedule.
What I’d do differently: let the slow dependencies set the plan, and build engineering around them. Get the compliance and bank conversations running on day one, before any code depends on them, then order the engineering work to feed each review exactly when it comes up, instead of building whatever’s next and batching it all for approval at the end. Finishing fast isn’t the goal when something slower than you set the real timeline. Feeding that timeline on schedule is.