Skip to content
JavaScript guide

Exchange rate API in JavaScript and Node.js

Call the fxapi currency API from Node.js with built-in fetch, add TypeScript types, and expose rates to your frontend through a Next.js route handler – without leaking your API key.

Last updated: · fxapi team

This guide covers everything you need to use an exchange rate API in JavaScript: a typed Node.js client built on the standard fetch, historical lookups, currency conversion, error handling for every status code, and a Next.js route handler that keeps your fxapi key on the server while your React components get the rates they need.

Setup

Sign up for a free key and put it in your server environment, for example in .env.local for Next.js:

FXAPI_KEY=your-api-key

Node.js 18+ has fetch built in, so the examples below have no dependencies. Every request goes to https://api.fxapi.com/v1/... with the key in the apikey header.

TypeScript types for the currency API

The latest, historical and convert endpoints share one response shape (range, fluctuation and average have their own – see the docs):

// fxapi.ts
export type RateEntry = { code: string; value: number };
export type RatesResponse = {
  meta: { last_updated_at: string };
  data: Record<string, RateEntry>;
};

export class FxApiError extends Error {
  constructor(
    public status: number,
    message: string,
    public errors?: Record<string, unknown>,
  ) {
    super(`${status}: ${message}`);
  }
}

An exchange rate API client in JavaScript (Node.js)

// fxapi.ts (continued)
const BASE_URL = "https://api.fxapi.com/v1";

export async function fxGet<T = RatesResponse>(
  path: string,
  params: Record<string, string | number> = {},
): Promise<T> {
  const url = new URL(BASE_URL + path);
  for (const [k, v] of Object.entries(params)) url.searchParams.set(k, String(v));

  const res = await fetch(url, {
    headers: { apikey: process.env.FXAPI_KEY ?? "" },
    signal: AbortSignal.timeout(10_000),
  });
  if (res.ok) return (await res.json()) as T;

  const body = await res.json().catch(() => ({}));
  switch (res.status) {
    case 401:
      throw new FxApiError(401, "Invalid API key");
    case 403:
      throw new FxApiError(403, "Endpoint or option not in your plan");
    case 422:
      throw new FxApiError(422, "Validation error", body.errors);
    case 429:
      throw new FxApiError(
        429,
        `Rate limit reached, monthly quota left: ${res.headers.get("X-RateLimit-Remaining-Quota-Month")}`,
      );
    default:
      throw new FxApiError(res.status, "Unexpected response");
  }
}

The 422 body includes an errors object keyed by parameter, which you can return to your own API callers. 429 means either the monthly quota is used up or – on the Free plan only – more than 10 requests were sent in a minute.

Get latest exchange rates in Node.js

const latest = await fxGet("/latest", { base_currency: "EUR", currencies: "USD,GBP,CHF" });

console.log(latest.meta.last_updated_at);
console.log(latest.data.USD.value); // USD per 1 EUR

Leave out currencies to get all 190+ currencies in one call, or filter by type=crypto or type=metal. Details: latest endpoint docs.

Historical rate on a specific date

const hist = await fxGet("/historical", {
  date: "2024-12-31",
  base_currency: "USD",
  currencies: "EUR,JPY",
});
console.log(hist.data.JPY.value);

date can be any day from 1999-01-01 up to yesterday; values are end-of-day rates in UTC. For full series use /v1/range on the Professional plan – see the time series API.

Currency conversion in JavaScript

With the Basic plan or higher, /v1/convert returns converted amounts:

const conv = await fxGet("/convert", { value: 99.5, base_currency: "USD", currencies: "EUR,GBP" });
console.log(conv.data.EUR.value);

On the Free plan, compute the conversion from the latest rates and format it with Intl.NumberFormat, which knows the correct decimals for each currency:

const { data } = await fxGet("/latest", { base_currency: "USD", currencies: "JPY" });
const yen = 99.5 * data.JPY.value;

const fmt = new Intl.NumberFormat("en-US", { style: "currency", currency: "JPY" });
console.log(fmt.format(yen)); // e.g. "¥14,925" – illustrative

