DEV Community

Madhushan
Madhushan

Posted on

live-currency-rates: One fluent API, three FX providers (no API key required to start)

Picking an FX data provider is one of those decisions you don't want to couple your code to. ECB data is free but only ~30 currencies. fawazahmed0/currency-api is free and covers crypto, but it's CDN-based. AllRatesToday gives you real-time Reuters data but needs a key. Each has different endpoints, shapes, and auth.

live-currency-rates is a tiny wrapper that hides all of that behind a fluent API. Write your code once; swap providers with one line when requirements change.

The API you actually write

import { Convert } from 'live-currency-rates';

const result = await Convert(100).from('USD').to('EUR');
console.log(result.amount); // 92.45
Enter fullscreen mode Exit fullscreen mode

That's it. No setup needed to start — defaults to the free Frankfurter provider (ECB data, no key, no signup).

Install

npm install live-currency-rates
Enter fullscreen mode Exit fullscreen mode

Zero dependencies. TypeScript types included.

Three providers, one interface

Provider Key? Currencies Source Notes
frankfurter no ~30 European Central Bank Default. Daily updates.
fawaz no 200+ fawazahmed0/currency-api Includes crypto. CDN-hosted.
allrates yes 160+ AllRatesToday (Reuters) Real-time mid-market rates.

Pick one with setup():

import { setup, Convert } from 'live-currency-rates';

// Free, no key — 200+ currencies including crypto
setup({ provider: 'fawaz' });

// AllRatesToday — real-time Reuters rates, free key at allratestoday.com/register
setup({ apiKey: 'art_live_...' });
Enter fullscreen mode Exit fullscreen mode

Your existing Convert(...) calls don't change. That's the point.

Core API

Convert(amount).from(...).to(...)

const result = await Convert(250).from('GBP').to('JPY');
console.log(`250 GBP = ${result.amount} JPY`);
console.log(`Rate: ${result.rate}`);
Enter fullscreen mode Exit fullscreen mode

Returns { amount, rate, from, to, originalAmount }.

Rate('XXX').to('YYY')

import { Rate } from 'live-currency-rates';

const { rate } = await Rate('USD').to('EUR');
console.log(`1 USD = ${rate} EUR`);
Enter fullscreen mode Exit fullscreen mode

Rates('XXX', ['YYY', 'ZZZ'])

One round-trip, multiple pairs:

import { Rates } from 'live-currency-rates';

const rates = await Rates('USD', ['EUR', 'GBP', 'JPY']);
// { EUR: 0.92, GBP: 0.78, JPY: 149.5 }
Enter fullscreen mode Exit fullscreen mode

Omit the target list to get every available rate for that base.

Why a wrapper?

Three reasons it earns its keep:

  1. Start free, upgrade later. Ship the MVP with Frankfurter. When you hit a currency Frankfurter doesn't cover, flip to fawaz or allrates without touching call sites.
  2. Test without hitting production. Point tests at Frankfurter; point prod at AllRatesToday. Same code.
  3. Provider lock-in is costly. Every provider has different endpoint shapes. A fluent wrapper means a future provider migration is one file change, not a rewrite.

When you outgrow the wrapper

The wrapper optimizes for "I don't care which provider yet." If you've settled on a provider and need its full feature set, drop to the native client:

  • AllRatesToday only? Use @allratestoday/sdk — full API: historicals, time-series, preset periods.
  • Just want a one-liner + CLI? Use fx-rates.
  • Need cashify-compatible sync conversion? Use moneyify.

Next steps

Which provider did you land on, and why? Comments open.

Top comments (0)