Docs / API Reference

Gold Price API Reference

Supported REST operations. Base URL: https://api.goldprice.dev/v1

OpenAPI schema · ReDoc reference. These include generated request parameters and status codes. The JSON response shapes and auth notes for legacy unmodeled handlers are below.

For authenticated operations, send Authorization: Bearer YOUR_API_KEY. X-API-Key: YOUR_API_KEY is also accepted as an alias.

Invalid parameters return 422 validation_error. Across REST operations, a supplied invalid key can return 401 invalid_api_key; limits return 429 rate_limited, rate_limit_exceeded, or quota_exceeded; and a key-verification outage returns 503 auth_unavailable. Endpoint-specific errors are listed below. An unexpected unhandled failure can return a plain-text 500.

Live prices

GET/v1/pricesAnonymous or bearer · Free+

Latest XAU, XAG, and HG spot; omit symbol for all allowed symbols. Licensed spot: Free/keyless 15 minutes late, paid live. Futures: Legacy plans only, delayed public feeds. Bid/ask are optional, paid-only. Request sources[], karat grams, or OHLC/divergence stats via ?include=.

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 (Legacy plans only). Use copper spot as HG-USD-SPOT. 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 limit / quota exceeded

Response schema

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

// SpotRow: required keys
{
  "symbol": string,
  "quote_currency": string,
  "unit": string,             // "troy_ounce" for XAU/XAG; "pound" for HG
  "contract_type": string,    // "spot" | "futures"
  "is_stale": boolean
}

// Optional core keys; omitted when unavailable
{
  "price"?: string,           // decimal-as-string
  "bid"?: string,             // paid plans only
  "ask"?: string,             // paid plans only
  "computed_at"?: string      // 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,
  "open_price"?: string, "high_price"?: string, "low_price"?: string,
  "prev_close_price"?: string, "ch"?: string, "chp"?: string,
  "open_time"?: number        // epoch seconds at UTC midnight
}

// Source
{
  "source": string,
  "display_name"?: string,
  "price"?: string,
  "unit"?: string,
  "is_stale"?: boolean,
  "informational"?: boolean // true for reference-only feeds that never set the primary price
}

Price history deprecated: use /v1/bars

GET/v1/prices/historyAnonymous or bearer · Free+

Daily close history backfilled from multiple archival sources. This endpoint is deprecated in favour of /v1/bars. The Successful and plan-gated responses include Deprecation and Link headers; Sunset is included once a retirement date is configured. Free returns 30 days; Basic one year; Plus and Pro daily XAU from 1996, XAG from 2007, and copper spot from 2026-09-16.

Query parameters

symbolstringREQUIRED
A single symbol, e.g. XAU-USD-SPOT.
fromdateREQUIRED
YYYY-MM-DD.
todateREQUIRED
YYYY-MM-DD.
intervalstring
One of 1d (default), 1h.
limitinteger
Maximum rows, from 1 to 10,000. Default 100.

Response codes

200 OK400 bad_request403 plan_gated429 limit / quota exceeded

Response schema

// 200 OK
// Successful and plan-gated response headers include:
//   Deprecation: true
//   Link: </v1/bars>; rel="successor-version"
//   Sunset: <ISO-8601 date>  // once configured
{
  "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 · Legacy plans only

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.

Path parameters

assetstringREQUIRED
One of XAU, XAG, HG.

Response codes

200 OK400 bad_request403 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": SourceBlock[],
  "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
}

// SourceBlock
{
  "id": string,
  "publisher": string,
  "url": string,
  "retrieved_at": string | null, // ISO-8601 UTC
  "type": "futures"
}

Single-symbol spot

GET/v1/spot/{symbol}Anonymous or bearer · Free+

This convenience alias for /v1/prices uses the same tier gate and fields, but returns a flat response (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 limit / quota exceeded

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 · Legacy plans only

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. These are delayed public-feed values.

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 bad_request403 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 (not HG, because copper conversion is unsupported). Currency legs: 35 currencies (AUD, BGN (fixed to the euro), BRL, CAD, CHF, CNY, CZK, DKK, EGP, EUR, GBP, HKD, HUF, IDR, ILS, INR, ISK, JPY, KRW, MXN, MYR, NOK, NPR, NZD, PHP, PKR, PLN, RON, SEK, SGD, THB, TRY, USD, VND, ZAR). Rates come live (~60s) from exchangerate.dev, our sibling currency API. If the live rate is not fresh, we use the last stored exchangerate.dev rate up to three days old. Without one, calls return 503 fx_unavailable. 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_unavailable503 fx_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 35-currency set as /v1/convert.

Response codes

200 OK400 unsupported_currency503 spot_unavailable503 fx_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: free_2026, basic_2026, plus_2026, pro_2026 visible; legacy tiers hidden
[{
  "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,
  "hidden": boolean
}]

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).

