TutorialsCode

Silver price in PHP

Get silver prices from goldprice.dev with native cURL, decimal math with BCMath, retries on 429, and a cache per symbol. No Composer required.

23 Oct 2026 · 4 min read

To get silver prices in PHP, call goldprice.dev at /v1/spot/XAG-USD-SPOT using native cURL and your API key in the X-API-Key header. The price is in USD per troy ounce. Keep prices as strings and use BCMath for decimal arithmetic. Free prices are 15 minutes late; paid plans are live. The example caches responses within the same process and retries requests that return 429.

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:

Shell
export GOLDPRICE_API_KEY=ga_live_replace_with_your_key_here

Free includes silver spot in USD, 5,000 calls a month and 10 requests a minute. Prices are 15 minutes late. No credit card required.

Check the required extensions

This example needs curl, json and bcmath enabled in the PHP installation that runs it. No Composer packages are required. Check the loaded modules below. If an extension is missing, install or enable it for your PHP version.

shell
php -m | grep -E '^(curl|json|bcmath)$'# curl# json# bcmath   <- if missing, install php8.3-bcmath (or enable in php.ini)

Write the silver price client

Save this as goldprice.php. The spot() method keeps a separate cached response for each symbol for 60 seconds within the process. It makes up to 3 attempts when requests return 429.

Prices stay as strings for BCMath. Read is_stale and computed_at when deciding how to display the result. Free prices remain delayed even when is_stale is false.

goldprice.php
<?php// php: goldprice.php, native cURL + BCMath, no Composer// curl-equivalent: https://api.goldprice.dev/v1/spot/XAG-USD-SPOTdeclare(strict_types=1);const API_BASE = 'https://api.goldprice.dev';const TIMEOUT  = 5;   // secondsconst TTL      = 60;  // secondsfinal class RateLimitedException extends RuntimeException {}final class GoldpriceClient{    private string $apiKey;    /** @var array<string, array{data: array, expires: int}> */    private static array $cache = [];    public function __construct()    {        $key = getenv('GOLDPRICE_API_KEY');        if ($key === false || $key === '') {            throw new RuntimeException('GOLDPRICE_API_KEY not set');        }        $this->apiKey = $key;    }    /**     * Fetch the latest spot price. Cached 60s per symbol, retries 3x on 429.     * Prices stay as strings for BCMath.     */    public function spot(string $symbol = 'XAG-USD-SPOT'): array    {        $now = time();        if (isset(self::$cache[$symbol]) && self::$cache[$symbol]['expires'] > $now) {            return self::$cache[$symbol]['data'];        }        for ($attempt = 0; $attempt < 3; $attempt++) {            try {                $data = $this->fetch($symbol);                self::$cache[$symbol] = ['data' => $data, 'expires' => $now + TTL];                return $data;            } catch (RateLimitedException) {                if ($attempt < 2) {                    sleep(1 << $attempt); // 1s, then 2s                }            }        }        throw new RateLimitedException('goldprice: 429 after 3 retries');    }    private function fetch(string $symbol): array    {        $ch = curl_init(API_BASE . '/v1/spot/' . rawurlencode($symbol));        curl_setopt_array($ch, [            CURLOPT_RETURNTRANSFER => true,            CURLOPT_TIMEOUT        => TIMEOUT,            CURLOPT_HTTPHEADER     => ['X-API-Key: ' . $this->apiKey],        ]);        $body = curl_exec($ch);        $code = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);        curl_close($ch);        if ($code === 429) {            throw new RateLimitedException('rate limited');        }        if ($code !== 200 || $body === false) {            throw new RuntimeException("goldprice: unexpected status {$code}");        }        return json_decode((string) $body, true, 512, JSON_THROW_ON_ERROR);    }}$client = new GoldpriceClient();$r = $client->spot('XAG-USD-SPOT');// Prices are strings; use BCMath for exact math (e.g. price for 5 oz):$fiveOz = bcmul($r['price'], '5', 4);printf("%s-%s: %s (computed %s)\n", $r['symbol'], $r['quote_currency'], $r['price'], $r['computed_at']);printf("5 troy oz = %s %s\n", $fiveOz, $r['quote_currency']);

Run the client

Run the file from the shell where you set GOLDPRICE_API_KEY. It fetches silver in USD per troy ounce and calculates a total with BCMath. The output below is an example, not a current quote.

Further calls within the cache window reuse the response in the same process. Under PHP-FPM, this static array does not persist across requests. Use a shared cache if separate requests need to reuse a response.

