Docs / API Reference

Gold Price API Reference

Eighteen live endpoints. Every endpoint returns JSON, accepts a single bearer token, and is idempotent. Base URL: https://api.goldprice.dev/v1

Live prices

GET/v1/pricesBearer · Free+

Returns the latest tick for one symbol, or every symbol the caller's tier allows when symbol is omitted. Default is XAU-USD-SPOT. Lean by default (Phase B, 2026-06-30): every caller — anonymous and authenticated alike — gets a 9-field core row. Pull sources[], the karat-gram fan, or OHLC/divergence stats explicitly via ?include=. Anonymous responses also carry X-Goldprice-Notice + a Link rel="related" header pointing at /onboarding — get a free key to lift the cap.

Query parameters

symbolstring
A single symbol, e.g. XAU-USD-SPOT. Aliases resolve first: gold/GOLD XAU-USD-SPOT, silver/XAG XAG-USD-SPOT, copper/HG HG-USD-FUTURES. Omit to get every symbol the tier allows.
includestring[]
Comma-separated: sources, karat, stats, all. Unknown tokens ignored. stats is auth-gated — anonymous callers never receive it, even via ?include=all (silently downgraded to sources,karat).

Response codes

200 OK400 invalid_symbol403 plan_gated429 rate_limited

Response schema

// 200 OK
{
  "symbols": SpotRow[]
}

// SpotRow — CORE (always present)
{
  "symbol": string,
  "quote_currency": string,
  "unit": string,             // always "troy_ounce"
  "contract_type": string,    // "spot" | "futures"
  "price": string | null,     // decimal-as-string
  "bid": string | null,
  "ask": string | null,
  "is_stale": boolean,
  "computed_at": string | null // ISO-8601 UTC
}

// + ?include=sources
{
  "sources": Source[]         // tier-filtered provenance
}

// + ?include=karat (XAU only; omitted for XAG/HG or null price)
{
  "price_gram_24k": string, "price_gram_22k": string, "price_gram_21k": string,
  "price_gram_20k": string, "price_gram_18k": string, "price_gram_16k": string,
  "price_gram_14k": string, "price_gram_10k": string
}

// + ?include=stats (auth-gated — anon never receives this group)
{
  "divergence_flag": boolean, "divergence_bps": number,
  "value_stale": boolean,     // only when primary source is the council rate
  "open_price": string | null, "high_price": string | null, "low_price": string | null,
  "prev_close_price": string | null, "ch": string | null, "chp": string | null,
  "open_time": number | null  // epoch seconds at UTC midnight
}

// Source
{
  "source": string,
  "display_name": string | null,
  "price": string | null,
  "unit": string | null,
  "license": string | null,
  "is_stale": boolean | null,
  "informational": boolean | null // true for reference-only feeds (e.g. tokenized gold) that never set the primary price
}

Price history deprecated — use /v1/bars

GET/v1/prices/historyBearer · Free+

Daily close history backfilled from multiple archival sources. This endpoint is deprecated in favour of /v1/bars. The API returns Deprecation, Sunset, and Link response headers on every call. Free returns the most recent 30 days; Physical returns the last year (365 days); Pro+ returns the full window back to 1996-01-01.

Query parameters

symbolstringREQUIRED
A single symbol, e.g. XAU-USD-SPOT.
fromdate
YYYY-MM-DD. Defaults to 30 days ago.
todate
YYYY-MM-DD. Defaults to today.
intervalstring
One of 1d (default), 1h.

Response codes

200 OK400 invalid_range403 plan_gated429 rate_limited

Response schema

// 200 OK
// Response headers include:
//   Deprecation: true
//   Sunset: <ISO-8601 date>
//   Link: </v1/bars>; rel="successor-version"
{
  "symbol": string,
  "interval": string,        // "1d" | "1h"
  "from": string,            // ISO-8601 date or timestamp
  "to": string,
  "series": SeriesEntry[],
  "meta": {
    "tier": string,
    "count": number,
    "ohlc_note": string
  }
}

