The Easiest Way to Get Stellar (XLM) - N/A Historical Rates using a REST API for time series

Metals-API 9 min read
The Easiest Way to Get Stellar (XLM) - N/A Historical Rates using a REST API for time series

Your team needs a clean daily history of Stellar (XLM) priced in USD for backtesting, charting, or reconciliation. In this guide you’ll fetch single-day snapshots and multi-day time series for XLM over a date range using a simple REST workflow, then write that series to CSV so it’s ready for your analytics stack.

What you will build: a daily history table for XLM in USD

By the end, you will have:

Illustration: The Easiest Way to Get Stellar (XLM) - N/A Historical Rates using a REST API for time series
  • A one-day historical lookup for XLM to validate a closing rate on any past date.
  • A time series pull that returns a day-by-day record of XLM priced against USD for a chosen range.
  • A small Python script that saves a proper CSV with date, XLM_per_USD, and USD_per_XLM columns.

If you need the exact symbol code, confirm it on the Metals-API Supported Symbols page. You can also explore the full set of parameters and options in the Metals-API Documentation. If you don’t have an API key yet, grab one here: Register.

Endpoints you’ll use

We’ll focus on two endpoints that cover most historical use cases:

  • Historical Rates (single day): request a specific YYYY-MM-DD to get that day’s snapshot.
  • Time-series (date range): request a start_date and end_date for daily values across the window.

These two will let you verify specific dates and also backfill larger datasets. For everything else (e.g., intraday, OHLC, bid/ask), see the Documentation.

Single-day historical lookup for XLM (Historical Rates)

Use this when you need the closing rate for a specific date—for example, to reconcile a trade blotter or validate a NAV mark. Replace YOUR_API_KEY with your actual key.

curl "https://metals-api.com/api/2026-10-19?access_key=YOUR_API_KEY&base=USD&symbols=XLM"

Official sample response you’ll parse

The JSON below is an official example for 2026-10-19. It shows how the values appear in a single-day response:

{"success":true,"timestamp":1792368480,"date":"2026-10-19","base":"USD","rates":{"XLM":5.6210722757473,"USD":1,"USDXLM":0.17790200000000067}}

Key fields to use:

  • date: the requested historical date (YYYY-MM-DD).
  • base: the asset all rates are quoted against. Here it’s USD.
  • rates.XLM: units of XLM per 1 USD on that date (XLM_per_USD).
  • rates.USDXLM: units of USD per 1 XLM on that date (USD_per_XLM). This is the inverse of XLM_per_USD.
  • timestamp: Unix time (seconds) you can use for ordering or auditing; interpret in UTC.

Multi-day pulls for XLM (Time-series)

Use the time-series endpoint to backfill a chart or build a training set for a model. Provide start_date and end_date. Dates are inclusive.

curl "https://metals-api.com/api/timeseries?access_key=YOUR_API_KEY&base=USD&symbols=XLM&start_date=2026-10-01&end_date=2026-10-19"

What to expect in the time-series response:

  • A top-level timeseries flag (true).
  • start_date and end_date passed through for verification.
  • rates as a dictionary keyed by date; each date contains a sub-dictionary of symbol-to-value pairs. For this use case, you’ll read rates[YYYY-MM-DD].XLM as XLM per USD for that day.

You can inspect additional attributes like unit or meta fields when present. If you need more options or symbols, review the parameters under Time-series in the Documentation.

Python example: write a daily XLM series to CSV

The snippet below queries a date range and writes a minimal CSV with date, XLM_per_USD, and USD_per_XLM. It assumes the time-series response nests dates under rates, with XLM as the symbol key for each day.

import csv
import os
import sys
import time
import urllib.parse
import urllib.request
import json

API_KEY = os.getenv("METALS_API_KEY", "YOUR_API_KEY")
BASE = "USD"
SYMBOL = "XLM"
START_DATE = "2026-10-01"
END_DATE = "2026-10-19"
OUTFILE = "xlm_usd_daily.csv"

def fetch_json(url):
with urllib.request.urlopen(url) as r:
return json.loads(r.read().decode("utf-8"))

def timeseries_url(api_key, base, symbol, start_date, end_date):
params = {
"access_key": api_key,
"base": base,
"symbols": symbol,
"start_date": start_date,
"end_date": end_date
}
return "https://metals-api.com/api/timeseries?" + urllib.parse.urlencode(params)

def main():
url = timeseries_url(API_KEY, BASE, SYMBOL, START_DATE, END_DATE)
data = fetch_json(url)

if not data.get("success"):
print("API request failed:", data)
sys.exit(1)

# The response is expected to have daily entries under data["rates"][YYYY-MM-DD][SYMBOL]
rates_by_date = data.get("rates", {})
if not rates_by_date:
print("No rates in response.")
sys.exit(1)

# Write CSV with both XLM_per_USD and USD_per_XLM (inverse)
with open(OUTFILE, "w", newline="") as f:
w = csv.writer(f)
w.writerow(["date", "XLM_per_USD", "USD_per_XLM"])
for day in sorted(rates_by_date.keys()):
day_map = rates_by_date.get(day, {})
xlm_per_usd = day_map.get(SYMBOL)
if xlm_per_usd is None:
# Some dates may be missing if outside range or for maintenance windows
continue
usd_per_xlm = 1.0 / xlm_per_usd if xlm_per_usd not in (0, None) else None
w.writerow([day, f"{xlm_per_usd:.12f}", f"{usd_per_xlm:.12f}" if usd_per_xlm else ""])
print(f"Wrote {OUTFILE}")

if __name__ == "__main__":
main()