shell
php goldprice.php# XAG-USD: 54.020 (computed 2026-10-23T18:12:06.354573+00:00)# 5 troy oz = 270.1000 USD

Switch metal or convert currency

Use spot() for silver, gold or copper. Silver and gold here are priced in USD per troy ounce. Copper is priced in USD per pound. Each symbol has a separate cache entry.

Silver spot symbols exist only in USD. For silver in euros per gram, make a separate GET request to /v1/convert?from=XAG&to=EUR&amount=1&unit=gram. This conversion works without a key, with prices 15 minutes late and a limit of 100 requests an hour per IP.

goldprice.php · multi-currency
$client = new GoldpriceClient();// Silver in USD per troy ounce$client->spot('XAG-USD-SPOT');// Gold in USD per troy ounce$client->spot('XAU-USD-SPOT');// Copper in USD per pound$client->spot('HG-USD-SPOT');

Expected output

JSON
{  "symbol": "XAG",  "quote_currency": "USD",  "unit": "troy_ounce",  "contract_type": "spot",  "price": "54.020",  "is_stale": false,  "computed_at": "2026-10-23T18:12:06.354573+00:00"}

The CLI prints the silver price and timestamp, then a calculated total. The JSON shows the response a Free key receives, with prices as strings. Check is_stale and computed_at before displaying a response.

Common errors

CodeWhat you seeFix
401RuntimeException: goldprice: unexpected status 401Check that the API key is valid and available to the PHP process. Under PHP-FPM, configure GOLDPRICE_API_KEY in the server environment; exporting it in your terminal does not configure web requests. Get your key through your account and keep it on the server.
429All request attempts return 429, then RateLimitedException is thrownCheck your request rate and remaining quota. Free allows 10 requests a minute and 5,000 calls a month. A shared cache reduces duplicate calls across web requests, but retries do not restore an exhausted quota. Reduce requests or review the limits at pricing.
N/ARounding errors after converting silver prices to floatsKeep the price string returned by the API. Use bcadd, bcmul and bccomp with an explicit scale for decimal arithmetic. Converting to (float) first can lose precision. If the BCMath functions are undefined, enable bcmath in the PHP installation running the code.

Going further

  • Share cached responses across PHP-FPM requests, with separate entries for each symbol
  • Check is_stale and display computed_at beside the silver price
  • Use the conversion endpoint for silver in another currency or in oz, gram or kg
  • For your own per-gram calculation, use BCMath and the conversion of 31.1035 g per troy ounce
  • Read the API reference for response fields and the quickstart for request setup

Questions

Are silver prices live on the free tier?

Silver prices on Free are 15 minutes late. Paid plans provide live prices. The cache in this example only controls how often your process fetches a response; it does not change the delay attached to your plan.

What is the free tier quota?

Free includes silver spot with 5,000 calls a month and 10 requests a minute, with no credit card required. Share cached responses across web requests to reduce duplicate calls. Check pricing if your application needs more capacity.

Can I get silver in another currency?

Silver spot symbols exist only in USD. For another currency, use /v1/convert?from=XAG&to=EUR&amount=1&unit=gram. Conversion supports oz, gram and kg. Without a key, prices are 15 minutes late and the limit is 100 requests an hour per IP.

Why use BCMath for silver prices?

Silver prices can include decimal places, and the API returns them as strings. Keep those strings for BCMath calculations. Binary floats can introduce rounding differences. Choose an explicit scale for each calculation because BCMath results still depend on that scale.

Do I need Composer or Guzzle?

This example does not require Composer or Guzzle. It uses native cURL for the request, JSON decoding for the response and BCMath for decimal calculations. Check that the required extensions are enabled in the PHP installation that runs your application.

Which metals can this client fetch?

The example calls silver with XAG-USD-SPOT, gold with XAU-USD-SPOT and copper with HG-USD-SPOT. Silver and gold use USD per troy ounce. Copper uses USD per pound, so keep the unit with each price when displaying or comparing results.

Can Claude get silver prices through MCP?

Yes. The goldprice.dev MCP server provides get_spot_price for silver. Connect Claude to https://api.goldprice.dev/v1/mcp/ without a key, or use npx @nusantara-ventures/goldprice-mcp with a key. Free and keyless prices are delayed; paid plans provide live prices.

Keep reading

Start with a free API key

5,000 requests a month on the free plan. No credit card.

Get a free key