Exchange Rate API Cheat Sheet: curl and jq Commands
This is an exchange rate API quick reference for the terminal. Every command below calls a real AllRatesToday endpoint with curl, and most pipe into jq to pull out exactly the number you want. Copy the setup block once, then use the sections as a cheat sheet.
Setup: keep the key out of shell history
Never paste the key into a command. It ends up in ~/.bash_history and in screenshots. Read it once into an environment variable instead:
read -rs ALLRATES_API_KEY && export ALLRATES_API_KEY # type or paste, nothing is echoed
export BASE=https://allratestoday.com
export AUTH="Authorization: Bearer $ALLRATES_API_KEY" Or keep it in a file only you can read:
mkdir -p ~/.config/allratestoday && chmod 700 ~/.config/allratestoday
read -rs k && printf '%s' "$k" > ~/.config/allratestoday/key && unset k
chmod 600 ~/.config/allratestoday/key
export ALLRATES_API_KEY="$(cat ~/.config/allratestoday/key)" History now records $AUTH, never the key. Every request authenticates with the Authorization: Bearer header.
Latest rate for one pair
curl -s "$BASE/api/v1/rates?source=USD&target=EUR" -H "$AUTH"
# [{"rate":0.9215,"source":"USD","target":"EUR","time":"2026-04-03T12:00:00Z"}]
curl -s "$BASE/api/v1/rates?source=USD&target=EUR" -H "$AUTH" | jq '.[0].rate'
# 0.9215 The response is an array even for one pair. jq '.rate' returns null; use .[0].rate.
For a flat object with just the rate, use /api/rate:
curl -s "$BASE/api/rate?source=GBP&target=USD" -H "$AUTH"
# {"rate":1.2634,"source":"mid-market"}
curl -s "$BASE/api/rate?source=GBP&target=USD" -H "$AUTH" | jq -r .rate Rates are mid-market, refreshed every 60 seconds. The time field says which snapshot you got.
Many targets in one request
A comma-separated target returns one array and costs one request:
curl -s "$BASE/api/v1/rates?source=USD&target=EUR,GBP,JPY,CAD" -H "$AUTH" \
| jq 'map({(.target): .rate}) | add'
# {"EUR":0.9215,"GBP":0.7891,"JPY":151.37,"CAD":1.3842} As tab-separated lines, ready for sort or column:
curl -s "$BASE/api/v1/rates?source=USD&target=EUR,GBP,JPY,CAD" -H "$AUTH" \
| jq -r '.[] | "\(.target)\t\(.rate)"' | sort -k2 -n Let curl build the query string when values come from variables:
FROM=USD; TO=EUR,GBP
curl -sG "$BASE/api/v1/rates" -H "$AUTH" \
--data-urlencode "source=$FROM" --data-urlencode "target=$TO" Convert an amount
Add amount to the same endpoint with exactly one target. Conversion is on the Medium plan and above.
curl -s "$BASE/api/v1/rates?source=USD&target=EUR&amount=1000" -H "$AUTH"
# {"from":{"currency":"USD","amount":1000},"to":{"currency":"EUR","amount":923.4},"rate":0.9234,"source":"mid-market"}
curl -s "$BASE/api/v1/rates?source=USD&target=EUR&amount=1000" -H "$AUTH" | jq '.to.amount'
# 923.4 to.amount is rounded to 6 decimal places; rate keeps full precision. There is no /api/convert endpoint.
Historical mid-market rates
History takes a period preset: 1d, 7d, 30d or 1y. The default is 7d, an unknown value silently becomes 7d, and from and to are ignored. History is on paid plans.
curl -s "$BASE/api/historical-rates?source=USD&target=EUR&period=30d" -H "$AUTH" \
| jq '.data | length' Lowest and highest point in the period:
curl -s "$BASE/api/historical-rates?source=USD&target=EUR&period=30d" -H "$AUTH" \
| jq '.data | (min_by(.rate) | {low: .rate, date}), (max_by(.rate) | {high: .rate, date})' Average, and the change from first to last point:
curl -s "$BASE/api/historical-rates?source=USD&target=EUR&period=30d" -H "$AUTH" \
| jq '[.data[].rate] | {avg: (add / length), change: (.[-1] - .[0])}' Save as CSV:
curl -s "$BASE/api/historical-rates?source=USD&target=EUR&period=1y" -H "$AUTH" \
| jq -r '"date,rate", (.data[] | [.date, .rate] | @csv)' > usd-eur-1y.csv Billing notes: 1y returns weekly points and costs 12 requests. 1d is an interpolated chart shape, not real intraday data.
Supported currencies
curl -s "$BASE/api/v1/symbols" -H "$AUTH" | jq '.currencies | length'
curl -s "$BASE/api/v1/symbols" -H "$AUTH" \
| jq -r '.currencies[] | "\(.code)\t\(.symbol)\t\(.name)"'
# exit code 0 if the code exists, 1 if not
curl -s "$BASE/api/v1/symbols" -H "$AUTH" | jq -e '.currencies | any(.code == "XOF")' Official central bank rates
Latest official table for a bank, with its own rate_date:
curl -s "$BASE/api/v1/central-bank/ecb/latest" -H "$AUTH" | jq '{rate_date, n: (.rates | length)}'
# one quote from the table
curl -s "$BASE/api/v1/central-bank/ecb/latest" -H "$AUTH" \
| jq '.rates[] | select(.quote == "USD") | .value' One pair, computed from the bank's table:
curl -s "$BASE/api/v1/central-bank/ecb/latest?source=USD&target=EUR" -H "$AUTH" \
| jq '{rate, rate_date}' The table for a past date. A weekend or holiday returns the most recent table, and rate_date shows which:
curl -s "$BASE/api/v1/central-bank/ecb/2026-11-10" -H "$AUTH" | jq .rate_date A date range for one pair. This is on paid plans and billed per month of the range, so the example below is three months:
curl -s "$BASE/api/v1/central-bank/ecb/history?source=USD&target=EUR&from=2026-01-01&to=2026-03-31" \
-H "$AUTH" -o ecb-usd-eur-q1.json Replace ecb with any of the 123 central bank and 6 tax authority codes listed on the central bank rates API page.
CSV, Excel and XML
Table endpoints accept ?format=json|csv|xml|xlsx. Write files with -o:
curl -s "$BASE/api/v1/central-bank/ecb/latest?format=csv" -H "$AUTH" -o ecb.csv
curl -s "$BASE/api/v1/central-bank/ecb/latest?format=xlsx" -H "$AUTH" -o ecb.xlsx
curl -s "$BASE/api/v1/central-bank/ecb/latest?format=xml" -H "$AUTH" -o ecb.xml The CSV starts with a UTF-8 byte order mark so Excel reads it correctly. Strip it for command-line tools:
sed '1s/^\xEF\xBB\xBF//' ecb.csv | column -s, -t | head Status codes and quota headers
Print only the status code:
curl -s -o /dev/null -w '%{http_code}\n' "$BASE/api/rate?source=USD&target=EUR" -H "$AUTH" See headers and body together:
curl -si "$BASE/api/rate?source=USD&target=EUR" -H "$AUTH" On a 429, the quota headers tell you where you stand:
curl -s -D - -o /dev/null "$BASE/api/rate?source=USD&target=EUR" -H "$AUTH" | grep -i '^x-monthly'
# x-monthly-limit: ...
# x-monthly-used: ...
# x-monthly-resets: ... These headers appear only on 429 responses. A 200 carries no rate-limit headers, so an empty grep on a successful call is normal.
A 401 means a missing or wrong key:
curl -s "$BASE/api/rate?source=USD&target=EUR" # no Authorization header
# {"error":"A valid API key is required","hint":"Get a free API key at https://allratestoday.com/register"} Rejected 401, 403 and 429 requests are not charged. In scripts, use --fail-with-body so curl exits non-zero on an error status and still prints the JSON error.
Endpoint summary
| Task | Endpoint |
|---|---|
| One pair, array | /api/v1/rates?source=USD&target=EUR |
| One pair, flat | /api/rate?source=GBP&target=USD |
| Many targets, one request | /api/v1/rates?source=USD&target=EUR,GBP,JPY |
| Convert (Medium+) | /api/v1/rates?source=USD&target=EUR&amount=1000 |
| History (paid) | /api/historical-rates?source=USD&target=EUR&period=30d |
| Currencies | /api/v1/symbols |
| Official latest | /api/v1/central-bank/ecb/latest |
| Official by date | /api/v1/central-bank/ecb/2026-11-10 |
| Official range (paid) | /api/v1/central-bank/ecb/history?source=USD&target=EUR&from=...&to=... |
There are no /api/latest, /api/convert or /api/timeseries endpoints; those paths return 404. The API docs have the full reference, and the free currency API comparison covers other providers if you are still choosing.
FAQ
Why does jq '.rate' return null on /api/v1/rates?
Because the response is an array, even for one pair. Use '.[0].rate', or map the array to an object with 'map({(.target): .rate}) | add'.
Can I pass from and to dates to /api/historical-rates?
No. That endpoint takes a period of 1d, 7d, 30d or 1y and ignores from and to. An unknown period silently falls back to 7d. For an exact date range of official rates, use /api/v1/central-bank/ecb/history with from and to.
Why do I not see X-RateLimit headers?
Successful responses carry no rate-limit headers. The X-Monthly-Limit, X-Monthly-Used and X-Monthly-Resets headers appear only on a 429. Check them with curl -i or curl -D -.
How do I keep my API key out of shell history?
Read it with read -rs, which does not echo or record what you type, or load it from a file with chmod 600. Commands then refer to $ALLRATES_API_KEY, so history only ever stores the variable name.
How do I open the CSV in Excel without odd characters?
The CSV starts with a UTF-8 byte order mark so Excel detects the encoding. Excel handles it. For command-line tools, strip it with sed '1s/^\xEF\xBB\xBF//'.
Try every command with your own key
Mid-market rates for 160+ currencies refreshed every 60 seconds, and official tables from 123 central banks and 6 tax authorities as JSON, CSV, XML or Excel.
Get a free API key