// SeriesEntry
{
  "date": string,            // "YYYY-MM-DD" (daily) or ISO-8601 UTC (intraday)
  "open": string | null,     // decimal-as-string
  "high": string | null,
  "low": string | null,
  "close": string | null,
  "volume": string | null,   // always null (close-only path)
  "is_stale": boolean,
  "is_closed": boolean       // forming vs. settled bar; present since the 2026-06-19 real-bars cutover
}

Forward view

GET/v1/forward-view/{asset}Bearer · Free+ (XAU) · Pro+ (XAG/HG)

Multi-horizon forward forecast for a metal asset. Returns the futures settlement curve (settle prices) per horizon up to one year out. Supported assets: XAU, XAG, HG. XAU is served on every tier; XAG/HG require Pro+ — same per-asset gate as /v1/prices.

Path parameters

assetstringREQUIRED
One of XAU, XAG, HG.

Response codes

200 OK400 invalid_asset403 plan_gated503 spot_unavailable503 no_horizons_available

Response schema

// 200 OK
{
  "asset": string,
  "spot_usd": string,        // decimal-as-string
  "computed_at": string,     // ISO-8601 UTC
  "horizons": Horizon[],
  "sources": Source[],
  "errors": string[]         // partial-failure per horizon
}

// Horizon
{
  "expiry": string,          // "YYYY-MM-DD"
  "futures": FuturesBlock | null,
  "errors": string[]
}

// FuturesBlock
{
  "contract": string,
  "settle_usd": string,
  "settle_source": string,
  "settle_age_seconds": number,
  "open_interest": number | null,
  "volume": number | null
}

Single-symbol spot

GET/v1/spot/{symbol}Bearer · Free+

Convenience alias for /v1/prices — same tier gate and fields, but flat (no symbols[] envelope) since you already know the symbol.

Path parameters

symbolstringREQUIRED
e.g. XAU-USD-SPOT. Aliases resolve the same as /v1/prices.

Query parameters

includestring[]
Same opt-in groups as /v1/prices: sources, karat, stats, all.

Response codes

200 OK400 invalid_symbol403 plan_gated404 not_found429 rate_limited

Response schema

Same lean-by-default SpotRow shape as /v1/prices, unwrapped (no symbols[] array).

Cross-source divergence

GET/v1/prices/divergenceBearer optional · Free+

Symbols whose cross-source price spread exceeds a threshold. Works anonymously (count only) or authenticated (full detail, tier-filtered).

Query parameters

thresholdint
Spread floor in basis points. Default 50, range 1–10000.

Response codes

200 OK422 validation_error

Response schema

// Anonymous
{
  "threshold_bps": number,
  "computed_at": string,
  "diverged_count": number
}

// Authenticated (any tier)
{
  "threshold_bps": number,
  "computed_at": string,
  "diverged": [{
    "symbol": string,
    "quote_currency": string,
    "contract_type": string,
    "divergence_bps": number,
    "primary_sources": Source[],  // tier-filtered
    "computed_at": string
  }]
}

Futures settlements

GET/v1/settlementsBearer · Pro+

Daily settlement series for GC, SI, HG futures. Every row today is a proxy sourced from a public daily-close series (typically within $1–$5 of the official exchange settlement) and carries a disclaimer field until the licensed feed swaps in.

Query parameters

symbolstringREQUIRED
One of GC, SI, HG.
fromdate
YYYY-MM-DD. Defaults to 30 days before to.
todate
YYYY-MM-DD. Defaults to today.
limitint
1–365, default 30. Window itself is capped at 365 days.

Response codes

200 OK400 invalid_range403 plan_gated

Response schema

{
  "settlements": [{
    "symbol": string,
    "settlement_date": string,     // "YYYY-MM-DD"
    "settlement_price": string | null,
    "prior_settlement": string | null,
    "change_value": string | null,
    "volume": number | null,
    "open_interest": number | null,
    "source": string | null,
    "source_type": string,         // e.g. "proxy_daily_close"
    "source_timestamp": string | null,
    "fetched_at": string | null,
    "disclaimer": string           // present only when source_type is a proxy
  }]
}

