The Easiest Way to Get Canadian Dollar (CAD) - N/A Historical Rates via REST API
You need a clean, reliable way to pull historical Canadian Dollar (CAD) rates into your app, spreadsheet, or pricing engine. In this guide you’ll build a daily history table for CAD using two Metals-API REST endpoints—single-day historical and multi-day time-series—then export it to CSV so your downstream tools can use it immediately.
What you’ll build: a daily CAD history you can ship
By the end, you will:
- Fetch CAD rates for a single historical date (for backfills or point-in-time valuation).
- Fetch a multi-day CAD time series (for charts, signals, and analytics).
- Parse the JSON structure Metals-API returns for dates and rates.
- Write the CAD series to a CSV file in Python with timestamps you can join to other datasets.
If you also price commodities or metals in CAD (e.g., converting gold quotes to CAD, or valuing inputs for manufacturing), the exact same pattern applies—Metals-API returns currency and metals data in an aligned schema so you can combine them later.
Endpoints you’ll use
We’ll focus on two endpoints that cover the essential historical workflows. For deeper capabilities (e.g., intraday, OHLC, fluctuations), see the reference in the Metals-API Documentation.
- Historical Rates Endpoint: query a single date by appending a date (YYYY-MM-DD) to the API path.
- Time-Series Endpoint: query daily historical rates between a start_date and end_date you choose.
Before you begin, you’ll need a free API key. You can create one in minutes at the Metals-API Website. If you’re unsure whether the CAD symbol is supported on your plan, check the always-updated Metals-API Supported Symbols.
Single-day historical CAD rate
Use this when you need the CAD rate on a specific date—common in backfills, EOD reconciliation, or point-in-time reporting. The API responds with a date, a Unix timestamp, a base currency, and a rates map keyed by symbols, including CAD.
curl example: single date
Replace YOUR_API_KEY with your actual key:
curl "https://metals-api.com/api/2026-09-27?access_key=YOUR_API_KEY&base=USD&symbols=CAD"
Sample JSON response
Values below are illustrative and fields mirror the live API:
{
"success": true,
"timestamp": 1790467837,
"base": "USD",
"date": "2026-09-27",
"rates": {
"CAD": 1.3502
}
}
What you’ll use in your app:
- date: The effective date for the rates (YYYY-MM-DD).
- timestamp: Unix epoch seconds (UTC) when this snapshot was generated.
- base: The base currency for the conversion. If base is USD, then rates.CAD means 1 USD equals rates.CAD Canadian dollars.
- rates.CAD: The numeric exchange rate for CAD relative to the base.
Tip: If you need the inverse (e.g., USD per CAD), compute 1 / rates.CAD in your application logic.
Multi-day CAD time series
Use the time-series endpoint when you need a date-indexed history between two dates to power charts, regressions, or PnL attribution. The response nests rates under each calendar date.
curl example: time series
curl "https://metals-api.com/api/timeseries?access_key=YOUR_API_KEY&base=USD&symbols=CAD&start_date=2026-09-21&end_date=2026-09-28"
Sample JSON response
Values are illustrative to demonstrate structure:
{
"success": true,
"timeseries": true,
"start_date": "2026-09-21",
"end_date": "2026-09-28",
"base": "USD",
"rates": {
"2026-09-21": { "CAD": 1.3541 },
"2026-09-23": { "CAD": 1.3517 },
"2026-09-28": { "CAD": 1.3495 }
}
}
What matters for your pipeline:
- timeseries: A boolean that confirms you’re looking at a date-range response.
- rates: A map keyed by date string, each containing the CAD rate for that day.
- Missing dates: Non-trading days (e.g., weekends) may be absent or repeat the most recent available snapshot depending on data availability. Always iterate over keys present in the rates map instead of assuming every calendar date will appear.
Python: write CAD time series to CSV
The snippet below calls the time-series endpoint, normalizes the response into rows, and writes a CSV with ISO date and CAD rate. This is a minimal, dependency-free approach—drop-in for a cron, Lambda, or notebook cell.
import csv
import os
import sys
import urllib.request
import json
API_KEY = os.getenv("METALS_API_KEY", "YOUR_API_KEY")
BASE = "USD"
SYMBOL = "CAD"
START_DATE = "2026-09-21"
END_DATE = "2026-09-28"
URL = (
"https://metals-api.com/api/timeseries"
f"?access_key={API_KEY}"
f"&base={BASE}"
f"&symbols={SYMBOL}"
f"&start_date={START_DATE}"
f"&end_date={END_DATE}"
)
def fetch_json(url):
with urllib.request.urlopen(url) as resp:
return json.loads(resp.read().decode("utf-8"))
def to_rows(payload):
if not payload.get("success"):
raise RuntimeError(f"API error: {payload}")
base = payload.get("base")
rates = payload.get("rates", {})
rows = []
for dt, symbols in sorted(rates.items()):
cad = symbols.get("CAD")
if cad is None:
# skip dates without CAD
continue
rows.append({"date": dt, "base": base, "CAD": cad})
return rows
def write_csv(path, rows):
if not rows:
print("No data to write.", file=sys.stderr)
return
fieldnames = ["date", "base", "CAD"]
with open(path, "w", newline="") as f:
writer = csv.DictWriter(f, fieldnames=fieldnames)
writer.writeheader()
writer.writerows(rows)
if __name__ == "__main__":
data = fetch_json(URL)
rows = to_rows(data)
write_csv("cad_timeseries.csv", rows)
print(f"Wrote {len(rows)} rows to cad_timeseries.csv")
Notes:
- The script sorts dates to ensure ascending order in the CSV.
- If you prefer the inverse rate (USD per CAD), modify cad = 1 / symbols.get("CAD").
- Use environment variables for the API key in production. The example reads METALS_API_KEY if set.
Understand base currency, units, and timestamps
Base currency: Metals-API returns rates relative to a base (the samples show "base": "USD"). If base=USD and rates.CAD=1.35, that means 1 USD equals 1.35 CAD. If you need CAD as the base currency, set base=CAD and read other rates relative to CAD, or compute inverses in your code.
Units: Currency pairs are unitless ratios (amount of quote currency per base currency unit). Metals quotes (like gold) include a "unit" field such as "per troy ounce." If you later merge CAD with metals like XAU, remember that 1 troy ounce equals approximately 31.1034768 grams. Keep unit conversions explicit in your data model.
Timestamps and timezone: The timestamp field is Unix epoch seconds and corresponds to UTC. For daily workflows, rely on the "date" key for grouping and join logic, and keep the timestamp for audit/logging.
Handling weekends, closures, and sparse calendars
FX and metals markets have different trading calendars and liquidity patterns. When requesting a time range:
- Do not assume every calendar date appears. Iterate over the "rates" keys returned.
- If you need a dense daily index, reindex after fetch: join the returned dates to your desired calendar and forward-fill with your internal rules (only where appropriate).
- Cache EOD responses. Historical points for past dates rarely change; store them to reduce calls and improve page load times.
Performance and reliability tips
- Batch with time-series over daily-by-daily loops to reduce request count and latency.
- Cache yesterday’s EOD payloads for read-mostly dashboards. Invalidate cache only when needed.
- Treat "base" as a first-class field in your dataset so you can detect and correct mismatches early.
- Validate symbol availability on the Supported Symbols page before shipping to production.
How this applies if you price metals and materials in CAD
Many teams need both currency and commodity context. For example, a manufacturer sourcing inputs in CAD may want to normalize dollar-denominated commodity prices. You can fetch the CAD series as shown, then either:
- Use the Convert endpoint to go from USD to CAD for your metal prices; or
- Fetch metal rates with base=CAD directly to get CAD-denominated quotes.
If you work with specialty inputs like tellurium in high-tech manufacturing, the same pattern holds: keep the currency series (CAD) and the materials series aligned by date and unit, then compute derived costs or hedges. Metals-API’s unified schema makes it straightforward to blend these data streams for analytics and production pricing. Explore more options in the endpoint reference.
Common pitfalls and guardrails
- Parsing nested maps: In the time-series response, you must loop date keys and then read symbols within each day. Don’t expect a flat array.
- Inverse logic: If you switch bases (e.g., base=CAD), your mental model of the rate flips. Document the convention your team uses.
- Floating-point math: For financial reporting, use decimal math in downstream systems where precision matters (e.g., invoicing). Your integration can still fetch JSON as floats.
- Rollover timing: Daily snapshots are timestamped in UTC. If your reporting day closes in Toronto time, align your batch schedule and any “as-of” labels accordingly.
Where to go next
- Read parameter details, date formats, and response shapes in the Metals-API Documentation.
- Confirm symbol availability and naming in the Supported Symbols directory.
- Get your free key and start testing in minutes at the Metals-API Website.
FAQ
Q: What does rates.CAD represent when base=USD?
A: It’s the amount of Canadian dollars per 1 US dollar. To get USD per 1 CAD, take the inverse: 1 / rates.CAD.
Q: How far back can I get historical CAD data?
A: Historical rates are available for most currencies dating back to 2019. Check any plan-specific limits in the documentation.
Q: Will I get entries for weekends?
A: Not necessarily. The time-series endpoint returns data for dates where a rate is available. Always iterate over the date keys returned, and reindex in your application if you need a dense calendar.
Q: Can I set CAD as the base currency?
A: Yes. Pass base=CAD to receive other rates relative to CAD. If you already have USD-based data, compute inverses in your client code.
Q: How should I cache historical responses?
A: Cache immutable historical days (past dates) aggressively. For the current day, refresh based on your plan’s update frequency and your product’s latency tolerance.
Ready to build your CAD history pipeline? Grab a free key at the Metals-API Website, verify symbols and date ranges in the docs, and ship your first CSV in under 10 minutes.