Once multicurrency is on, QuickBooks Online downloads market rates automatically. It also lets you enter your own rate per currency per day, and that override is a first-class API object: ExchangeRate in the Accounting API, keyed by source currency and AsOfDate. Transactions dated that day pick the override up unless a rate was set on the transaction itself.
That means the whole "book at the central bank's rate" integration is one POST per currency per day. The full guide is on AllRatesToday: QuickBooks Online integration.
The rate QuickBooks expects
Rate is home-currency units per 1 unit of SourceCurrencyCode. For a USD company and EUR that is USD per EUR. Rather than working out whether the bank publishes that direction, ask the API for the pair directly. It inverts or crosses when needed and tells you:
GET https://allratestoday.com/api/v1/central-bank/ecb/latest?source=EUR&target=USD
Authorization: Bearer art_live_your_key
{ "bank": "ecb", "rate_date": "2026-10-09", "source": "EUR", "target": "USD",
"rate": 1.1206, "derived": false, "method": "published" }
The daily sync
import requests
REALM = "1234567890"
QBO = f"https://quickbooks.api.intuit.com/v3/company/{REALM}"
QBO_H = {"Authorization": f"Bearer {qbo_access_token}", "Accept": "application/json"}
ART_H = {"Authorization": "Bearer art_live_your_key"}
BANK, HOME = "ecb", "USD"
# 1. currencies enabled in the company
q = requests.get(f"{QBO}/query", headers=QBO_H,
params={"query": "SELECT * FROM CompanyCurrency", "minorversion": 75}).json()
codes = [c["Code"] for c in q["QueryResponse"].get("CompanyCurrency", [])]
# 2. one official rate per currency, home units per 1 foreign unit
for code in codes:
r = requests.get(f"https://allratestoday.com/api/v1/central-bank/{BANK}/latest",
params={"source": code, "target": HOME}, headers=ART_H, timeout=10)
if r.status_code == 404: # bank does not cover this currency
continue
body = r.json()
payload = {"SourceCurrencyCode": code, "AsOfDate": body["rate_date"], "Rate": body["rate"]}
requests.post(f"{QBO}/exchangerate", headers=QBO_H, params={"minorversion": 75}, json=payload).raise_for_status()
print(code, body["rate_date"], body["rate"], "derived" if body["derived"] else "published")
Run it after the bank's publication time each business day. Re-posting the same currency and date updates the rate in place, so a rerun is safe, and a bank that amends its table (it happens) is handled by simply running again.
Three things to know
- Pairs are always foreign to home in QuickBooks. There is no cross-pair table to maintain.
- US companies often need the US Treasury quarterly table rather than a daily central-bank rate. Same loop, different bank code, quarterly schedule.
-
Per-transaction override is still available. If only some documents need the official rate, set
ExchangeRateon the invoice or bill body instead of the company table. Same meaning: home units per 1 unit of document currency.
Try it without a key
https://allratestoday.com/api/open/central-bank/ecb returns the latest ECB table keyless, so you can see what the bank covers before you sign up. The keyed endpoint adds the pair resolution and dated history.
Links
- QuickBooks guide: https://allratestoday.com/docs/integrations/quickbooks/
- Xero (which has no org-level rate table, so the approach differs): https://allratestoday.com/docs/integrations/xero/
- 121 central banks and 3 tax authorities: https://allratestoday.com/central-bank-rates-api/
- Free API key: https://allratestoday.com/register/
Rates are redistributed from each institution's public publication. They are reference rates for accounting, tax and compliance, not dealing quotes.
Top comments (0)