Convert

GET/v1/convertNo auth required · Free+

Convert between metals, currencies, and units. Metal legs: XAU, XAG (no HG — copper has no spot row). Currency legs: 31 currencies (AUD, BGN, BRL, CAD, CHF, CNY, CZK, DKK, EUR, GBP, HKD, HUF, IDR, ILS, INR, ISK, JPY, KRW, MXN, MYR, NOK, NZD, PHP, PLN, RON, SEK, SGD, THB, TRY, USD, ZAR). Rates come live (~60s) from exchangerate.dev, our sibling currency API, with ECB daily reference rates as fallback. Historical (date) conversion is not supported — use /v1/prices/history and do the cross yourself.

Query parameters

fromstringREQUIRED
Source symbol: XAU, XAG, USD, EUR, …
tostringREQUIRED
Target symbol.
amountnumber
Default 1. Must be finite and positive.
unitstring
One of oz (default), gram, kg. Applies to the metal side only.

Response codes

200 OK400 unsupported_currency400 unsupported_unit400 bad_request503 spot_unavailable

Response schema

{
  "from": string,
  "to": string,
  "amount": string,      // decimal-as-string
  "rate": string,
  "result": string,
  "unit": string,        // "oz" | "gram" | "kg"
  "timestamp": string    // UTC ISO-8601
}

Karat / carat pricing

GET/v1/caratNo auth required · Free+

Per-gram XAU price at every common karat purity, in one call. See the focused karat gold price API guide for formulas, examples, and MCP usage.

Query parameters

currencystring
Default USD. Same 31-currency set as /v1/convert.

Response codes

200 OK400 unsupported_currency503 spot_unavailable

Response schema

{
  "currency": string,
  "timestamp": string,
  "price_gram_24k": string, "price_gram_22k": string, "price_gram_21k": string,
  "price_gram_20k": string, "price_gram_18k": string, "price_gram_16k": string,
  "price_gram_14k": string, "price_gram_10k": string
}

Tier catalog

GET/v1/metadata/tiersNo auth required · Free+

Authoritative, machine-readable tier catalog — the same values that back the /pricing page. Static; cached 1 hour.

Response codes

200 OK

Response schema

// array, one entry per tier: free, basic (hidden), physical, pro, realtime
[{
  "name": string,
  "monthly_price_usd": string,
  "yearly_price_usd": string,
  "rate_limit_per_minute": number,
  "monthly_quota": number,
  "allowed_bases": string[],       // e.g. ["XAU"], ["XAU","XAG","HG"]
  "allowed_contracts": string[],   // e.g. ["spot"], ["spot","futures"]
  "includes_mcp": boolean,
  "commercial_use": boolean,
  "support_sla_hours": number | null,
  "max_concurrent_streams": number
}]

Account & API keys

Self-serve key management and usage counters. All four operations require a bearer token — there is no separate dashboard-only auth path.

GET/v1/account/keysBearer · Free+

List your non-revoked (and grace-window) API keys.

Response codes

200 OK401 unauthenticated

Response schema

[{
  "id": string,
  "key_prefix": string,
  "name": string,
  "created_at": string,
  "last_used_at": string | null,
  "revoked_at": string | null   // future-dated during the 24h grace window
}]
POST/v1/account/keysBearer · Free+

Mint a new key. Every currently-active key on the org is scheduled for revocation in 24h (grace period) rather than revoked immediately, so in-flight deploys don't break.

Response codes

201 Created401 unauthenticated

Response schema

{
  "id": string,
  "plaintext": string,   // shown once — store it now
  "key_prefix": string,
  "created_at": string,
  "previous_key_revokes_at": string | null
}
DELETE/v1/account/keys/{key_id}Bearer · Free+

Hard-revoke a key immediately (no grace window).

Response codes

