---
title: "Migrating from Open Exchange Rates to AllRatesToday: A Developer's Guide"
description: "Step-by-step migration from openexchangerates.org to AllRatesToday — endpoint-by-endpoint URL swaps, response shape differences, and drop-in SDK replacements for JS, Python, and PHP."
canonical: https://allratestoday.com/blog/migrate-from-openexchangerates-to-allratestoday/
source: AllRatesToday (https://allratestoday.com/) — Markdown mirror of the page above; index of all pages at https://allratestoday.com/llms.txt
generated: 2026-10-19T19:58:04.100Z
---

![Data migration process](https://images.pexels.com/photos/28169154/pexels-photo-28169154.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=650&w=940)

If you've decided to move off Open Exchange Rates — for real-time rates, any-base-currency flexibility, official SDKs, or historical data from €4.99/month — the migration itself is usually a one-afternoon job. The JSON shapes are similar enough that most of the work is mechanical.

This guide walks you through every endpoint, shows the URL and response-shape differences, and ends with the SDK drop-in for each supported language.

## Before you start

1. **Get your AllRatesToday API key** at [allratestoday.com/register](https://allratestoday.com/register). 300 free requests (one-time), no credit card. Historical data and commercial use need a paid plan from €4.99/month.
2. **Keep both keys active** during migration so you can run a side-by-side comparison.
3. **Write a wrapper in one place.** If your codebase has inline `fetch` calls to `openexchangerates.org`, consolidate them before migrating. Then you'll only touch one file.

## Endpoint-by-endpoint mapping

### 1. Latest rates

**Open Exchange Rates:**

```
GET https://openexchangerates.org/api/latest.json?app_id=YOUR_APP_ID
```

Response:

```
{
  "disclaimer": "...",
  "license": "...",
  "timestamp": 1713702122,
  "base": "USD",
  "rates": {
    "EUR": 0.9234,
    "GBP": 0.7891,
    ...
  }
}
```

**AllRatesToday:**

```
GET https://allratestoday.com/api/v1/rates?source=USD
Authorization: Bearer YOUR_API_KEY
```

Response:

```
[
  { "rate": 0.891743, "source": "USD", "target": "EUR", "time": "2026-10-16T16:38:01+0000" },
  { "rate": 0.750976, "source": "USD", "target": "GBP", "time": "2026-10-16T16:38:01+0000" },
  ...
]
```

**Differences:**

- `base` → `source`
- The `rates` object → an array of rows, one per currency, each with `target` and `rate`
- `timestamp` (Unix epoch) → `time` (ISO 8601) on each row
- No `disclaimer`/`license` fields (they don't exist in AllRatesToday responses).

### 2. Specific currency pair

**Open Exchange Rates** (free tier is USD-only):

```
GET https://openexchangerates.org/api/latest.json?symbols=EUR&app_id=YOUR_APP_ID
```

Response gives `{base: "USD", rates: {EUR: 0.9234}}`.

**AllRatesToday:**

```
GET https://allratestoday.com/api/v1/rates?source=USD&target=EUR
```

Response:

```
[
  { "rate": 0.891743, "source": "USD", "target": "EUR", "time": "2026-10-16T16:38:01+0000" }
]
```

Note: **AllRatesToday always returns an array of rows**, one per `target`, so a single pair is `rows[0].rate`. Open Exchange Rates always returns a `rates` object.

### 3. Non-USD base currency

**Open Exchange Rates (paid plans only):**

```
GET https://openexchangerates.org/api/latest.json?base=EUR&app_id=YOUR_APP_ID
```

On the free tier, this fails with `403` and message `"Changing the API \`base\` currency is available for Developer, Enterprise and Unlimited plan clients."`

**AllRatesToday (all plans, including free):**

```
GET https://allratestoday.com/api/v1/rates?source=EUR
```

Just works. If you're currently doing cross-rate math client-side because of the USD-only restriction, you can delete all of that code.

### 4. Historical rate for a specific date

**Open Exchange Rates:**

```
GET https://openexchangerates.org/api/historical/2025-06-15.json?app_id=YOUR_APP_ID
```

**AllRatesToday** (paid plans):

```
GET https://allratestoday.com/api/v1/rates?source=USD&target=EUR&time=2025-06-15
```

Response returns an array with one entry.

### 5. Time-series / range historical

**Open Exchange Rates** (counts 1 request per day):

```
GET https://openexchangerates.org/api/time-series.json?start=2025-01-01&end=2025-12-31&base=USD&symbols=EUR&app_id=YOUR_APP_ID
```

Response:

```
{
  "base": "USD",
  "rates": {
    "2025-01-01": { "EUR": 0.9521 },
    "2025-01-02": { "EUR": 0.9534 },
    ...
  }
}
```

**AllRatesToday** (paid plans, 1 request per month of data):

```
GET https://allratestoday.com/api/v1/rates?source=USD&target=EUR&from=2025-01-01&to=2026-01-01&group=day
```

One `target` per range request, up to 366 days, and the `to` date is exclusive. Response (daily rows, newest first):

```
[
  { "rate": 0.8519, "source": "USD", "target": "EUR", "time": "2025-12-31T00:00:00+0000" },
  { "rate": 0.8507, "source": "USD", "target": "EUR", "time": "2025-12-30T00:00:00+0000" },
  ...
  { "rate": 0.9521, "source": "USD", "target": "EUR", "time": "2025-01-01T00:00:00+0000" }
]
```

**Transformation** (OXR → ART shape):

```
const oxrRates = oxrResponse.rates;
const artRates = Object.entries(oxrRates)
  .map(([date, pair]) => ({
    rate: pair[target],
    source: 'USD',
    target,
    time: date + 'T00:00:00+0000'
  }))
  .reverse(); // ART lists newest first
```

### 6. Currency conversion

**Open Exchange Rates** (paid plans only):

```
GET https://openexchangerates.org/api/convert/1000/USD/EUR?app_id=YOUR_APP_ID
```

On the free tier, this returns `403` with `"The requested feature is not available on your current plan."`.

**AllRatesToday** (all plans, including free), via SDK:

```
await client.convert('USD', 'EUR', 1000);
// { from: 'USD', to: 'EUR', amount: 1000, rate: 0.9234, result: 923.4 }
```

Or raw HTTP (fetch the rate and multiply client-side — same pattern you likely already have for OXR free tier):

```
const [{ rate }] = await fetch('https://allratestoday.com/api/v1/rates?source=USD&target=EUR', {
  headers: { Authorization: 'Bearer YOUR_API_KEY' }
}).then(r => r.json());
const result = 1000 * rate;

// Or let the API do it: add amount= and read to.amount
// GET /api/v1/rates?source=USD&target=EUR&amount=1000
// { "from": { "currency": "USD", "amount": 1000 }, "to": { "currency": "EUR", "amount": 891.743 }, "rate": 0.891743, "source": "mid-market" }
```

### 7. List of supported currencies

**Open Exchange Rates:**

```
GET https://openexchangerates.org/api/currencies.json
```

Returns `{ "AED": "UAE Dirham", "AFN": "Afghan Afghani", ... }`.

**AllRatesToday:**

```
GET https://allratestoday.com/api/v1/symbols
Authorization: Bearer YOUR_API_KEY
```

Returns `{ "currencies": [{ "code": "USD", "name": "US Dollar", "symbol": "$" }, ...] }`, a list of objects rather than a code-to-name map.

## Authentication difference

Open Exchange Rates uses a query-string `app_id` parameter:

```
?app_id=YOUR_APP_ID
```

AllRatesToday uses a standard `Authorization: Bearer` header:

```
Authorization: Bearer YOUR_API_KEY
```

If your current code has URL builders that interpolate `app_id`, swap to an HTTP client that sets the auth header once globally. The SDKs do this for you.

## SDK drop-in replacements

Instead of replacing URLs by hand, replace your OXR client with AllRatesToday's SDK.

### JavaScript / TypeScript

```
npm install @allratestoday/sdk
```

```
import AllRatesToday from '@allratestoday/sdk';

const client = new AllRatesToday({ apiKey: process.env.ALLRATES_API_KEY! });

const { rate } = await client.getRate('USD', 'EUR');
const history = await client.getHistoricalRates('USD', 'EUR', '30d'); // paid plans
const { result } = await client.convert('USD', 'EUR', 1000);
```

### Python

```
pip install allratestoday
```

```
from allratestoday import AllRatesToday

client = AllRatesToday("YOUR_API_KEY")
rate = client.get_rates("USD", "EUR")[0]["rate"]
history = client.get_historical_rates("USD", "EUR", "30d")  # paid plans
```

### PHP

```
composer require allratestoday/sdk
```

```
use AllRatesToday\AllRatesToday;

$client = new AllRatesToday('YOUR_API_KEY');
$rate = $client->getRates('USD', 'EUR')[0]['rate'];
```

## Side-by-side validation

Keep both providers live for a week and compare results:

```
const [oxr, art] = await Promise.all([
  fetchOXR('USD', 'EUR'),
  fetchART('USD', 'EUR'),
]);
const diffBps = Math.abs(oxr - art) / art * 10000;
if (diffBps > 20) logger.warn({ oxr, art, diffBps }, 'rate mismatch');
```

For major pairs, you should see the two within ~20 basis points during normal market hours. Larger diffs usually mean one of the sources is stale (OXR hourly cadence) or you're comparing different market timestamps.

## After migration

Once you're on AllRatesToday:

- Delete any cross-rate math that existed to work around OXR's USD-only free tier.
- Reduce historical calls to one-per-range (instead of one-per-day) and reclaim quota.
- Swap any `/api/convert.json` workarounds for `client.convert()`.

## Rollback plan

Keep the OXR client wrapper behind a feature flag for two weeks. If anything goes wrong, flip back with a config change while you debug. Don't delete the OXR code until you've had a full billing cycle on AllRatesToday.

## Start your migration today

300 free requests, no credit card, 60-second rates, official SDKs for JS, Python, and PHP.

 [Get your free API key](https://allratestoday.com/register/)

## Related Articles

- [OXR Pricing vs AllRatesToday](https://allratestoday.com/blog/openexchangerates-pricing-vs-allratestoday/)
- [OXR USD Base Currency Problem](https://allratestoday.com/blog/openexchangerates-usd-base-currency-problem/)
- [Open Exchange Rates Alternative](https://allratestoday.com/compare/openexchangerates-alternative/)
