Code Examples

Next.js App Router with CurrencyCore

Add server-only CurrencyCore routes to Next.js, keep the API key off the client, and cache daily reference rates with revalidate.


Call CurrencyCore from a Route Handler or a Server Action, never from a Client Component. The key stays in process.env on the server, the browser receives only your response, and the Next.js data cache can hold a dated rate snapshot instead of refetching it for every visitor.

The example targets the App Router on Node.js 18 or later. Free includes 1,000 requests per month at 60 per minute. Live keys require a paid plan; test keys share the data and quota and are always capped at 60 per minute.

Keep the variable server-only. A NEXT_PUBLIC_ prefix inlines the value into the client bundle.

This route uses fetch directly instead of @currencycore/sdk for one reason: Next.js caching is configured through the next option on fetch, and the generated SDK does not expose that option. Everywhere else, the SDK is the shorter path.

import { NextResponse } from "next/server";

export async function GET(request: Request) {
  const key = process.env.CURRENCYCORE_API_KEY;
  if (!key) {
    return NextResponse.json(
      { error: { code: "missing_key", message: "Set CURRENCYCORE_API_KEY" } },
      { status: 500 },
    );
  }

  const { searchParams } = new URL(request.url);
  const url = new URL("https://api.currency-core.com/v1/convert");
  url.searchParams.set("from", searchParams.get("from") ?? "USD");
  url.searchParams.set("to", searchParams.get("to") ?? "INR");
  url.searchParams.set("amount", searchParams.get("amount") ?? "100");

  const res = await fetch(url, {
    headers: { Authorization: `Bearer ${key}`, Accept: "application/json" },
    signal: AbortSignal.timeout(10_000),
    next: { revalidate: 21_600 },
  });

  const body: unknown = await res.json();
  return NextResponse.json(body, { status: res.status });
}

A rate table is the same handler pointed at /v1/rates/EUR. The two responses look different:

{
  "from": "USD",
  "amount": 100,
  "date": "2026-11-10",
  "results": [{ "to": "INR", "result": 8345.0, "rate": 83.45 }]
}
{
  "base": "EUR",
  "date": "2026-11-10",
  "rates": { "EUR": 1, "USD": 1.0861, "INR": 91.62 }
}

Returning the upstream status keeps 400, 401, 403, and 429 visible to your client. Do not log the Authorization header. next.revalidate caches per URL, so every amount and target combination is a separate entry.

Caching behavior depends on the Next.js version and on whether the route uses dynamic APIs. In Next.js 15, a Route Handler that reads the Request is dynamic, while an explicit next.revalidate on the fetch still caches that request. Verify the cached response in your build, and prefer a stable key such as base + date over a free-form amount when you need a long TTL.

A Server Action uses the same fetch. Keep it in a "use server" module or mark the function, and validate the amount before forwarding it.

Next steps