For invoices and ledgers, work in integer minor units or a decimal library rather than floats – see currency rounding and precision.

Next.js route handler: keep the API key server-side

Never call fxapi with your key from browser code. Anything shipped to the client – including NEXT_PUBLIC_* variables – is visible to every visitor, who can then spend your quota. Instead, add a route handler that runs on the server and caches the upstream response:

// app/api/rates/route.ts
import { fxGet, FxApiError } from "@/lib/fxapi";

let cache: { body: unknown; at: number } | null = null;
const TTL_MS = 60 * 60 * 1000; // hourly updates on the Basic plan

export async function GET() {
  if (cache && Date.now() - cache.at < TTL_MS) {
    return Response.json(cache.body, { headers: { "Cache-Control": "public, max-age=300" } });
  }
  try {
    const latest = await fxGet("/latest", { base_currency: "USD" }); // one call, all currencies
    cache = { body: latest, at: Date.now() };
    return Response.json(latest, { headers: { "Cache-Control": "public, max-age=300" } });
  } catch (err) {
    if (cache) return Response.json(cache.body); // serve stale rates instead of failing
    const status = err instanceof FxApiError ? 502 : 500;
    return Response.json({ error: "Rates unavailable" }, { status });
  }
}

Your React components then call /api/rates and never see the key. The same pattern works in Express, Fastify, Cloudflare Workers or AWS Lambda: read the key from the environment, call fxapi from the server, cache, and return only what the client needs.

Serverless functions start cold and lose in-memory state, so for high traffic use a shared cache (Redis, Vercel KV, Cloudflare KV) as shown in the caching guide.

Caching and quota

  • Match the TTL to your plan’s update interval: daily on Free, hourly on Basic, 60 seconds on Professional and Enterprise (pricing).
  • One request, all currencies: fetch everything against one base and derive cross rates locally.
  • Cache historical rates forever – a past date’s rate doesn’t change.
  • Read the quota headers: X-RateLimit-Remaining-Quota-Month and X-Cost are on every response; /v1/status is free to call.

Using the official JavaScript SDK

@everapi/fxapi-js is an ES module with one method per endpoint (status, currencies, latest, historical, convert, range). Each takes an object of query parameters and returns a promise of the parsed JSON:

npm install --save @everapi/fxapi-js
import FxAPI from "@everapi/fxapi-js";

const fxApi = new FxAPI(process.env.FXAPI_KEY);

const latest = await fxApi.latest({ base_currency: "USD", currencies: "EUR" });
const hist = await fxApi.historical({ date: "2024-12-31", currencies: "EUR" });

The SDK resolves with the JSON body for every status code, so check for an errors field (or use the fxGet helper above) if you need distinct handling for 401, 403, 422 and 429.

Next steps

The examples in this guide use fxapi, a foreign exchange rate API with a free plan of 300 requests a month – no credit card required.

Frequently asked questions

Can I call the exchange rate API directly from the browser?
Technically yes, but anyone can read the key from your bundle or the network tab and use up your quota. Call fxapi from your server or a serverless function and let the browser call your endpoint instead.
Which Node.js version do I need?
Node.js 18 or newer ships a global fetch, so the examples need no dependencies. On older versions, install undici or node-fetch.
How do I convert currencies in JavaScript on the Free plan?
Fetch /v1/latest with your source currency as base_currency and multiply the amount by the target rate. /v1/convert does this server-side but needs the Basic plan or higher.
How should I format converted amounts?
Use Intl.NumberFormat with style: 'currency' – it applies the right number of decimals per currency, such as 0 for JPY. See currency rounding and precision.
Is there an official JavaScript SDK?
Yes, @everapi/fxapi-js on npm. It wraps each endpoint in a method that returns a promise of the parsed JSON.
Free plan · no credit card

Get your free exchange rate API key

300 requests a month, latest and historical rates, fluctuation and averages – free forever. Upgrade when you need faster updates or more requests.