To get silver prices in Node.js, call https://api.goldprice.dev/v1/spot/XAG-USD-SPOT with native fetch and your goldprice.dev API key in the X-API-Key header. The price is in USD per troy ounce. Use decimal.js for price math and cache responses to save calls. Free includes 5,000 calls a month with prices delayed by 15 minutes. Paid plans provide live prices. Check is_stale and computed_at before using a response.
Get your goldprice.dev API key
Create a Free account at goldprice.dev/onboarding and get your API key. Set it as an environment variable:
export GOLDPRICE_API_KEY=ga_live_replace_with_your_key_hereFree includes silver spot in USD, 5,000 calls a month, and 10 requests a minute. Prices are 15 minutes late. No credit card is required.
Install decimal.js
The sample uses native fetch to make requests. Install decimal.js to work with the API's price strings without converting them to JavaScript's Number type first:
npm install decimal.jsWrite the silver price client
Save this as goldprice.mjs. The spot() function caches each symbol for a minute in a Map. It makes up to three attempts when requests return 429, waiting longer between attempts.
Prices become Decimal values. Bid and ask become null when absent and appear only on plans that include them. The returned object also keeps the response's stale flag and calculation time.
// node: goldprice.mjs// curl-equivalent: https://api.goldprice.dev/v1/spot/XAG-USD-SPOTimport Decimal from "decimal.js";const API_BASE = "https://api.goldprice.dev";const API_KEY = process.env.GOLDPRICE_API_KEY;if (!API_KEY) { throw new Error("GOLDPRICE_API_KEY not set");}const TTL_MS = 60_000;const cache = new Map();/** Fetch the latest spot price. Cached 60s per symbol, retries 3x on 429. */export async function spot(symbol = "XAG-USD-SPOT") { const cached = cache.get(symbol); if (cached && cached.expiresAt > Date.now()) { return cached.data; } let lastErr; for (let attempt = 0; attempt < 3; attempt++) { const res = await fetch(`${API_BASE}/v1/spot/${symbol}`, { headers: { "X-API-Key": API_KEY }, signal: AbortSignal.timeout(5000), }); if (res.status === 429) { lastErr = new Error("goldprice: 429 rate limited"); if (attempt < 2) { const backoffMs = 2 ** attempt * 1000; // 1s, then 2s await new Promise((resolve) => setTimeout(resolve, backoffMs)); } continue; } if (!res.ok) { throw new Error(`goldprice: unexpected status ${res.status}`); } const raw = await res.json(); const data = { symbol: raw.symbol, quoteCurrency: raw.quote_currency, price: new Decimal(raw.price), bid: raw.bid == null ? null : new Decimal(raw.bid), ask: raw.ask == null ? null : new Decimal(raw.ask), isStale: raw.is_stale, computedAt: raw.computed_at, }; cache.set(symbol, { data, expiresAt: Date.now() + TTL_MS }); return data; } throw lastErr;}Run it
Import the module and call spot(). The first call requests a silver price from the API. Calls for that symbol within a minute return the cached object.
The cache belongs to the running process. Restarting clears it, and separate workers keep separate caches. The output comment is an example, not a current price.
import { spot } from "./goldprice.mjs";const r = await spot("XAG-USD-SPOT");console.log(`${r.symbol}-${r.quoteCurrency}: ${r.price} (computed ${r.computedAt})`);// XAG-USD: 53.89 (computed 2026-10-23T07:00:18.221118+00:00)Switch metal or convert silver
Use the same spot() function for silver, gold, or copper. Each symbol has its own cache entry. Silver and gold prices are per troy ounce. Copper is per pound.
Silver spot symbols exist only in USD. For silver in EUR per gram, call GET /v1/convert?from=XAG&to=EUR&amount=1&unit=gram separately. Conversion supports oz, gram, and kg. Without a key, prices are 15 minutes late and requests are limited to 100 an hour per IP.
// Silver: USD per troy ounceawait spot("XAG-USD-SPOT");// Gold: USD per troy ounceawait spot("XAU-USD-SPOT");// Copper: USD per poundawait spot("HG-USD-SPOT");Expected output
{ "symbol": "XAG", "quote_currency": "USD", "unit": "troy_ounce", "contract_type": "spot", "price": "53.89", "is_stale": false, "computed_at": "2026-10-23T07:00:18.221118+00:00"}The JSON shows an example API response. The script prints the symbol, quote currency, price, and calculation timestamp. Your application receives the object returned by spot(), with prices as Decimal values and the metadata available as isStale and computedAt.
Common errors
| Code | What you see | Fix |
|---|---|---|
| 401 | goldprice: unexpected status 401 on the first call | Check that GOLDPRICE_API_KEY contains your API key and that the request sends it in X-API-Key. Get a key through onboarding if needed. An empty environment variable causes GOLDPRICE_API_KEY not set when the module loads, before any request. |
| 429 | Three attempts return 429, then spot() rejects | Check your request rate and remaining quota. Free allows 10 requests a minute and 5,000 calls a month. The cache saves calls for repeated symbols within one process, but separate workers and simultaneous requests can still exceed a limit. Reduce requests or review pricing for a suitable plan. |
| N/A | Price calculations show unexpected decimal places | Keep the API's price strings as decimal.js Decimal values during arithmetic. Converting them to Number can introduce floating point rounding. Use .toString() when serializing, and round explicitly for display. Do not assume every silver price has the same number of decimal places. |
Going further
- Share cached silver prices across workers if your application runs in multiple processes
- Use
/v1/convertto show silver in another currency or in grams - Return the price, unit, stale flag, and calculation time from your application's price route
- Share one pending request among callers asking for the same uncached symbol
- Track cache hits, request failures, and rate limit responses to understand your API usage