What happens to your users when you rip out the entire backend and bolt in a different one? If your answer is “they file support tickets for a month,” you should look closely at what Apple Card is doing in 2026.
Here’s the verified shape of it. In January 2026, JPMorgan Chase reached a deal to become the Apple Card issuer, closing out Goldman Sachs’ run in consumer finance. The transition runs over 24 months. And the stated goal, per Apple’s side of the messaging, is that existing users will not see any visible change.
That last sentence is the part I keep rereading. Twelve million users as of early 2024, up from 3.1 million by March 2020, and the plan is for none of them to notice that the institution processing their money got replaced.
Why this is a bot builder’s problem
I build bots. Most of them sit on top of somebody else’s infrastructure — an LLM provider, a vector store, a messaging API, a payments processor. And every one of those dependencies is a Goldman Sachs waiting to happen. Pricing changes. Terms change. A provider decides your use case is no longer strategic. Somebody gets acquired.
The instinct when you’re moving fast is to write directly against whatever SDK you picked on day one. It’s faster. It feels fine for months. Then your provider announces a deprecation and you discover the provider’s naming conventions have leaked into your database schema, your prompt templates, your error handling, and your user-facing copy.
Apple clearly did not do that. You don’t get to announce a 24-month issuer migration with a straight face unless the card’s identity was never really tied to the issuer in the first place. The Wallet app, the transaction categorization, the daily cash mechanic, the physical titanium slab — none of that reads as “Goldman Sachs.” Users experienced Apple Card. Goldman was an implementation detail.
The abstraction layer, unglamorously
Translating this to something you’d actually build: your bot needs a boundary between what it does and who does it for you.
- One adapter per provider, and one interface they all satisfy. Your application code calls
chat.complete(), not the vendor’s client directly. When you swap, you write a new adapter, not a new app. - Store your own canonical data. If your conversation history lives only inside a provider’s thread objects, you don’t own your conversation history. Keep your own records, in your own schema, and treat the provider’s IDs as foreign keys you can afford to lose.
- Never put a vendor name in user-facing text. “Powered by [Provider]” is a promise you may not be able to keep in two years.
- Run both in parallel before you cut over. The 24-month window is the tell. Big migrations aren’t flips, they’re long overlaps where both systems are live and you compare outputs.
- Keep an eval suite that isn’t provider-specific. The only way to know a new backend behaves like the old one is to have written down what “behaves correctly” means before you needed to.
The growth curve is the reason it’s hard
3.1 million users to 12 million is roughly a 4x over four years. That’s a good problem and a brutal migration constraint. Every user you add before you build the abstraction is a user who has to be carried across it later. The cost of a portability layer scales with your codebase; the cost of not having one scales with your user count.
Which means the honest version of this advice is uncomfortable: the right time to build the boundary is when you have twelve users and it feels like premature engineering. Not because you’ll definitely swap providers, but because the interface you’d design under no pressure is better than the one you’d design during a forced migration.
What “no visible change” actually costs
I want to be careful here, because I don’t have visibility into Apple’s internals and neither do you. What I can say is what the public timeline implies. Two years of transition for a product with roughly a decade and a half of history behind it. That’s not a weekend rewrite. That’s account migration, regulatory handoff, statement continuity, dispute histories, credit reporting, and a thousand things that have to line up so a user tapping their phone at a coffee shop experiences nothing at all.
Invisible is expensive. It’s also the entire point. Users don’t want to know about your architecture. They want their thing to keep working.
Your bot is smaller than Apple Card. Your migration will be smaller too. But the design question is identical: if your provider disappeared tomorrow, would your users find out from you, or from a broken feature? Build like the answer should be neither.
🕒 Published: