Use casesUse case

Exchange rate API for expense reports

Two euro receipts, one on a Monday and one on a Saturday, converted to dollars

8 Nov 2026 · 2 min read

An expense tool converts each receipt at the rate of the day it was dated. The date endpoint returns the daily reference rate for that day. When the day had no fixing, a weekend or a holiday, it returns the last published rate and says so in the response, so the report can show it.

Convert each receipt on its own date

Two receipts: 84.50 EUR dated Monday 12 October, and 41.20 EUR dated Saturday 10 October. The script asks for the rate on each date and prints the fields a report needs.

Python
import json, urllib.requestfrom decimal import Decimaldef get(path):    return json.load(urllib.request.urlopen(f"https://api.exchangerate.dev/v1/{path}"))expenses = [("2026-10-12", "EUR", Decimal("84.50")), ("2026-10-10", "EUR", Decimal("41.20"))]for date, ccy, amount in expenses:    day = get(f"{date}?base={ccy}&symbols=USD")    rate = Decimal(str(day["rates"]["USD"]))    print(date, f"{amount} {ccy} x {rate} = {amount * rate:.2f} USD", "| forward-filled:", day["is_forward_filled"], "| rate dated", day["data_updated_at"][:10])
Output
2026-10-12 84.50 EUR x 1.1181 = 94.48 USD | forward-filled: False | rate dated 2026-10-122026-10-10 41.20 EUR x 1.1206 = 46.17 USD | forward-filled: True | rate dated 2026-10-09

Weekends and holidays

Saturday 10 October has no fixing. The API returned the Friday rate, 1.1206, and set is_forward_filled to true. Friday is the last rate the market published before the receipt date, and most finance teams accept it. Show the flag in the report, so an auditor sees the date the rate really comes from.

Pick a policy and apply it everywhere

  • Receipt date. Use the rate on the date printed on the receipt. This is the default above. For card spend, pass the settlement date instead.
  • Report date. Use one rate for the whole report, such as the last day of the trip.

Whichever you choose, store the rate and the date it came from next to the converted amount. Approvers can then check a total without calling the API.

How far back you can go

Reports are often filed weeks late. The Free plan returns daily rates for the last 30 days. Basic ($19 a month) goes back a year, and Plus ($39 a month) covers history back to 1999. A request older than the window returns a plan_gated error with the earliest allowed date, so the failure is clear and the app can tell the user what to do.

Round after multiplying

Multiply the full receipt amount by the full rate, then round to the report currency's decimal places. Rounding the rate first moves a total by cents once an expense report holds a few hundred lines.

Indicative rates

The daily reference rates are indicative. A tax authority may require its own rate. The official rates pages list the tables that tax offices publish and the guide on choosing an official rate covers when to switch.

Questions

What does is_forward_filled mean?

It is true when the requested date had no published daily rate and the response carries the previous business day's rate. `data_updated_at` shows which day that was.

Can I convert a whole report in one request?

Receipts on different dates need one request per distinct date. Group receipts by date and currency, then ask once for each pair.

What happens for a date outside my plan?

The API returns a `plan_gated` error that names your history window and the earliest date you can request.

Keep reading

Run this against the live API

The Free plan gives 5,000 requests a month and 10 a minute. Commercial use is allowed with a visible, linked credit. Calls without a key work at 100 an hour per IP address.

Get a free key