{Symbol} Price API JSON
You need to price gold-linked products, quotes, or positions in real time, and you want a clean JSON response you can wire into a chart, pricer, or alert. By the end of this guide, you’ll call the Latest endpoint for XAU, interpret the JSON fields correctly (including oz/USD vs USD/oz), handle units and timestamps, and ship code that’s resilient to weekends and caching.
What you’ll build: reliable XAU spot reads in JSON
This walkthrough focuses on the Latest endpoint and the single symbol XAU (Gold) so you can:
- Request the current gold rate in ounces per USD and USD per ounce (USDXAU) in one call.
- Transform and display the price in your app (including grams or kilograms) without unit mistakes.
- Cache and retry sensibly to avoid noisy updates and save requests.
If you need additional endpoints later (historical snapshots, time series, intraday, bid/ask, or OHLC), see the Metals-API Documentation. For a full list of identifiers, including XAU and cross symbols like USDXAU, refer to Metals-API Supported Symbols.
Endpoint and parameters you’ll actually use
We’ll use the Latest Rates endpoint. It returns the most recent rates with base currency set to USD by default. That matters because:
- rates.XAU = troy ounces per 1 USD (oz/USD).
- rates.USDXAU = USD per 1 troy ounce (USD/oz).
Query parameters for this implementation:
- access_key: your API key.
- symbols: request both XAU and USDXAU so you have oz/USD and USD/oz in one response.
Copy-paste curl for XAU latest
curl -s "https://metals-api.com/api/latest?access_key=YOUR_API_KEY&symbols=XAU,USDXAU"
This returns JSON with a base of USD. You’ll commonly store rates.USDXAU (USD/oz) as your “spot price” for charting and quoting, and keep rates.XAU for conversions or sanity checks.
Field-by-field: interpret the official JSON response for XAU
Below is a real response payload. Use these exact fields in your integration:
{"success":true,"timestamp":1791072420,"date":"2026-10-04","base":"USD","rates":{"XAU":0.0002415575631673,"USD":1,"USDXAU":4139.8000000000475}}
What to read and why:
- success: Boolean guard. Check this before parsing rates.
- timestamp: Unix seconds. Treat as UTC. Use it for caching and recency checks.
- date: YYYY-MM-DD, aligned to the data snapshot (UTC). Useful for labeling charts and detecting weekend carry-over.
- base: Currency the rates are quoted against (USD here).
- rates.XAU: Ounces per one USD (oz/USD). This is the inverse of USD/oz.
- rates.USD: Always 1 when base is USD; useful in some conversions.
- rates.USDXAU: USD per ounce (USD/oz). Most front-ends will display this as the “gold price.”
Production-ready Python example for XAU latest
This script fetches both oz/USD (XAU) and USD/oz (USDXAU), normalizes values, and converts to grams and kilograms for product pricing.
import os
import time
import requests
API_KEY = os.getenv("METALS_API_KEY", "YOUR_API_KEY")
URL = "https://metals-api.com/api/latest"
# Unit constants
TROY_OUNCE_TO_GRAMS = 31.1034768
GRAMS_TO_KG = 0.001
def get_xau_latest():
params = {
"access_key": API_KEY,
"symbols": "XAU,USDXAU"
}
r = requests.get(URL, params=params, timeout=10)
r.raise_for_status()
data = r.json()
if not data.get("success"):
# A lightweight error shape; adapt to your logging
raise RuntimeError(f"Metals-API error: {data}")
ts = int(data["timestamp"]) # Unix seconds, UTC
base = data.get("base", "USD")
rates = data["rates"]
xau_oz_per_usd = float(rates["XAU"]) # oz/USD
usd_per_oz = float(rates["USDXAU"]) # USD/oz
# Derived prices
usd_per_gram = usd_per_oz / TROY_OUNCE_TO_GRAMS
usd_per_kg = usd_per_gram / GRAMS_TO_KG
return {
"timestamp": ts,
"date": data.get("date"),
"base": base,
"usd_per_oz": usd_per_oz,
"oz_per_usd": xau_oz_per_usd,
"usd_per_gram": usd_per_gram,
"usd_per_kg": usd_per_kg
}
if __name__ == "__main__":
quote = get_xau_latest()
# Cache for 1–10 minutes depending on your plan/data needs
print(f"XAU {quote['date']} @ {time.strftime('%Y-%m-%d %H:%M:%S', time.gmtime(quote['timestamp']))}Z")
print(f"USD/oz: {quote['usd_per_oz']:.4f}")
print(f"USD/g: {quote['usd_per_gram']:.4f}")
print(f"USD/kg: {quote['usd_per_kg']:.2f}")
Notes:
- For display, round to your product’s precision. For P&L or risk, keep full precision internally.
- Cache responses until the next expected update window (see your plan and timestamp drift). Avoid re-requesting within the same minute if the timestamp hasn’t advanced.
JSON field guide for XAU latest: what to store and how to invert
In Latest responses with base=USD:
- rates.XAU = oz/USD. Multiply USD by this to get ounces; divide ounces by this to get USD.
- rates.USDXAU = USD/oz. Multiply ounces by this to get USD; divide USD by this to get ounces.
Inversion math:
- If you only had rates.XAU, then USD/oz = 1 / rates.XAU.
- If you only had rates.USDXAU, then oz/USD = 1 / rates.USDXAU.
Requesting both symbols in one call avoids accidental inversion errors and floating-point drift.
Units and conversions you’ll need (avoid common mistakes)
- Base unit is the troy ounce. 1 troy ounce = 31.1034768 grams. Do not use the avoirdupois ounce.
- USD/oz (USDXAU) is the value most traders and product managers expect to see as “spot gold.”
- Inventory and retail commonly price in grams or kilograms:
- USD/g = USD/oz ÷ 31.1034768
- USD/kg = USD/g ÷ 0.001
For background on the troy ounce standard, see market references like the LBMA. For futures term structure and hedging context, review CME gold futures specifications on the exchange’s site. Always align your unit conventions across pricing, invoicing, and risk to prevent reconciliation errors.
Make it stable: timestamps, caching, weekends
- Timestamps are Unix seconds, UTC. If your UI expects local time, convert explicitly and label the timezone.
- Update frequency depends on your plan. Use the timestamp to determine if a new tick has arrived before refreshing UI or alerts.
- Weekends/market closures: if you query on a non-trading day, you’ll typically receive the last available rate and its date. In your UI, show the date and consider disabling “live” blips until an updated timestamp appears.
- Cache tier:
- Edge: CDN or reverse proxy cached for 30–60 seconds to flatten bursts.
- App: in-memory cache keyed by symbol set (XAU,USDXAU) with TTL aligned to expected update cadence.
- Retries: short exponential backoff on network errors; do not retry on a valid response with success=false—surface the message to logs and fallback to the last good rate.
When you need more than “latest” for XAU
Many applications start with the Latest endpoint and then add one or two more endpoints:
- Historical or Time-Series: backfill charts or compute day-over-day changes from snapshots. Reference the Metals-API Documentation for exact URL formats and date parameters.
- OHLC or Bid/Ask: build candlestick views or quote screens. If you only display mid-level “spot,” Latest is often sufficient; for trading UIs, OHLC and bid/ask fields are standard.
Keep your symbol list precise. Only request XAU (and USDXAU) when your app is gold-only; expanding symbol sets increases payload size and rate consumption without benefit.
Rounding, precision, and valuation rules
- Internal precision: store USD/oz and oz/USD at double precision. Avoid early rounding of portfolio valuations.
- Display precision: common choices are:
- USD/oz: 2–3 decimals for consumer UI; 2–4+ for trader UI depending on downstream rounding.
- USD/g: 3–4 decimals.
- Rounding mode: specify bank or half-away-from-zero consistently across systems to eliminate penny mismatches.
Example: build a lightweight gold pricer
Inputs
- Weight: grams (from SKU or user input)
- Purity: decimal (e.g., 0.9999 for 24k, 0.9167 for 22k)
- Spread/fee: percentage or absolute USD
Computation
- net_grams = grams × purity
- usd_per_gram = USD/oz ÷ 31.1034768
- base_price = net_grams × usd_per_gram
- quote_price = base_price × (1 + spread_pct) + spread_abs
Pull USD/oz from rates.USDXAU once per cache interval, not per keystroke, to keep the UI responsive and your usage lean.
Versioning, monitoring, and guardrails
- Schema stability: track the fields you consume (success, timestamp, base, rates.XAU, rates.USDXAU). Ignore extra keys you don’t need to reduce tight coupling.
- Health checks: alert if timestamp stalls beyond your expected update cadence, or if USDXAU deviates abnormally from a rolling median.
- Fallbacks: display the last good snapshot with a “stale” badge if new data is unavailable.
Security and key management
- Do not embed your key directly in client-side code. Proxy requests through your backend or serverless function.
- Scope environment-specific keys and rotate periodically.
- Rate-limit client calls to your proxy, not just the upstream API.
Common pitfalls and how to avoid them
- Confusing oz vs g: Always convert with 31.1034768, and centralize that constant in a shared module.
- Forgetting inversion: With base=USD, rates.XAU is oz per USD—not USD per oz. Use USDXAU for direct display.
- Repeated polling without checking timestamps: Compare timestamp before updating the UI; skip if unchanged.
- Weekend “live” indicators: Label with the response date and disable animated ticks until markets reopen.
Scaling your integration
- Batch symbols: If you later add silver, platinum, or palladium pricing to the same screen, request the extra symbols in a single call and cache the combined payload.
- Normalization layer: Keep one module that transforms all rates into your canonical price (e.g., USD/oz) and per-unit derivatives (USD/g, USD/kg). Everything downstream consumes this canonical schema.
- Data lineage: Log the access_key identifier (not the secret), timestamp, and hashes of the response used to compute quotes for auditability.
Where to find symbols and docs
Confirm XAU, USDXAU, and any other identifiers you plan to use on the Metals-API Supported Symbols page. When you extend beyond Latest—for example, to time series or OHLC—consult the parameter and response details in the Metals-API Documentation.
Get access and build
To move this into production, create an account and obtain your API key. Start with your immediate need (XAU Latest) and add endpoints as your product requires.
FAQ
Q: Which field should I show as the “gold price”?
A: Use rates.USDXAU (USD per troy ounce). It’s the display figure most traders and customers expect. Keep rates.XAU (oz per USD) for conversions and checks.
Q: How do I convert USD/oz to USD/gram accurately?
A: Divide USD/oz by 31.1034768. For kilograms, divide USD/gram by 0.001.
Q: Why didn’t the price change even after I polled again?
A: Compare the timestamp. If it’s unchanged, you’ve received the same snapshot. Respect the update cadence; cache until a new timestamp appears, especially during quiet periods or closures.
Q: How do I price non-24k items?
A: Multiply grams by purity (e.g., 0.9167 for 22k) before applying USD/gram. Add your spread or fee after computing the base metal value.
Q: Can I backfill a chart for XAU without changing endpoints?
A: For historical bars or daily closes, use the appropriate historical or time-series endpoints documented in the Documentation. Store snapshots alongside their timestamps for consistent plotting.
If you’re ready to implement, get your key and start with the Latest endpoint for XAU. You can extend to time series, OHLC, or bid/ask when you need them. Create your account here: Register.