ブラウザでは匿名リクエストから始められます。Node.js やサーバーではキーを環境変数に置き、レートの source と観測時刻も保存します。
- fetch は Node 18+、Deno、Bun、現代のブラウザで使える。
- ブラウザにアカウントキーを含めない。
- currency.js は金額計算と表示に使い、レート取得とは分ける。
- HTTP エラーを確認し、429 では Retry-After に従う。
- source と effective_at を表示してデータの時点を説明する。
最初のコール、キー不要
Node 18やモダンブラウザにはfetchが最初から入っている。EURレートを読むにはawait 1回で足りる:
匿名コールはIPアドレスごとに上限があるため、簡単な試験を超えたら無料キーに移行する。
キーとエラーハンドリングを追加する
キーはAuthorizationヘッダーのベアラートークンとして渡す。res.okを確認し、異常ステータスではthrowしてエラーを早期に表面化させる:
X-API-Key: exr_live_...ヘッダーも受け付けられる。Authorizationヘッダーを設定できないプラットフォーム(一部のサーバーレスランタイム、Zapierなどのノーコードツール)向けだ。
金額を換算する
直接換算するには/v1/convert/{from}/{to}/{amount}を呼ぶ。レスポンスは1往復でレートと換算額の両方を返す:
convertエンドポイントもlatestと同じsourceとmarket_sessionフィールドを返すため、レートの種別とインターバンクの取引週が開いているかをユーザーに示せる。
sourceとmarket_sessionを理解する
表示する通貨については、sources[currency]でデータの種類、effective_at[currency]で観測時刻を確認してください。sourceはレスポンス全体で最も更新頻度の低いデータを表します。market_sessionは市場の取引時間帯、timestampはレスポンスの生成時刻であり、価格の観測時刻ではありません。
| フィールド値 | 意味 | 動くタイミング |
|---|---|---|
| source: live | 参考用のスポット市場レート | 取引週の日中(約60秒間隔) |
| source: ecb_daily | 欧州中央銀行の参照フィックス | 営業日に1回(16:00 CET頃) |
| source: market_daily | ECBなしの保存終値 | 日次市場 |
| market_session: weekend | 土曜または日曜(インターバンク休場) | 参照フィックスは金曜値を維持、ライブフィードは停止 |
data_updated_atフィールドは元のレートが最後に書き込まれた時刻を示す。timestampはレスポンスが生成された時刻だ。この2つを合わせて、値のキャッシュ方法と表示方法を決められる。
これらのレートは参照、分析、表示向けに公開されている。ディーリングクォートではなく、取引や送金の決済に使ってはならない。すべてのレスポンスのnoticeフィールドにその旨が記載されている。
無料枠の上限
月間利用枠は毎月1日00:00 UTCにリセットされます。429の場合はRetry-Afterに従って再試行してください。
- 月5,000コール
- 毎分10リクエスト
- クレジットカード不要
/v1/latest、/v1/convert、/v1/range、/v1/{date}/{base}をカバー
金額を計算して表示する
currency.js は金額、精度、表示を扱うライブラリです。先に API からレートを取得し、その後で金額を掛けます。
const response = await fetch("https://api.exchangerate.dev/v1/latest/USD?symbols=EUR,GBP", { signal: AbortSignal.timeout(10_000),});if (!response.ok) throw new Error(`HTTP ${response.status}; Retry-After: ${response.headers.get("Retry-After")}`);const data = await response.json();console.log(data.rates.EUR);console.log(data.sources.EUR, data.effective_at.EUR);console.log(data.market_session);// Node.js server only. Never put an account key in browser code.const KEY = process.env.EXCHANGERATE_API_KEY;if (!KEY) throw new Error("Set EXCHANGERATE_API_KEY on your server");async function getLatest(base = "USD") { const response = await fetch(`https://api.exchangerate.dev/v1/latest/${encodeURIComponent(base)}`, { headers: { Authorization: `Bearer ${KEY}` }, redirect: "error", signal: AbortSignal.timeout(10_000), }); if (!response.ok) throw new Error(`HTTP ${response.status}; Retry-After: ${response.headers.get("Retry-After")}`); return response.json();}const data = await getLatest("USD");console.log(data.rates.GBP, data.effective_at.GBP);// Node.js server only.const KEY = process.env.EXCHANGERATE_API_KEY;if (!KEY) throw new Error("Set EXCHANGERATE_API_KEY on your server");const response = await fetch("https://api.exchangerate.dev/v1/convert/USD/EUR/100", { headers: { Authorization: `Bearer ${KEY}` }, redirect: "error", signal: AbortSignal.timeout(10_000),});if (!response.ok) throw new Error(`HTTP ${response.status}; Retry-After: ${response.headers.get("Retry-After")}`);const data = await response.json();console.log(data.rate, data.converted);import currency from "currency.js";const response = await fetch("https://api.exchangerate.dev/v1/latest/USD?symbols=EUR", { signal: AbortSignal.timeout(10_000),});if (!response.ok) throw new Error(`HTTP ${response.status}`);const data = await response.json();const rate = data.rates.EUR;if (!Number.isFinite(rate) || rate <= 0) throw new Error("Invalid rate");const euros = currency("100.00", { precision: 2, symbol: "€" }).multiply(rate);console.log(euros.format());