---
title: "Exchange Rate API Cheat Sheet: curl and jq Commands"
description: "Exchange rate API quick reference for the command line: curl calls for latest, convert, history, symbols and central bank tables, plus jq one-liners."
canonical: https://allratestoday.com/blog/exchange-rate-api-curl-jq-cheat-sheet/
source: AllRatesToday (https://allratestoday.com/) — Markdown mirror of the page above; index of all pages at https://allratestoday.com/llms.txt
generated: 2026-11-11T15:57:44.466Z
---

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](https://allratestoday.com/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](https://allratestoday.com/docs/) have the full reference, and the [free currency API comparison](https://allratestoday.com/blog/best-free-currency-exchange-api-2026/) 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](https://allratestoday.com/central-bank-rates-api/institutions/) as JSON, CSV, XML or Excel.

 [Get a free API key](https://allratestoday.com/register)

## Related Articles

- [API documentation](https://allratestoday.com/docs/)
- [Central bank exchange rates API](https://allratestoday.com/central-bank-rates-api/)
- [How to cache exchange rates and avoid rate limits](https://allratestoday.com/blog/how-to-cache-exchange-rates-avoid-rate-limits/)
- [Historical exchange rate APIs compared](https://allratestoday.com/blog/best-free-historical-exchange-rate-api-2026/)
- [How often are exchange rates updated](https://allratestoday.com/blog/how-often-are-exchange-rates-updated/)
- [How to get live exchange rates in Python](https://allratestoday.com/blog/how-to-get-live-exchange-rates-python/)