204 No Content401 unauthenticated404 key_not_found
GET/v1/account/usageBearer · Free+

Today's and this month's call counts for the authed org.

Response codes

200 OK401 unauthenticated

Response schema

{
  "calls_today": number,
  "calls_this_month": number
}

OHLC bars, ratios & bulk history

Real OHLCV bar history from the canonical price_bars store — XAU/USD daily back to 1996 (intraday intervals from 2006). Depth is tier-windowed, not endpoint-gated: /v1/bars serves XAU-USD spot daily bars for the last 30 days free, one year on Physical, and the full daily history plus every symbol (XAG, GLD, GC/SI/HG) on Pro+. Intraday intervals (1m–4h) are Pro+ and capped at the most recent 30 days. Cross-commodity /v1/ratios is Pro+. Bulk /v1/download (paid floor: Physical one year, Pro+ full) serves per-year parquet — including the deep intraday archive back to 2006.

/v1/bars — OHLCV bar history

GET/v1/barsBearer optional · Free+

Cursor-paginated OHLCV bars from the canonical price_bars store, newest-first. Replaces /v1/prices/history. Volume is real for futures (GC/SI/HG) and ETFs (GLD); null for spot (no consolidated spot volume). is_closedmarks whether the bar's window has settled — false is the currently-forming bar. Free and Physical see XAU-USD spot daily bars within their window (30 days / 1 year); the other symbols (XAG, GLD, GC/SI/HG) and intraday intervals (1m–4h) require Pro+. Pro+ unlocks full daily history to 1996, but intraday intervals are capped at the most recent 30 days on every tier — use /v1/download for the deep intraday archive back to 2006. For implementation examples, pagination, and tier windows, see the historical gold price API guide.

Query parameters

symbolstringREQUIRED
E.g. XAU-USD-SPOT, XAU/USD, GLD. Free/Physical: XAU-USD spot only.
intervalstring
One of 1m, 5m, 15m, 30m, 1h, 2h, 4h, 1d. Default 1d. Intraday (1m–4h) is Pro+ and capped at the last 30 days.
fromdateREQUIRED
ISO-8601 UTC (inclusive).
todateREQUIRED
ISO-8601 UTC (inclusive).
cursorstring
Opaque keyset cursor from next_cursor in a prior response.
limitinteger
Max bars per page (1–10000). Default 100.

Response codes

200 OK400 range_too_deep403 plan_gated429 rate_limited

Response schema

// 200 OK
{
  "symbol": string,
  "interval": string,
  "bars": Bar[],
  "next_cursor": string | null,  // null = exhausted
  "meta": {
    "tier": string,
    "count": number,
    "source_id": string | null
  }
}

// Bar
{
  "bar_start": string,       // ISO-8601 UTC with Z suffix
  "open": string | null,     // decimal-as-string
  "high": string | null,
  "low": string | null,
  "close": string | null,
  "volume": string | null,   // null for spot; real for futures/ETF
  "is_closed": boolean       // false = forming bar (provisional)
}

/v1/bars/latest — latest bar

GET/v1/bars/latestBearer optional · Free+

Returns the single most-recent bar for a symbol+interval — either the currently-forming bar (is_closed: false) or the last settled bar. Always 200; bar is null when no bar exists. Same per-symbol gate as /v1/bars (Free/Physical: XAU-USD spot; XAG, GLD and futures are Pro+); no depth window applies to the latest bar. There is no bar WebSocket channel — poll this endpoint for a near-real-time latest bar.

Query parameters

symbolstringREQUIRED
E.g. XAU-USD-SPOT, GLD.
intervalstring
One of 1m1d. Default 1d.

Response schema

// 200 OK
{
  "symbol": string,
  "interval": string,
  "bar": Bar | null,         // null when no bar exists
  "meta": { "tier": string, "count": number, "source_id": string | null }
}

/v1/ratios — cross-commodity ratio series

GET/v1/ratiosBearer · Pro+

