Skip to content
Back to Blog

How I Run Live Exchange Rates on a Cheap API Tier (Without It Ever Going Down)

Updated:
• 4 min read • … views

When people picture an app that needs “live exchange rates” for calculations, they usually imagine the app calling an exchange-rate API every time you press “calculate”. It’s also what would have forced Forexizer (the position size calculator I built) onto a more expensive API plan.

Here’s the architecture I used instead:

The constraint that shaped everything

Exchange-rate APIs charge by request volume, and the jump from the entry tiers to the high-volume ones is quite steep. The tier I deliberately stay on allows on the order of 15,000 requests a month, the next tier would allow up to 600,000 requests, and I’d rather architect around the 15k ceiling than pay 4 times more for headroom I wouldn’t need yet.

The naive design makes that impossible. Do the math on per-user, per-open calls: a few hundred users opening the app to calculate their position sizes x times a month, each calculation across multiple currency pairs, and you blow through a month’s quota very quickly. After that you’re either staring at errors or forced onto a pricier plan to paper over an architecture problem.

So the real design question was never “how do I fetch rates?” It was: how do I decouple how often users need rates from how often I fetch them?

The decision: the app never touches the rate API

The architecture comes down to one rule:

The external API is touched by exactly one thing, on a fixed schedule. The app only ever reads from my own database.

Concretely:

  1. A cron job runs hourly on the backend. It makes one request: USD against the 15 other currencies Forexizer supports. From those, it derives every cross (a 16×16 matrix, 256 rates) and writes them all to the database. EUR/JPY is just USD/JPY ÷ USD/EUR.
  2. That’s the only code in the entire system that calls the external API.
  3. The mobile app, on every calculation, reads rates from my database, never from the third party.

The numbers work out because the API bills per request, not per rate. One call an hour, skipped while the forex market is closed at the weekend, lands around ~550 requests a month. That’s under 4% of the 15,000 ceiling, with room to add currencies or fetch every few minutes if I ever need fresher rates.

And crucially, that cost is now completely flat. Whether I have 10 users or 100,000, the API bill doesn’t move, because user traffic and API traffic are fully decoupled.

The benefits I didn’t fully appreciate until later

Decoupling fetch-from-serve started as a cost hack. It turned out to be a great resilience decision for the app:

The trade-off, stated honestly

Rates are up to an hour stale. For Forexizer’s audience (people calculating position sizes) that’s completely fine, and I made that trade deliberately. If I were building a trading terminal, this architecture would be wrong, and I’d need streaming prices and a very different cost model. Knowing which app you’re building is the whole game.

Sign up for updates !