# Gold price API on Stack Overflow: developer troubleshooting, answered

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:

```bash
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`:

```bash
# 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:

```javascript
// 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_stale` — `true` 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:

```bash
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](/docs/quickstart) takes a minute. If you prefer a language-specific walkthrough, [Fetch live gold prices in JavaScript](/blog/fetch-gold-prices-javascript) covers the REST path end to end, and [Caching gold prices and staying inside rate limits](/blog/gold-price-caching-rate-limits) covers doing it at volume.
