How to get live gold prices in Python
Call the goldprice.dev API from Python with requests, Decimal arithmetic, retry-on-429, and a 60-second TTL cache.
Updated
To get live gold prices in Python, send a GET to api.goldprice.dev/v1/spot/XAU-USD-SPOT with your API key in the X-API-Key header using requests. Wrap the call in cachetools.TTLCache for a 60-second cache and use Decimal for price math. The free tier covers 1,000 calls/month, no credit card. Tested April 2026 against Python 3.12 + requests 2.32.
1.Get your goldprice.dev API key
Sign up for a free account at goldprice.dev/onboarding. After email confirmation, your dashboard shows a key starting with
ga_live_. Set it as an environment variable:export GOLDPRICE_API_KEY=ga_live_replace_with_your_key_hereThe free tier includes 1,000 calls/month and 31 supported currencies. No credit card required.
Get your free API key1,000 calls/mo, no credit cardSign up free →2.Install dependencies
You need three packages:
requestsfor the HTTP call,cachetoolsfor the in-process TTL cache, andtenacityfor retry-on-429. Install with pip or uv:BASH · shell# pip pip install requests cachetools tenacity # or uv (recommended) uv add requests cachetools tenacity3.Write the goldprice client
Save this as
goldprice.py. Thespot()function caches per symbol for 60 seconds, retries up to 3 times on 429 with exponential backoff, and returns prices asDecimalso downstream math does not drift from float imprecision.PYTHON · goldprice.py# python: goldprice.py # curl-equivalent: https://api.goldprice.dev/v1/spot/XAU-USD-SPOT import os from decimal import Decimal from typing import TypedDict import requests from cachetools import TTLCache, cached from tenacity import ( retry, retry_if_exception_type, stop_after_attempt, wait_exponential, ) API_BASE = "https://api.goldprice.dev" API_KEY = os.environ["GOLDPRICE_API_KEY"] TIMEOUT = 5 # seconds class SpotResponse(TypedDict): symbol: str quote_currency: str price: Decimal bid: Decimal ask: Decimal is_stale: bool computed_at: str class RateLimited(Exception): """Raised on HTTP 429 so tenacity retries with backoff.""" @cached(cache=TTLCache(maxsize=128, ttl=60)) @retry( retry=retry_if_exception_type(RateLimited), wait=wait_exponential(multiplier=1, min=2, max=30), stop=stop_after_attempt(3), reraise=True, ) def spot(symbol: str = "XAU-USD-SPOT") -> SpotResponse: """Fetch live spot price. Cached 60s per symbol, retries 3x on 429.""" resp = requests.get( f"{API_BASE}/v1/spot/{symbol}", headers={"X-API-Key": API_KEY}, timeout=TIMEOUT, ) if resp.status_code == 429: raise RateLimited(resp.text) resp.raise_for_status() data = resp.json() return { "symbol": data["symbol"], "quote_currency": data["quote_currency"], "price": Decimal(data["price"]), "bid": Decimal(data["bid"]), "ask": Decimal(data["ask"]), "is_stale": data["is_stale"], "computed_at": data["computed_at"], } if __name__ == "__main__": r = spot("XAU-USD-SPOT") print(f"{r['symbol']}-{r['quote_currency']}: {r['price']} (computed {r['computed_at']})")4.Run it
From the same shell where you exported
GOLDPRICE_API_KEY, run the file. The first call hits the API; calls within 60 seconds return the cached value instantly. Repeated runs from a fresh process miss the cache (in-process only); persist to Redis if you need cross-process caching.BASH · shellpython goldprice.py # XAU-USD: 4726.01 (computed 2026-04-27T04:49:01.706844+00:00)5.Switch currency or metal
Symbols are
METAL-CURRENCY-SPOT. Pass any symbol from the 31 supported currencies tospot(). Each unique symbol caches independently inTTLCache, so a multi-currency dashboard polling 5 symbols at 60s intervals fires 5 API calls/minute uncached and 0 cached.PYTHON · goldprice.py · multi-currency# USD spot — default spot("XAU-USD-SPOT") # INR — Indian gold market (largest retail gold-search globally) spot("XAU-INR-SPOT") # EUR — European pricing surfaces spot("XAU-EUR-SPOT") # Silver in USD spot("XAG-USD-SPOT")
Expected output
The API returns this shape:
{
"symbol": "XAU",
"quote_currency": "USD",
"unit": "troy_ounce",
"contract_type": "spot",
"price": "4726.01",
"bid": "4726.68",
"ask": "4725.33",
"is_stale": false,
"computed_at": "2026-04-27T04:49:01.706844+00:00"
}Stdout shows one line: symbol, quote_currency, price as Decimal, and the ISO 8601 computed_at timestamp. The TypedDict response is what your downstream code consumes.
Common errors
| Code | Symptom | Fix |
|---|---|---|
| 401 | requests.exceptions.HTTPError: 401 Client Error | API key missing or invalid. Confirm GOLDPRICE_API_KEY is set: echo $GOLDPRICE_API_KEY. If empty, re-export from your dashboard. The client raises on missing env at import time, not at call time, so the failure surfaces on the first import goldprice. |
| 429 | Three RateLimited retries fail with backoff, then raises out | You exhausted the per-minute cap. The 60-second cache prevents this for steady polling; if a burst of distinct symbols hits at once, raise TTLCache.maxsize or stagger calls. For sustained high-volume use, see /pricing for Physical and Pro tiers. |
| N/A | Float drift accumulates when summing many prices | Always pass Decimal through arithmetic — never float. The client returns prices as Decimal; if you cast to float for JSON serialization, use str(price) instead so precision is preserved across the wire. |
FAQ
How often does the price update?
The spot endpoint refreshes every 60 seconds (live oracle + continuous spot reference + futures settlement aggregation). The TTLCache above matches that cadence — repeated spot() calls within 60s return the cached Decimal without an HTTP round-trip.
Will this fit the free tier with auto-refresh?
Depends on your call site. A trading bot polling once per minute = 1,440 calls/day = ~43,000/month — well over the 1,000/month free tier. Use the cache aggressively and call only on demand. Steady polling at 1 call/hour = 720/month, inside the free tier. For continuous high-volume use, see /pricing for Physical and Pro tiers.
Can I use this commercially?
The Free tier is for personal use. For commercial use (apps you ship, services you sell, internal production systems), upgrade to Physical ($10/mo) or Pro ($30/mo) — monthly billing, cancel anytime, no annual lock-in. See /pricing.
Why Decimal instead of float?
Float arithmetic drifts on summation: 0.1 + 0.2 == 0.30000000000000004. Gold prices are reported with 6+ decimal places (e.g. 4726.0100); summing thousands of trades in float introduces basis-point errors over time. Decimal preserves exact arithmetic. The API returns prices as strings precisely so clients can choose Decimal.
What metals are supported?
Gold (XAU), silver (XAG), copper (HG) — platinum and palladium are not offered on any tier. Substitute the metal code in the symbol, e.g. spot("XAG-USD-SPOT").
Is the free tier really free?
Yes — 1,000 calls/month, no credit card, no expiration. Get the key at /onboarding.
Can I have Claude write this for me?
Yes. Open Claude Desktop with the goldprice.dev MCP server installed and ask: Build a Python client for the goldprice.dev /v1/spot endpoint. Use requests, Decimal, a 60-second cachetools TTLCache, and tenacity retry-on-429 with exponential backoff. Read the API key from GOLDPRICE_API_KEY. The MCP server gives Claude the live schema, so generated code uses correct field names on first try.
Going further
- Persist the cache across processes — replace
TTLCachewith a Redis-backed cache so multiple workers share one in-memory price - Add a
bars()wrapper for/v1/bars?symbol=XAU-USD-SPOT&interval=1d&from=...&to=...with pandas DataFrame conversion for backtesting - Switch
requestsforhttpx.AsyncClientif your service is async — the response shape is identical - Wire the client into a FastAPI endpoint and serve internally for non-Python services
- Expose Prometheus metrics for cache hit rate, p50/p95 latency, and 429-retry counts
Next steps
Try the same setup in a different platform: