# Migrate from CurrencyLayer

> Move a CurrencyLayer integration to CurrencyCore: access_key to bearer auth, live and historical mapping, quotes to rates conversion, 60-second tier comparison, and caveats.

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

---
CurrencyLayer returns a snapshot with `quotes` keyed by concatenated pairs, such
as `USDEUR`. CurrencyCore returns `rates` keyed by ISO code and a `results[]`
array for conversions. The host, auth header, and key shape change. The ISO
codes and the units-per-base arithmetic stay the same.

Public CurrencyLayer pricing and coverage below were checked on **2026-11-10**.
Verify the vendor's current plans before you budget.

## What changes at a glance

| Area | CurrencyLayer | CurrencyCore |
|---|---|---|
| Currencies | 168 currencies plus precious metals | 160 fiat currencies, no metals quoted |
| History | 1999 onward | GBP/USD and USD/INR parity from 1949, daily majors from 1971, EUR pairs from 1999 |
| Free quota | 100 requests/mo, daily, non-commercial | 1,000 requests/mo, 60/min, test keys |
| Entry paid plan | Basic, $14.99/mo, hourly | Starter, $9/mo, full history |
| 60-second updates | Enterprise+, $99.99/mo | Not offered |
| Auth | `access_key` query parameter | `Authorization: Bearer` or `x-api-key` |
| Response shape | `quotes` keyed by pair | `rates` keyed by ISO code |

The 60-second tier is the honest break point. CurrencyCore does not sell
sub-minute executable quotes. If your product needs them, CurrencyLayer is the
better fit. If you need reference rates, longer history, PPP, or analytics,
CurrencyCore covers that at a lower entry price.

## 1. Replace access_key with a bearer token

CurrencyLayer examples put the key in the URL:

```bash
curl "https://api.currencylayer.com/live?access_key=YOUR_KEY&source=USD"
```

CurrencyCore uses a header:

```bash
curl "https://api.currency-core.com/v1/rates/USD" \
  -H "Authorization: Bearer cc_live_your_key"
```

Remove `access_key` from every URL, log line, and fixture. A test key is enough
while integrating; live keys require a paid plan. See
[Authentication](/docs/authentication/).

## 2. Map endpoints

| CurrencyLayer endpoint | CurrencyCore endpoint | Mapping note |
|---|---|---|
| `/live` | `/v1/rates` | USD base only |
| `/live?source=EUR` | `/v1/rates/EUR` | The base moves from query to path |
| `/historical?date=YYYY-MM-DD` | `/v1/rates/{base}?date=YYYY-MM-DD` | Use `/v1/convert?date=` for a dated amount |
| `/convert?from=USD&to=EUR&amount=100` | `/v1/convert?from=USD&to=EUR&amount=100` | Read `results[0].result` |
| `/timeframe?start_date=&end_date=` | `/v1/history?currency=EUR&from=&to=` | One currency per call |
| `/change?start_date=&end_date=` | `/v1/history/analysis` | Growth or higher. Not a field-for-field match. |

`/timeframe` returns a pair-keyed map for several currencies at once.
CurrencyCore's `/v1/history` returns one dense date-to-rate map per currency, so
split a multi-currency timeframe call into one call per currency or loop over the
codes you need.

## 3. Convert quotes to rates

A CurrencyLayer live response:

```json
{
  "success": true,
  "source": "USD",
  "quotes": {
    "USDUSD": 1,
    "USDEUR": 0.9214,
    "USDINR": 84.07
  }
}
```

The CurrencyCore equivalent:

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

The transformation is mechanical: remove the three-letter source prefix from
each quote key and use the remainder as the ISO code. The base itself appears as
`1` in both envelopes. Do not split on a fixed character count if you also carry
non-ISO codes; use the known base length for the current response instead.

A CurrencyLayer conversion:

```json
{ "success": true, "result": 92.14 }
```

becomes:

```json
{ "from": "USD", "amount": 100, "date": "2026-11-10", "results": [{ "to": "EUR", "result": 92.14, "rate": 0.9214 }] }
```

The amount is `results[0].result` and the rate is `results[0].rate`. When `to`
contains several targets, match each entry by `results[].to`.

A CurrencyLayer historical response uses the same `quotes` shape with a
`historical: true` flag and a date. Map it to `/v1/rates/{base}?date=`. If you
need an amount rather than a rate, use `/v1/convert?from=&to=&amount=&date=`.

| CurrencyLayer field | CurrencyCore field | Note |
|---|---|---|
| `source` | `base` | Use `/v1/rates/{base}` for a non-USD source |
| `quotes.USDEUR` | `rates.EUR` | Strip the source prefix |
| `result` | `results[0].result` | Conversions use an array |
| `success` | HTTP status | Failures use the error envelope |
| `timestamp` | none | Use `date`, a UTC calendar date |
| `start_date` and `end_date` | `from` and `to` | Inclusive UTC dates |

See [Errors](/docs/errors/) for the stable error codes.

## 4. Account for the coverage differences

CurrencyLayer advertises **168 currencies plus precious metals** and history from
**1999**. CurrencyCore advertises **160 fiat currencies** and does not quote
metals. Before cutover:

- Diff every code you store against `/v1/currencies`. Some CurrencyLayer codes
  may not be quoted, and metals are not in the CurrencyCore rate feed.
- If you use `XAU`, `XAG`, or another metal, keep a dedicated metals provider.
  CurrencyCore lists `XAU` and `XAG` as reference entries, not quoted rates.
- Check history depth per pair. CurrencyCore's 1949 start is annual parity for
  GBP/USD and USD/INR, not a daily series for every currency.
- Free history is limited to the last **30 days**. Starter and above get full
  history.

Public plan comparison at the time of writing:

| CurrencyLayer tier | Price | Requests | Cadence |
|---|---|---|---|
| Free | $0 | 100/mo | Daily, non-commercial |
| Basic | $14.99/mo | 10,000/mo | Hourly |
| Enterprise+ | $99.99/mo | 500,000/mo | 60 seconds |

CurrencyCore starts at **$9/mo** for 50,000 requests and full history, but its
reference rates are polled hourly and the underlying fixings are daily. It has
no 60-second tier. See [Pricing](/pricing/) for the current CurrencyCore plans.

## 5. Cut over

1. Create a test key and replace `access_key` with the bearer header.
2. Map `/live` to `/v1/rates` or `/v1/rates/{base}`.
3. Convert `quotes` objects to `rates` objects in one adapter function.
4. Map `/convert` and read `results[0]`.
5. Split multi-currency `/timeframe` calls into one `/v1/history` call per
   currency, or keep the old adapter until that path is ready.
6. Shadow requests and compare the same fixing dates, not the same wall-clock
   timestamps.
7. Switch reads, watch `401`, `403`, and `429`, then revoke the old key.
8. Keep rollback available until the next billing cycle.

For the provider-neutral checklist, see
[Migrate an existing integration](/docs/guides/migration/).

## Related

- [Migration overview](/docs/guides/migration/)
- [OpenAPI specification](/docs/openapi/)
- [Authentication](/docs/authentication/)
- [Errors](/docs/errors/)
- [Rate limits](/docs/rate-limits/)
- [All integration guides](/docs/guides/)
- [`/rates` endpoint](/docs/rates-endpoint/)
- [`/convert` endpoint](/docs/convert-endpoint/)
- [`/history` endpoint](/docs/history-endpoint/)