Notes:

  • The code computes USD_per_XLM as the inverse of XLM_per_USD. If your response already includes USDXLM on single-day calls, you can trust either value (they should be inverses within rounding).
  • Sort the dates so your CSV is chronological. All dates are interpreted in UTC.
  • Use an environment variable for your API key in production. Replace YOUR_API_KEY to test locally.

How to read and validate the JSON structure

For single-day Historical Rates, you’ll parse:

  • success: boolean; check this before using data.
  • date: the requested day (YYYY-MM-DD).
  • base: "USD". Interpret all values relative to this base.
  • rates.XLM: XLM per 1 USD (float).
  • rates.USDXLM: USD per 1 XLM (float), the inverse of rates.XLM.
  • timestamp: seconds since epoch (UTC). Useful for reproducibility and caching.

For Time-series, expect:

  • timeseries: true.
  • start_date and end_date: mirror your request.
  • rates: a map keyed by date; each value contains symbol-value pairs (e.g., {"XLM": 5.62...}).

Practical details that save time

  • Base currency and direction: In our examples, base=USD, and the value at rates.XLM means “how many XLM per 1 USD.” If you need the inverse (USD per XLM), use rates.USDXLM when present on single-day responses, or compute 1/value in your own code for time series.
  • Units: Crypto isn’t quoted in troy ounces like precious metals. Treat the XLM rate as a pure exchange rate relative to USD (base), not a weight-based unit.
  • Date format and timezone: Dates use YYYY-MM-DD, and timestamps are in UTC seconds. Align your ETL and chart axes accordingly.
  • Range limits: Historical ranges and depth depend on plan and the endpoint. Check exact availability and any constraints in the Documentation.
  • Weekend/holiday behavior: Crypto trades around the clock. Still, daily aggregates are produced once per calendar day; don’t assume multiple daily points unless you use intraday endpoints.
  • Caching: Cache successful responses by date and symbol. Time-series results are deterministic for past dates; re-use them to reduce API calls and speed up your pipelines.
  • Error handling: Always check success and presence of expected keys. If a particular date is missing (maintenance or range gap), skip or backfill using adjacent days rather than failing the whole job.
  • Symbols: Validate XLM in the official list before deploying. See Metals-API Supported Symbols.

When to use Historical vs Time-series

Use Case Endpoint Typical Request What You Parse
Point-in-time verification (one date) Historical Rates /api/YYYY-MM-DD?access_key=...&base=USD&symbols=XLM rates.XLM (XLM_per_USD), rates.USDXLM (USD_per_XLM), date, timestamp
Backfilling a chart or model window Time-series /api/timeseries?access_key=...&base=USD&symbols=XLM&start_date=...&end_date=... rates[YYYY-MM-DD].XLM per day, timeseries flag, start_date, end_date

Quality checks for analytics and trading pipelines

  • Monotonic dates: Ensure dates are sorted and unique before computing returns or resampling.
  • Inversion consistency: Verify that 1 / (XLM_per_USD) ≈ USD_per_XLM to catch parsing mistakes.
  • Missing data handling: Forward-fill or drop, based on your model and backtesting rules. Log the missing days for audit.
  • Reproducibility: Persist the raw JSON response alongside your processed CSV for future audits.

Beyond historical: where to look next

Once your XLM history is flowing, you can explore other endpoints like OHLC, fluctuation, or intraday to deepen your analysis. Keep the scope tight for production, but feel free to prototype with the additional endpoints documented here: Metals-API Documentation. For complementary research context, see Stellar network overview and market reference data for XLM to compare how your rates align with broader market sources.

Operational tips for production

  • Scheduling: Pull time series once per day (after the UTC close) to avoid partial updates. For intraday needs, schedule at fixed intervals and tag each batch run with its fetch timestamp.
  • Idempotency: Write ETL stages so a rerun on the same dates produces identical CSVs unless new data arrived. Store a hash of the raw JSON to detect changes.
  • Observability: Emit metrics (rows written, missing dates, parse errors) and alerts. Keep dashboards for “last data date” so you quickly spot lags.
  • Scaling: If your app requests many symbols, fetch in batches and cache per symbol-date. Most past dates won’t change, so skip redundant API calls.

Security and keys

  • Keep your API key in a secrets manager or encrypted environment variable, not in source control.
  • Throttle and backoff: On network hiccups or transient API errors, retry with exponential backoff and jitter. Log the final failure with the request URL redacted of secrets.

FAQ

Q: Which side of the XLM/USD pair am I getting?
A: With base=USD, rates.XLM is “XLM per 1 USD.” If you need the inverse (USD per XLM), use rates.USDXLM on single-day responses when present, or compute 1 / rates.XLM in your code (as shown in the Python example).

Q: How far back can I query XLM?
A: Historical availability depends on the endpoint and your plan. Review the historical coverage and any date constraints in the Documentation.

Q: Are weekends included?
A: Crypto trades 24/7, so you should see daily entries for weekends as well. If a date is missing in a time series, handle it as a gap (skip or fill) rather than assuming market closure.

Q: Can I change the base currency?
A: Yes, set base to the currency you want to price XLM against if supported. In this article we used base=USD for clarity. See the parameter details in the Documentation.

Q: What if my time-series JSON has more keys than I expect?
A: Treat unknown keys as optional metadata. Only rely on date, base, and the symbol values you requested. Log unexpected fields for observability but don’t fail the pipeline.

Get your API key and start pulling XLM history in minutes. Create a free account here: Register. Then explore more endpoints, examples, and options in the Documentation. For broader ecosystem and tooling, check out the MCP page and verify any symbol specifics on the Symbols list.