RunPee and the API Economy (Or: What I Learned When Suppliers Get Acquired)
When I built the first version of RunPee, the idea of an "API economy" wasn't quite the cliché it is now. You could hook into a handful of services — movie databases, showtimes, maybe payment processing — and stitch them together into something useful. This felt like progress. Why build data infrastructure when someone else had already built it?
Seventeen years later, I have opinions about this.
The short version: third-party APIs are leverage on the way up and liability on the way down. The longer version involves several specific incidents that I'll recount here without being too litigious about which company did which thing.
The Movie Database Problem
RunPee needs movie data. Titles, release dates, run times, descriptions. This seems like a solved problem — there are multiple movie databases with public APIs. When I started, I picked one based on availability and cost (free, with reasonable rate limits) and integrated it.
That database got acquired. The terms changed. The rate limits changed. The fields I relied on got renamed or removed in a new API version. I migrated to a different source. That source changed its terms. I migrated again.
I've now migrated the movie data layer of RunPee three times. Each migration was days of work — not weeks, the codebase is manageable, but real days with real consequences if something broke in production. The business logic didn't change. The data didn't really change. The interface to the data changed because someone made a decision at a company I don't work for.
The Lesson: For data that your application depends on critically, treat third-party APIs as a source, not a store. Pull the data you need into your own database. Sync it. Own the copy. The API is the origin; your database is the truth. When the API changes, you update your sync layer, and the application that depends on your database keeps working.
This is not a new insight. It's in every good architecture guide. I ignored it early because the sync layer was extra work and the API was free and it seemed fine. It was fine until it wasn't.
The Showtimes Problem
RunPee used to show showtimes. Not just "when is the movie playing" but "here are specific times at theaters near you." This was a genuinely useful feature and required integrating with a showtimes data provider.
Showtimes data providers are not stable businesses. The data is expensive to source (they have to aggregate from thousands of theater chains, each of which has their own proprietary system), the margins are thin, and the customer base is mostly applications like mine — small developers with limited budgets. Two of the providers I worked with over the years were acquired and shut down their APIs. One just stopped responding to support requests, and the API started returning errors intermittently for weeks before I got an email saying it was being discontinued.
I eventually removed the showtimes feature. Not because I didn't want it, but because I couldn't build something reliable on infrastructure that kept disappearing.
The Lesson: Evaluate APIs not just on their current quality but on the business sustainability of the company providing them. A well-documented, fast API from a company with unclear revenue and one enterprise customer is a different risk profile than a clunky API from a company with a clear, stable business model. I should have done more of this analysis earlier.
The Payment Processing Problem
This one's shorter. Stripe is good. Before Stripe, the things I used were not good. Now I use Stripe and think about payment processing rarely. That's the whole story, and it's an unusual outcome in the API dependencies category.
Why is it an unusual outcome? Because Stripe found a business model that aligns their incentives with mine. They make money when I make money; they have a strong reason to keep the API stable and the documentation excellent. Most API providers don't have this alignment.
What Good Third-Party Dependency Hygiene Looks Like
After seventeen years of learning this lesson in multiple different ways:
Own your data layer. Any data you depend on that comes from a third party should be synced into your own database. Run your queries against your database. Use the third-party API to keep that database fresh.
Build to an abstraction, not to the API. Your code should call getMovieInfo(movieId), not theMovieDatabaseApi.getMovieById(movieId). The implementation behind that function can change; the interface your application code sees stays stable. When you migrate providers, you change the implementation, not every call site.
Budget for migration. If you're planning a project timeline and you have external API dependencies, add time for migration in year 3 and year 7 and whenever acquisition rumors start. Not because you'll definitely need it, but because pretending it won't happen is how you end up scrambling.
Prefer APIs from companies whose business model you understand. If you can't explain how they make money, you can't predict their behavior when money gets tight.
Read the terms of service. Actually read them, at least the key sections. Specifically: data ownership clauses, rate limits and how they change, notification requirements for changes, and what happens to your data if the service shuts down.
None of this is exciting. It's maintenance thinking applied to architecture, which is the unglamorous category where a lot of real engineering decisions live.
RunPee has been running for seventeen years. A significant part of why it's still running is that I've kept the critical data infrastructure under my own control when I could, and kept the external dependencies isolated and swappable. The features that depended on external APIs I couldn't control or replace — those features aren't there anymore.
The app you ship in year one is not the app you'll be maintaining in year ten. Building for replaceability is building for longevity. I wish I'd internalized that earlier.