多通貨請求書向け為替レートAPI

元の金額と使用レートを失わずに、1つの通貨で請求し、別の通貨でレポートできます。日付指定レートを取得し、金額を一度だけ丸め、根拠を保存します。

請求日でレートを固定する

送付済みの請求書は、後から開いても同じ金額を示す必要があります。別の通貨で参考額を表示するなら、請求日のレートを取得して結果を保存します。古い書類を今日のレートで計算し直しません。顧客、サポート、経理が同じ数字を確認できる状態にします。

どの日付を使うかは業務ルールで決まります。発行日を使うシステムもあれば、サービス提供日や計上日を使うシステムもあります。APIは指定日の値を返しますが、採用する日付は契約と会社方針が決めます。

元の金額と換算結果を両方残す

currencyとamountを元データとして保存します。さらにreporting_currency、converted_amount、rate、指定日、data_updated_at、source、is_forward_filledを保存します。この形なら、PDFの再作成、顧客からの問い合わせ、会計ソフトへの出力で、以前使ったレートを推測する必要がありません。

換算額は対象通貨の小数桁に合わせて丸めます。JPYは通常0桁、多くの通貨は2桁です。レートは全桁を保存し、各行を何度も丸めません。合計額に対して丸めるルールなら、先に請求書の小計を計算します。

クレジットノートにも同じルールを使う

クレジットノートには元の請求書と使用したレートのルールを記録します。全額を取り消すなら、元の請求レートを使うとレポート上の金額もきれいに反転します。クレジットノートの日付のレートを使う方針なら、新しいレートを別の記録として保存します。

訂正のために元の請求記録を書き換えません。訂正文書、元の金額、換算額、請求書との関係を残します。更新のたびに1つの行を書き換えるより、この履歴の方が照合しやすくなります。

請求額と実際の入金結果を分ける

請求書に使うレートは、表示やレポート向けの参考値です。実際の決済額、手数料、適用レートは銀行や決済代行会社が決めます。入金時には決済記録を保存し、請求書の値と比較します。差額は会社の会計方針に従って処理します。

海外向け請求では、この区別が大切です。exchangerate.devは一貫した表示とレポート作成を助けますが、売り手の受取額や顧客の支払額を保証しません。決済の事実には、決済事業者の記録を使います。

日付指定レートでJPY請求書を作る

APIキーはサーバー側に置きます。この例では、計算結果と一緒に為替レートと出典情報を保存します。

TypeScript · サーバー側の多通貨請求
import Decimal from 'decimal.js';

type HistoricalRates = {
  date: string;
  rates: Record<string, number>;
  source: 'ecb_daily' | 'fred_daily' | 'nbp_daily';
  data_updated_at: string;
  is_forward_filled: boolean;
};

const invoice = {
  id: 'invoice_2207',
  issuedOn: '2026-07-15',
  currency: 'USD',
  total: '2400.00',
  displayCurrency: 'JPY',
} as const;

const response = await fetch(
  `https://api.exchangerate.dev/v1/${invoice.issuedOn}/${invoice.currency}?symbols=${invoice.displayCurrency}`,
  { headers: { Authorization: `Bearer ${process.env.EXR_API_KEY}` } },
);
if (!response.ok) throw new Error('Could not load the invoice-date FX rate');

const fx = (await response.json()) as HistoricalRates;
const rawRate = fx.rates[invoice.displayCurrency];
if (!Number.isFinite(rawRate)) throw new Error('Missing USD/JPY rate');

// JPY is a zero-decimal currency. Keep rate at full precision.
const rate = new Decimal(String(rawRate));
const displayTotal = new Decimal(invoice.total)
  .mul(rate)
  .toDecimalPlaces(0, Decimal.ROUND_HALF_UP)
  .toFixed(0);

await saveInvoiceFx({
  invoice_id: invoice.id,
  original_currency: invoice.currency,
  original_total: invoice.total,
  display_currency: invoice.displayCurrency,
  display_total: displayTotal,
  fx_rate: rate.toString(),
  fx_requested_date: fx.date,
  fx_source: fx.source,
  fx_observed_at: fx.data_updated_at,
  fx_is_forward_filled: fx.is_forward_filled,
});

APIを試してみますか?

クイックスタートを読み、レスポンス項目を確認してください。アカウントの利用枠が必要になったら料金も確認できます。

Freeは評価および社内の非商用利用向けです。BasicとProは商用利用に対応します。

無料の評価用キーを作成 →