fetcher is the binary that drives the whole system. It fetches live exchange
rates from external APIs, computes cross rates for every supported currency, and
writes a tree of static JSON files ready to be deployed to a CDN.
┌─────────────────────┐
│ data/currencies │ master list of supported currencies
│ data/crypto_ids │ maps code → CoinGecko ID
└────────┬────────────┘
│
┌──────────▼──────────┐
│ sources/fiat.rs │ GET fiat API → EUR-based fiat rates
│ sources/crypto.rs │ GET CoinGecko → EUR-based crypto rates
│ sources/metals.rs │ GET metalpriceapi → EUR-based metal rates (optional)
└──────────┬──────────┘
│ merge
┌──────────▼──────────┐
│ normalize.rs │ computes cross rates for every currency pair
└──────────┬──────────┘
│ write
┌──────────▼──────────┐
│ generate.rs │ writes dist/v1/ file tree
└─────────────────────┘
Every rate in the system is first normalized to EUR as the base. To convert between any two currencies A → B, the formula is:
rate(A → B) = eur_rate[B] / eur_rate[A]
This applies to every supported type — fiat, crypto, and precious metals.
For example, rate(XAU → BRL) = eur_rate[BRL] / eur_rate[XAU].
This lets us derive all ~40,000 currency pairs from a single EUR-based map.
cargo build --releaseThe binary will be at ./target/release/fetcher.
fetcher [OPTIONS]
Options:
--output <DIR> Output directory [default: dist]
--date <YYYY-MM-DD|YYYY-MM-DDTHH:MM> Override snapshot datetime [default: current UTC clock]
--dry-run Fetch data but skip writing files
-h, --help Print help
cargo run --releaseFetches live rates and writes everything to dist/v1/.
cargo run -- --dry-runUseful for verifying your environment variables are correct before deploying.
cargo run --release -- --output /tmp/my-outputcargo run --release -- --date 2026-01-15Stamps each output file with "date": "2026-01-15". No timestamp field is
included — output is identical to the old format. Useful for backfills.
cargo run --release -- --date 2026-03-07T14:30Stamps output with both "date": "2026-03-07" and "timestamp": "2026-03-07T14:30:00Z".
This is the format used by sub-daily.yml in GitHub Actions.
cargo run --releaseUses the current UTC clock. Produces both date and timestamp fields automatically.
RUST_LOG=debug cargo run -- --dry-runAfter a successful run, dist/ will look like this:
dist/
└── v1/
├── currencies.json # full list: { "usd": "US Dollar", ... }
├── currencies.min.json # same, minified
├── countries.json # country data (copied from data/ if present)
└── currencies/
├── eur.json # { "date": "...", "timestamp": "...", "eur": { "usd": 1.08, ... } }
├── eur.min.json
├── usd.json
├── usd.min.json
└── ... # one pair per supported currency
The entire dist/ directory is what gets deployed to Cloudflare Pages.
The CLI reads these at startup. Set them in your shell for local runs or as GitHub secrets for CI (see SETUP.md).
| Variable | Required | Default | Description |
|---|---|---|---|
FIAT_API_URL |
No | https://open.er-api.com/v6/latest/EUR |
EUR-based fiat endpoint. Supports {key} placeholder (e.g. https://v6.exchangerate-api.com/v6/{key}/latest/EUR). Must use EUR as base. |
FIAT_API_KEY |
No | (none) | Substituted into {key} in FIAT_API_URL, or sent as Bearer header if no placeholder is present |
CRYPTO_API_URL |
No | https://api.coingecko.com/api/v3/simple/price |
CoinGecko-compatible price endpoint |
CRYPTO_API_KEY |
No | (none) | x-cg-demo-api-key header value |
METALS_API_URL |
No | https://api.metalpriceapi.com/v1/latest?base=EUR¤cies=XAU,XAG,XPT,XPD |
Precious metals endpoint (metalpriceapi.com-compatible) |
METALS_API_KEY |
No | (none) | X-API-KEY header value. If not set, metals are silently skipped |
Copy .env.example to .env, fill in your keys, then:
source .env && cargo run --release- Open
data/currencies.jsonand add the entry:"xyz": "My New Currency"
- Depending on the type:
- Cryptocurrency — also open
data/crypto_ids.jsonand map its CoinGecko ID:You can find the CoinGecko ID at"xyz": "my-new-currency-coingecko-id"
https://www.coingecko.com— it is the slug in the coin's URL, e.g.coingecko.com/en/coins/bitcoin→bitcoin. - Precious metal — ensure
METALS_API_KEYis set and the metal's ISO code (e.g.XAU) is included in thecurrenciesquery parameter ofMETALS_API_URL. The default URL already includes XAU, XAG, XPT, and XPD. - Fiat currency — no extra config needed; the fiat API returns it automatically.
- Cryptocurrency — also open
- Rebuild and run. The new currency will appear in the output automatically.
Delete its entry from data/currencies.json (and data/crypto_ids.json if
applicable). It will be excluded from the next run.