Open Exchange Rates Time-Series Burns Your Quota
If you've shipped anything against Open Exchange Rates that touches history, you've probably hit this the hard way. Their documentation is explicit: "Requests to the time-series.json API endpoint count as one request for each day of data returned."
Meaning:
- 7 days of data = 7 requests
- 30 days = 30 requests (3% of your free 1,000/month cap)
- 90 days = 90 requests (9%)
- 365 days = 365 requests (36.5% of your free monthly quota in a single call)
For a charting use case that backfills a year of daily rates across 5 currency pairs, you're at 5 × 365 = 1,825 requests — past the free tier in a single page load.
AllRatesToday prices historical differently: one request per range, not per day. This article explains the difference, what it costs in practice, and how to design around either.
The quota model
OpenExchangeRates time-series.json
GET /api/time-series.json?app_id=XXX&start=2025-01-01&end=2025-12-31&base=USD&symbols=EUR
# costs: 365 requests against your monthly quota The endpoint returns all 365 daily rates in one HTTP call — but internally it's billed as if you'd made 365 individual historical requests.
AllRatesToday historical-rates
GET /api/historical-rates?source=USD&target=EUR&from=2025-01-01&to=2025-12-31
# costs: 1 request against your monthly quota One HTTP call, one quota decrement.
Concrete scenarios
Scenario 1: Dashboard with 5 pairs × 90-day history
- OpenExchangeRates: 5 × 90 = 450 requests per dashboard load. Past the free 1,000/mo cap after two loads.
- AllRatesToday: 5 × 1 = 5 requests per load. ~60 loads possible on the free 300/mo cap.
Scenario 2: Tax-year backfill (1 year, 1 pair)
- OpenExchangeRates: 365 requests. One-shot operation consumes 36.5% of the monthly quota.
- AllRatesToday: 1 request. 0.33% of the monthly quota.
Scenario 3: Multi-pair backtest (10 pairs × 3 years)
- OpenExchangeRates: 10 × 1,095 = 10,950 requests. Well past any plan below Enterprise.
- AllRatesToday: 10 requests.
The OpenExchangeRates model effectively turns historical analysis into a line-item purchase: every day of data you want, you pay for.
Why the pricing model exists
Historical data is bandwidth-heavy. An "all currencies for one day" response can be 5-10 KB. Open Exchange Rates' per-day billing reflects internal cost: each day is a separate backend lookup. It's defensible from an infra economics perspective.
It's still a bad developer experience. When your request count doesn't match your HTTP call count, capacity planning gets confusing fast. You have to explain to new team members why one line of code burned 365 requests.
AllRatesToday's approach is to price the API surface area, not the underlying row count. One call, one request, regardless of the date range. Simpler to reason about, easier to stay under quota.
When per-day billing is fine
- You only pull history for specific dates (accounting, invoice reconciliation). Open Exchange Rates'
historical/{date}.jsonis one request per date — the same price as AllRatesToday for single-date queries. - You rarely look at ranges — your app mostly uses current rates.
When range-based pricing matters
- Charting: every dashboard render pulls a range.
- Analytics: rolling 30/90/365-day windows.
- Backtesting: long ranges across many pairs.
- Reporting: monthly/quarterly/yearly recaps.
Any of these become 10-50x cheaper in quota terms on AllRatesToday.
AllRatesToday historical endpoint, in detail
curl -X GET "https://allratestoday.com/api/historical-rates?source=USD&target=EUR&from=2025-01-01&to=2025-12-31" \
-H "Authorization: Bearer YOUR_API_KEY" Response:
{
"source": "USD",
"target": "EUR",
"from": "2025-01-01",
"to": "2025-12-31",
"rates": [
{ "time": "2025-01-01", "rate": 0.9521 },
{ "time": "2025-01-02", "rate": 0.9534 },
...
{ "time": "2025-12-31", "rate": 0.9214 }
]
} Supported periods include shortcuts (period=30d, period=1y) and custom date ranges. Every range is one request.
Migrating a time-series query
Most apps using Open Exchange Rates' time-series.json pass start, end, and a base/symbols combination. The equivalent AllRatesToday call is:
- https://openexchangerates.org/api/time-series.json?start=2025-01-01&end=2025-12-31&base=USD&symbols=EUR&app_id=XXX
+ https://allratestoday.com/api/historical-rates?source=USD&target=EUR&from=2025-01-01&to=2025-12-31
(Authorization: Bearer YOUR_API_KEY) Response shape is different (array of {time, rate} vs keyed object), but the transformation is straightforward.
What if you still need per-day granularity?
Both APIs support single-date historical lookups at one-request-per-date:
- OpenExchangeRates:
GET /api/historical/2025-06-15.json - AllRatesToday:
GET /api/historical-rates?source=USD&target=EUR&from=2025-06-15&to=2025-06-15
If your app cares about a handful of specific dates rather than ranges, either API is fine.
Stop burning quota on history
Free historical data, one request per range, 60-second real-time updates. No credit card.
Get your free API key