Blog/Developer

Gold price API on Stack Overflow: developer troubleshooting, answered

The gold-price-API errors developers hit on Stack Overflow, fixed: 401 auth, 400 invalid_symbol, 429 rate limits, CORS from the browser, reading the response, and pulling historical data.

Developer.md

When an integration breaks, developers paste the error into Stack Overflow. The questions that come up for a gold price API are almost always the same handful: an auth rejection, a malformed symbol, a rate-limit wall, or a CORS error from the browser. This post fixes each one directly, using goldprice.dev as the worked example. Every snippet below is a real, working call against https://api.goldprice.dev.

"401 Unauthorized" — my API key is rejected

The key goes in the Authorization header as a bearer token, and the word Bearer (with a trailing space) has to be there:

curl https://api.goldprice.dev/v1/prices?symbol=XAU-USD-SPOT \
  -H "Authorization: Bearer ga_live_YOUR_KEY"

The three things that actually cause a 401: the Bearer prefix is missing, the key has a stray newline or quote from a copy-paste, or the key is being read from an env var that is not loaded. Keys are prefixed ga_live_. You do not strictly need a key to start — anonymous calls work but are capped at 100 requests per hour per IP and return a trimmed response shape, so for anything past a quick test, authenticate.

"400 invalid_symbol" — the most common first error

The symbol parameter is not a bare metal code. It is BASE-QUOTE-CONTRACT. Passing symbol=XAU returns 400 invalid_symbol; the value you want for live gold spot is XAU-USD-SPOT:

# wrong — 400 invalid_symbol
curl "https://api.goldprice.dev/v1/prices?symbol=XAU"

# right
curl "https://api.goldprice.dev/v1/prices?symbol=XAU-USD-SPOT"

Silver spot is XAG-USD-SPOT and copper is HG-USD-SPOT. Futures use the FUTURES contract, for example XAU-USD-FUTURES — note that gold futures need the Basic tier, and silver and copper need Pro, so on the free tier those symbols return 403 plan_gated. Omitting symbol entirely returns the default allowed rows for your tier, which is also a valid way to avoid the error.

"429 Too Many Requests" — handling rate limits

Every response carries an X-RateLimit-Remaining header. Read it and back off before you hit zero rather than polling blind and catching 429s. The free tier is 30 requests per minute; Basic is 120; Pro and Realtime are 500. For most apps a short client-side cache, sized to how often the price actually moves, keeps you well clear of the limit — the spot price does not change meaningfully every second, so caching for a few seconds is usually correct.

"CORS error" — calling the API from the browser

Do not call the API directly from front-end JavaScript with your key. Two reasons: it exposes ga_live_... to anyone who opens devtools, and browser CORS will block it. Proxy the call through your own backend, keep the key server-side, and have the browser hit your endpoint:

// your backend route — the key never reaches the browser
const r = await fetch(
  "https://api.goldprice.dev/v1/prices?symbol=XAU-USD-SPOT",
  { headers: { Authorization: `Bearer ${process.env.GOLDPRICE_API_KEY}` } },
);
const data = await r.json();

"Which field is the price?" — reading the response

The anonymous response gives you price, bid, ask, computed_at, is_stale, a sources[] array, and a per-gram karat breakdown. Authenticate and the shape adds open_price, high_price, low_price, prev_close_price, the change fields, and divergence_bps / divergence_flag. Two fields matter for correctness:

  • is_staletrue when the value is older than its expected refresh window. Check it before you display a price.
  • sources[] — one row per upstream, each with its own price and timestamp. When sources disagree, divergence_bps tells you by how much, so you can set your own tolerance instead of trusting a single blended number.

"How do I get historical / OHLC data?"

Daily close history is GET /v1/prices/history, available on every tier — what changes is how far back you can go. The free tier returns the last 30 days, Basic the last year, and Pro the full history. So if a historical query comes back shorter than you expected, that is the window for your tier, not an auth error.

The shortest call that works

No key, correct symbol:

curl "https://api.goldprice.dev/v1/prices?symbol=XAU-USD-SPOT"

That returns a live, honest gold price with its sources and a staleness flag. When you want the full response shape and higher limits, a free key takes a minute. If you prefer a language-specific walkthrough, Fetch live gold prices in JavaScript covers the REST path end to end, and Caching gold prices and staying inside rate limits covers doing it at volume.

// related guides

// goldprice.dev

Live gold prices, historical OHLC, and multi-source aggregation — available via REST and SSE.