# Migrate from Open Exchange Rates

> Move an Open Exchange Rates integration to CurrencyCore: app_id to bearer auth, latest and historical mapping, convert and time-series calls, response fields, and cutover checks.

Canonical: https://currency-core.com/docs/guides/migrate-open-exchange-rates/
Updated: 2026-11-11
Published: 2026-11-11

---
Open Exchange Rates authenticates with an `app_id` query parameter and returns a USD-based snapshot by default. Its `latest.json` payload pairs an epoch `timestamp` with a `rates` map. CurrencyCore moves the key into a header, puts the base in the path, and returns a dated map. ISO codes and the units-per-one-base arithmetic stay the same, so the work is mostly URL and response plumbing.

Public Open Exchange Rates pricing and coverage below were checked on **2026-11-10**. Verify the vendor's current plan before you budget.

## What changes at a glance

| Area | Open Exchange Rates | CurrencyCore |
|---|---|---|
| Currencies | Over 200 | 160 fiat currencies |
| History | Back to 1 January 1999 | GBP/USD and USD/INR parity from 1949, daily majors from 1971, EUR pairs from 1999 |
| Free quota | 1,000 requests/mo, hourly updates, USD base only | 1,000 requests/mo, 60/min |
| Entry paid plan | Developer, $12/mo for 10,000 requests, all bases | Starter, $9/mo for 50,000 requests, full history |
| Auth | `app_id` query parameter, or `Authorization: Token` | `Authorization: Bearer` or `x-api-key` |
| Base | USD only on Free; all bases from Developer | Any base in the path, every plan |
| Cadence | Hourly on Free and Developer, 30 minutes on Enterprise, 5 minutes on Unlimited | Central-bank reference rates polled hourly, daily fixings |
| Conversion | Listed on Unlimited | `/v1/convert` on every plan |

## 1. Replace app_id with a bearer token

```bash
# Before
curl "https://openexchangerates.org/api/latest.json?app_id=YOUR_KEY&base=EUR"

# After
curl "https://api.currency-core.com/v1/rates/EUR" \
  -H "Authorization: Bearer cc_test_your_key"
```

Remove `app_id` from URLs, logs, and fixtures. CurrencyCore does not accept query-string auth, so there is no fallback form. Use a test key, then a live key. See [Authentication](/docs/authentication/).

## 2. Map endpoints

| Open Exchange Rates | CurrencyCore | Note |
|---|---|---|
| `/latest.json?app_id=...&base=EUR` | `/v1/rates/EUR` | The base moves from a query parameter into the path |
| `/latest.json?app_id=...` | `/v1/rates` | USD is the default base |
| `/historical/DATE.json` | `/v1/rates/{base}?date=DATE` | One dated snapshot per call |
| `/convert?app_id=...` | `/v1/convert?from=USD&to=INR&amount=100` | Included on every CurrencyCore plan |
| `/time-series.json` | `/v1/history?currency=INR&base=USD&from=&to=` | One currency per call, inclusive UTC dates |

Open Exchange Rates returns a non-USD base on paid plans. CurrencyCore puts the base in the path on every plan, so `/v1/rates/EUR` is a complete snapshot with no second call.

## 3. Map response fields

```json
{ "timestamp": 1762732800, "base": "USD", "rates": { "EUR": 0.8924, "INR": 94.13 } }
```

```json
{ "base": "USD", "date": "2026-11-10", "rates": { "USD": 1, "EUR": 0.8924, "INR": 94.13 } }
```

`timestamp` has no equivalent. Use `date`, a UTC calendar date. Dated requests may also return `requestedDate` and `asOf`, showing the fixing used. `base` and `rates` map directly, and the base entry is `1`.

A CurrencyCore conversion returns one entry per target:

```json
{ "from": "USD", "amount": 100, "date": "2026-11-10", "results": [{ "to": "INR", "result": 9413, "rate": 94.13 }] }
```

Read `results[0].result` for the amount and `results[0].rate` for the rate. Match by `results[].to` when you send several targets.

## 4. Cut over

1. Create an organization and a `cc_test_` key.
2. Change auth and URL construction in one client module.
3. Rewrite `latest.json` calls as `/v1/rates/{base}` and delete `base`.
4. Rewrite `historical/DATE.json` calls as `/v1/rates/{base}?date=DATE`.
5. Rewrite time-series calls as `/v1/history`, one currency at a time.
6. Rewrite conversion calls and read `results[0]`.
7. Shadow production requests and compare the same dates.
8. Watch `401`, `403`, `429`, then revoke the Open Exchange Rates app ID.

## When Open Exchange Rates is the better fit

Stay if USD is your only base, you already cache the snapshot, and you do not need PPP or analytics. Its long record is a real reason to stay. If you need 30-minute or 5-minute updates, its Enterprise and Unlimited plans list those cadences and CurrencyCore does not sell them. Choose the cadence and base you actually need.

## Related

- [API reference](/docs/api/)
- [OpenAPI specification](/docs/openapi/)
- [Authentication](/docs/authentication/)
- [Errors](/docs/errors/)
- [All guides](/docs/guides/)
- [Provider-neutral migration checklist](/docs/guides/migration/)
