Currency Exchange Rates API for Invoices: Which Rate to Use
When you issue an invoice in a foreign currency, two questions follow. Which rate converts the amounts into your reporting or tax currency? And which date does that rate come from? A currency exchange rates API for invoices has to answer both, and the answer is usually set by tax law, not by your preference. This guide covers the tax-point rule, the official rates that laws name, what to store on the invoice, and code to fetch an official rate for a given date.
The date: tax point or date of supply
Most VAT and GST systems tie the conversion to one date: the tax point, also called the time or date of supply. That is the date the tax becomes due. Depending on the country and the transaction, it can be the delivery date, the invoice date or the payment date.
So the rule for your code is simple. Do not use "today's rate" when the invoice is generated. Use the rate for the tax-point date. If you generate an invoice on 12 November for a supply on 9 November, the rate date should follow 9 November, under whatever rule applies to you.
Official rates named by law
Many tax systems name the source of the rate as well as the date. Some examples:
- UAE VAT. Article 69 of the VAT Decree-Law says amounts in a foreign currency are converted at the rate approved by the Central Bank of the UAE at the date of supply. The details, including weekends, are in our UAE VAT Article 69 guide.
- UK customs and VAT. HMRC sets official monthly exchange rates, released before the start of each month. They are the rates for customs declarations and an accepted option for VAT on imports and invoices. See the HMRC exchange rate API.
- EU VAT. Many EU countries allow the ECB euro reference rate for converting invoice amounts. Some also allow the national central bank's rate. Check your member state's rule.
- India GST. Rule 34 of the CGST Rules points to the CBIC customs rates for goods and to accounting-standard rates for services. See the GST invoice exchange rate guide.
The pattern is the same across these: an institution, a date rule, and a table. Your system should fetch from that institution's table, not from a payment provider or a card network.
Mid-market for display, official for the tax line
An invoice system often needs two different rates, used for two different jobs.
| Job | Rate | Why |
|---|---|---|
| Showing an estimated price in a quote or checkout | Mid-market, current | Closest to what the market is doing right now |
| Converting the VAT or GST amount on the invoice | The official rate the rule names | The tax authority checks against that table |
| Booking the invoice in the ledger | The rate your accounting policy names | Often the same official table, for consistency |
| Recording the payment received | The rate actually applied by the bank | Gives the realised FX gain or loss |
Mixing these up is the most common mistake. A live mid-market rate is the right number to show a customer a price. It is not the rate a VAT rule names. More on the difference in mid-market vs retail exchange rates.
What to store on the invoice
Store enough to reproduce the number later without calling any API.
- Rate. At the full precision of the official table. Round the converted amount once, not the rate.
- Source. The institution, such as "Central Bank of the UAE" or "HMRC".
- Rate date. The official date of the table you used. This may differ from the tax-point date on a weekend or holiday.
- Tax-point date. The date the rule refers to.
- Lookup time. When your system fetched the rate.
- Converted amounts. Net, tax and gross in the tax currency.
Several systems also require the rate to be printed on the invoice itself. UAE tax invoices are one example. Even where it is not required, printing "Rate: 4.112542 AED per EUR, Central Bank of the UAE, 9 November 2026" answers most questions before they are asked.
Fetching an official rate for a date
The AllRatesToday central bank endpoint returns an institution's official table for a date: GET /api/v1/central-bank/{bank}/{YYYY-MM-DD}. The response carries the requested date, the institution's own rate_date, and the rates.
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://allratestoday.com/api/v1/central-bank/cbuae/2026-11-08"
# "requested_date": "2026-11-08", "rate_date": "2026-11-06",
# "published_on_requested_date": false,
# "rates": [ ... { "base": "EUR", "quote": "AED", "type": "reference", "value": 4.091466 }, ... ] 8 November 2026 is a Sunday. The CBUAE does not issue rates at weekends, so the response returns Friday's table and says so. Here is the same lookup in JavaScript, with the fields you need to store:
async function officialRate(bank, date, base, quote) {
const res = await fetch(
`https://allratestoday.com/api/v1/central-bank/${bank}/${date}`,
{ headers: { Authorization: `Bearer ${process.env.ALLRATES_API_KEY}` } }
);
if (!res.ok) throw new Error(`Official rate lookup failed: ${res.status}`);
const table = await res.json();
const row = table.rates.find((r) => r.base === base && r.quote === quote);
if (!row) throw new Error(`${bank} has no ${base}/${quote} on ${table.rate_date}`);
return {
rate: row.value,
source: bank,
rateDate: table.rate_date,
taxPointDate: date,
publishedOnDate: table.published_on_requested_date,
fetchedAt: new Date().toISOString(),
};
}
// EUR invoice, VAT payable in AED, supply on 8 November 2026
const fx = await officialRate("cbuae", "2026-11-08", "EUR", "AED");
const netEur = 1000.0;
const vatEur = netEur * 0.05;
const vatAed = Math.round(vatEur * fx.rate * 100) / 100; // round once, at the end
console.log(`VAT AED ${vatAed.toFixed(2)} at ${fx.rate} (${fx.source}, ${fx.rateDate})`); A few points about this code:
- Direction. Each row has a
baseand aquote. Check you have the direction you need. If a table only quotesEUR/AED, thenAED/EURis1 / value. - Weekend fallback.
published_on_requested_date: falsetells you the table came from an earlier day. Store both dates so the fallback is visible in an audit. - Rounding. Use the full official precision in the multiplication. Round the tax amount once. For money in production, use integer minor units or a decimal library rather than floats.
- Cache by date. A past table does not change. Fetch it once per bank and date, then store it.
Swap cbuae for the institution your rule names: ecb, hmrc and the others are listed on the central bank rates API page. The @allratestoday/central-bank package on npm and allratestoday-central-bank on PyPI wrap the same endpoint. Dated tables and history are on paid plans, and the Official plan covers any past date with JSON, CSV, XML and XLSX output for ERP imports.
A checklist for your invoicing code
- The rate date follows the tax-point date, not the generation date.
- The source is the institution your tax rule names.
- Weekend and holiday fallback is written down and applied the same way every time.
- Rate, source, rate date and lookup time are stored with the invoice.
- Rounding happens once, on the converted amount.
- Display prices may use a live mid-market rate. The tax line does not.
If you are still choosing a provider for the display side, the free currency API comparison covers update frequency and limits. For the tax side, the question is simpler: which institution does the rule name, and can you get its table for a date.
FAQ
Which exchange rate should I use on a foreign-currency invoice?
For the tax amount, use the rate your tax rule names, taken on the tax point or date of supply. Many countries name an official rate, such as the Central Bank of the UAE rate for UAE VAT or HMRC's monthly rates for UK customs. For showing a price before the sale, a mid-market rate is fine.
Can I use a mid-market rate for VAT on an invoice?
Only if your tax rule allows it. Where the law names an official rate, use that rate for the tax line. A mid-market rate is a market snapshot, not the rate a tax authority names.
What should I store with each invoice?
Store the rate, the source institution, the official rate date of the table, the date you looked it up, and the converted amounts. That lets you reproduce the figure in an audit.
What if the date of supply is a weekend or a holiday?
Most central banks do not issue rates on non-working days. The usual practice is to use the latest table before the date. Write that fallback into your policy and apply it the same way every time.
Is this tax advice?
No. It is a developer's summary of common rules. Confirm the rule that applies to your business with your tax adviser or the tax authority.
The rate the rule names, by date
Official tables from 123 central banks and 6 tax authorities, each with the institution's own rate date, as JSON, CSV, XML or Excel. Dated tables are on paid plans.
See plans