Path parameters

key_idstringREQUIRED
The API-key ID returned by GET /v1/account/keys.

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,
  "active_streams": number | null,
  "max_streams": number | null
}

OHLC bars, ratios & bulk history

Real OHLCV bar history from the canonical price_bars store. Daily history starts in 1996 for XAU,2007 for XAG, and 2026-09-16 for copper spot. Depth is tier-windowed, not endpoint-gated: /v1/bars serves XAU, XAG, and HG spot on every plan. Daily depth: Free 30 days, Basic one year, Plus and Pro full. Intraday: Plus 1h and 4h for 30 days, Pro 1m to 4h at full depth; Free and Basic are daily only. Ratios, futures, and ETF/GLD bars are Legacy plans only. /v1/download is Basic+: Basic last year, Plus and Pro every year.

/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_closed marks whether the bar's window has settled. false is the currently-forming bar. All plans include XAU, XAG, and HG spot. Futures/ETF/GLD: Legacy plans only. Daily depth: Free 30 days, Basic one year, Plus and Pro full (XAU 1996, XAG 2007, copper 2026-09-16). Free and Basic: daily only. Plus: 1h and 4h, 30 days. Pro: 1m to 4h, full depth. Use /v1/download for bulk history within the available symbol range. For implementation examples, pagination, and tier windows, see the historical gold price API guide.

Query parameters

symbolstringREQUIRED
XAU, XAG, HG spot (e.g. XAU-USD-SPOT, XAU/USD). Futures/ETF: Legacy plans only.
intervalstring
One of 1m, 5m, 15m, 30m, 1h, 2h, 4h, 1d. Default 1d. Free/Basic: daily. Plus: 1h/4h, 30 days. Pro: 1m–4h, full depth.
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 limit / quota exceeded

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. A successful empty result is 200 with a null bar. The route can also return 403 plan_gated, 404 disabled, or 422 validation_error. Same per-symbol gate as /v1/bars: all plans include XAU, XAG, and HG spot; futures/ETF: Legacy plans only. Plan intervals apply; the latest bar has no depth window. No bar WebSocket channel; poll for the latest bar.

Query parameters

symbolstringREQUIRED
E.g. XAU-USD-SPOT; GLD: Legacy plans only.
intervalstring
One of 1m … 1d. 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 · Legacy plans only

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

Query parameters

pairstringREQUIRED
Slug: gold-silver, gld-xau. Platinum and palladium ratios are unavailable.
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_pair / bad_request403 plan_gated404 disabled429 limit / quota exceeded

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 · Legacy plans only

Most-recent shared-date ratio point for a pair. A successful empty result is 200 with a null point. The route can also return 400 unknown_pair, 403 plan_gated, 404 disabled, or 422 validation_error.

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 · Basic+

Bulk history as one precomputed Parquet or CSV archive 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. Basic gets the last year of files; Plus and Pro get every year. All paid plans include XAU, XAG, and HG spot. Futures and ETF/GLD files are Legacy plans only. Useful for backfill or offline analysis without cursor-paginating /v1/bars.

Query parameters

symbolstringREQUIRED
XAU, XAG, HG spot. Futures/ETF: Legacy plans only.
yearintegerREQUIRED
Calendar year within the available symbol history. One archive file per year and format.
intervalstring
One of 1m … 1d. Default 1d.
fmtstring
parquet (default) or csv. Both point to precomputed objects in cold storage; the serving API never transcodes a partition.

Response codes

307 → presigned URL401 authentication_required403 plan_gated404 disabled / not_found422 validation_error429 limit / quota exceeded500 storage_unavailable503 storage_error

Response

307 Temporary Redirect with a Location header pointing at the requested presigned archive URL (expires in 1 hour). There is no JSON body. Most HTTP clients follow the redirect automatically.

Physical dealer prices

GET/v1/physicalBearer · Basic+

Lists the countries with currently available physical-price data.

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

Latest bullion dealer sell and buyback quotes for one supported country, with premium_over_spot_bps per quote and the live gold spot price used for comparison. Use GET /v1/physical (no path param) for the current country list.

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 · Plus+

Full-duplex feed for real-time XAU, XAG, and HG spot spot ticks. On Pro, you can also subscribe to the physical:{country} channel to receive updates when a dealer quote changes. Authentication happens on the first client frame ({"action":"auth","api_key":"ga_live_…"}); the server closes on bad auth (4401) or a plan without streaming (4403). Plus: 1 connection shared with SSE; Pro: 5 SSE + 5 WebSocket, 8 symbols/socket. 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.