TutorialsCode

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.

27 Apr 2026 · 3 min read

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 5,000 calls/month, no credit card. Tested October 2026 against Python 3.15 + requests 2.34.

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:

Shell
export GOLDPRICE_API_KEY=ga_live_replace_with_your_key_here

The free tier includes 5,000 calls/month and gold spot in 31 currencies. No credit card required.

Install dependencies

You need three packages: requests for the HTTP call, cachetools for the in-process TTL cache, and tenacity for retry-on-429. Install with pip or uv:

shell
# pippip install requests cachetools tenacity# or uv (recommended)uv add requests cachetools tenacity

Write the goldprice client

Save this as goldprice.py. The spot() function caches per symbol for 60 seconds, retries up to 3 times on 429 with exponential backoff, and returns prices as Decimal so downstream math does not drift from float imprecision.

goldprice.py
# python: goldprice.py# curl-equivalent: https://api.goldprice.dev/v1/spot/XAU-USD-SPOTimport osfrom decimal import Decimalfrom typing import TypedDictimport requestsfrom cachetools import TTLCache, cachedfrom 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  # secondsclass SpotResponse(TypedDict):    symbol: str    quote_currency: str    price: Decimal    bid: Decimal | None  # only on plans that include bid and ask    ask: Decimal | None    is_stale: bool    computed_at: strclass 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"]) if data.get("bid") else None,        "ask": Decimal(data["ask"]) if data.get("ask") else None,        "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']})")

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.

shell
python goldprice.py# XAU-USD: 4012.75 (computed 2026-10-23T07:00:18.221118+00:00)

Switch currency or metal

Symbols are METAL-CURRENCY-SPOT. Pass any symbol from the 31 spot currencies to spot(). Each unique symbol caches independently in TTLCache, so a multi-currency dashboard polling 5 symbols at 60s intervals fires 5 API calls/minute uncached and 0 cached.

goldprice.py · multi-currency
# USD spot, defaultspot("XAU-USD-SPOT")spot("XAU-INR-SPOT")spot("XAU-EUR-SPOT")# Silver in USDspot("XAG-USD-SPOT")

Expected output

JSON
{  "symbol": "XAU",  "quote_currency": "USD",  "unit": "troy_ounce",  "contract_type": "spot",  "price": "4012.75",  "is_stale": false,  "computed_at": "2026-10-23T07:00:18.221118+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

CodeWhat you seeFix
401requests.exceptions.HTTPError: 401 Client ErrorAPI 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.
429Three RateLimited retries fail with backoff, then raises outYou 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 paid plans.
N/AFloat drift accumulates when summing many pricesAlways 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.

Going further

  • Persist the cache across processes, replace TTLCache with 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 requests for httpx.AsyncClient if 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

Questions

How often does the price update?

The spot endpoint refreshes every 60 seconds (licensed live spot data; Free/keyless delayed 15 minutes, paid live). 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 5,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 paid plans.

Can I use this commercially?

Commercial use is allowed on every plan. Paid plans need no credit link; Free requires a visible link to goldprice.dev near the prices.

Why Decimal instead of float?

Decimal preserves exact arithmetic. Float arithmetic drifts on summation: 0.1 + 0.2 == 0.30000000000000004. Summing thousands of trades in float introduces basis-point errors over time. The API returns prices as strings with 2 decimals, such as "4012.75", so clients can choose Decimal for their calculations.

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, 5,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.

Keep reading

Start with a free API key

5,000 requests a month on the free plan. No credit card.

Get a free key