Daily ratio time-series derived from date-joined closing prices (numerator ÷ denominator). Only dates where BOTH legs have a settled bar are emitted — no forward-fill, no fabricated rows. Cursor-paginated, newest-first.

Query parameters

pairstringREQUIRED
Slug: gold-silver, gold-platinum, silver-platinum, gold-palladium, gld-xau.
fromdateREQUIRED
YYYY-MM-DD (inclusive).
todateREQUIRED
YYYY-MM-DD (inclusive).
cursorstring
Keyset cursor from a prior response.
limitinteger
Max points per page (1–10000). Default 100.

Response codes

200 OK400 unknown_pair403 plan_gated429 rate_limited

Response schema

// 200 OK
{
  "pair": string,
  "numerator": string,       // resolved symbol
  "denominator": string,
  "interval": string,        // "1d"
  "points": RatioPoint[],
  "next_cursor": string | null,
  "meta": { "tier": string, "count": number }
}

// RatioPoint
{
  "date": string,            // "YYYY-MM-DD"
  "ratio": string,           // 4 dp decimal-as-string
  "numerator_close": string,
  "denominator_close": string
}

/v1/ratios/latest — latest ratio point

GET/v1/ratios/latestBearer · Pro+

Most-recent shared-date ratio point for a pair. Always 200; point is null when no shared date exists.

Query parameters

pairstringREQUIRED
E.g. gold-silver.

Response schema

// 200 OK
{
  "pair": string,
  "numerator": string,
  "denominator": string,
  "interval": string,
  "point": RatioPoint | null,
  "meta": { "tier": string, "count": number }
}

/v1/download — bulk OHLCV history

GET/v1/downloadBearer · Physical+ (paid floor)

Bulk history as one parquet file per symbol + interval + year. Returns a 307 redirect to a time-limited presigned URL (1-hour TTL) in cold storage (R2) — follow it to download. Free and anonymous callers are blocked (bulk history is the paid floor); Physical downloads its 1-year window of XAU-USD spot, Pro+ the full history and every symbol. Useful for backfill or offline analysis without cursor-paginating /v1/bars.

Query parameters

symbolstringREQUIRED
E.g. XAU-USD-SPOT, GLD. Physical: XAU-USD spot only.
yearintegerREQUIRED
Calendar year (1996–present). One parquet file per year.
intervalstring
One of 1m1d. Default 1d.
fmtstring
parquet (default) or csv.

Response codes

307 → presigned URL401 authentication_required403 plan_gated404 not_found

Response

307 Temporary Redirect with a Location header pointing at the presigned parquet URL (expires in 1 hour). No JSON body — most HTTP clients follow the redirect automatically.

Physical dealer prices

GET/v1/physical/{country}Bearer · Physical+

Latest bullion dealer sell and buyback quotes for one country, with premium_over_spot_bps per quote and a live spot reference. Twelve countries: UAE, China, Egypt, Hong Kong, Indonesia, India, Japan, Malaysia, Nepal, Pakistan, Saudi Arabia, Vietnam. GET /v1/physical (no path param) returns the live country index instead.

Full reference (sample responses, error codes, per-country coverage) is on the dedicated page: /docs/physical.

WebSocket stream

WSwss://api.goldprice.dev/v1/streamAuth-on-connect · Realtime Pro

Full-duplex feed for real-time XAU and XAG spot ticks. On the same connection you can also subscribe to the physical:{country} channel — pushed when a dealer quote changes. Authentication happens on the first client frame ({"action":"auth","api_key":"ga_live_…"}); the server closes with code 4401 on bad auth. Max 10 concurrent connections per Realtime Pro key. Tick shape matches the SSE feed — price and conf are decimal strings, computed_at is ISO-8601 UTC with a Z suffix.

The stream carries live prices and channel payloads only — it does not push OHLC bars. For the freshest forming or settled bar, poll /v1/bars/latest.

Full protocol reference (client frames, server frames, heartbeat semantics, error codes, browser JS + Python examples, and a live playground) is on the dedicated page: /docs/stream.