Silver price in Python

Fetch XAG/USD spot and daily bars in Python with Decimal, auth, and freshness checks.

Updated

Use goldprice.dev to fetch silver with GET https://api.goldprice.dev/v1/spot/XAG-USD-SPOT and a Pro or Realtime Pro API key in the Bearer header. Parse price strings as Decimal, reject stale quotes, and request daily history from /v1/bars. The example below keeps authentication in an environment variable, converts troy ounces to grams, and handles 401, 403, and 429 responses.

  1. 1.Create a Pro-tier API key

    Silver spot and silver history are available on Pro and Realtime Pro. Store the key outside your source code:

    export GOLDPRICE_API_KEY=ga_live_replace_with_your_key

    Do not put a key in a notebook checked into git or a client-side application. The Free tier does not include XAG.

    Get a silver API keySilver requires Pro or Realtime Pro.
    Compare plans →
  2. 2.Install the HTTP client

    Install requests. The standard library decimal module avoids binary floating-point representation errors; division still uses the configured Decimal precision.

    BASH · shell
    python -m pip install requests
  3. 3.Fetch spot and daily history

    Save this as silver_price.py. It uses the canonical Bearer header, checks the tier response, parses decimal strings, rejects stale data, and reverses newest-first bars into chronological order. The canonical response uses bars, bar_start, and is_closed; a forming daily bar is provisional. This example limits the range to 90 days with a 100-row page, so it does not silently truncate a longer series.

    PYTHON · silver_price.py
    import os
    from datetime import datetime, timedelta, timezone
    from decimal import Decimal
    import requests
    
    BASE = "https://api.goldprice.dev"
    KEY = os.environ["GOLDPRICE_API_KEY"]
    HEADERS = {"Authorization": f"Bearer {KEY}"}
    TROY_OUNCE_GRAMS = Decimal("31.1034768")
    
    def get_json(path, params=None):
        response = requests.get(BASE + path, headers=HEADERS, params=params, timeout=10)
        if response.status_code == 401:
            raise RuntimeError("401: check GOLDPRICE_API_KEY")
        if response.status_code == 403:
            raise RuntimeError("403: XAG requires a Pro or Realtime Pro key")
        if response.status_code == 429:
            raise RuntimeError("429: wait for the Retry-After window before trying again")
        response.raise_for_status()
        return response.json()
    
    def silver_spot():
        data = get_json("/v1/spot/XAG-USD-SPOT")
        price = Decimal(data["price"])
        if data.get("is_stale"):
            raise RuntimeError("the API marked this quote stale")
        return {
            "price_per_oz": price,
            "price_per_gram": price / TROY_OUNCE_GRAMS,
            "computed_at": data["computed_at"],
        }
    
    def silver_history(days=30):
        if not 1 <= days <= 90:
            raise ValueError("this example supports 1 to 90 daily bars per request")
        end = datetime.now(timezone.utc).date()
        start = end - timedelta(days=days - 1)
        data = get_json("/v1/bars", {
            "symbol": "XAG-USD-SPOT", "interval": "1d",
            "from": start.isoformat(), "to": end.isoformat(), "limit": 100,
        })
        return [
            {"date": bar["bar_start"][:10], "close": Decimal(bar["close"]), "is_closed": bar["is_closed"]}
            for bar in reversed(data["bars"])
            if bar.get("close") is not None
        ]
    
    if __name__ == "__main__":
        quote = silver_spot()
        print(f"XAG/USD per oz: {quote['price_per_oz']}")
        print(f"XAG/USD per gram: {quote['price_per_gram']}")
        print(f"Computed: {quote['computed_at']}")
        print(f"Daily bars returned: {len(silver_history())}")
  4. 4.Run the client

    Run python silver_price.py. Keep the computed_at timestamp with every stored value. A quote can be current at request time yet still be marked stale by the service, so treat that flag as a data-quality check.

    BASH · shell
    python silver_price.py
    # XAG/USD per gram: 1.04...
    # Daily bars returned: depends on available observations
  5. 5.Control request volume

    One spot call plus one history call per run is two calls. A script run every 15 minutes uses about 5,760 calls/month, before retries. Cache spot for at least 60 seconds, batch work where possible, and choose a tier whose monthly quota covers your schedule.

    PYTHON · quota.py
    calls_per_month = 2 * 4 * 24 * 30  # 5,760 calls for a 15-minute schedule
    print(calls_per_month)

Expected output

The API returns this shape:

JSON · GET /v1/spot/XAU-USD-SPOT
{
  "symbol": "XAG",
  "quote_currency": "USD",
  "price": "32.50",
  "is_stale": false,
  "computed_at": "2026-09-29T10:00:00+00:00"
}

The script prints the Decimal price per troy ounce, the Decimal price per gram, the source timestamp, and the number of daily bars returned (which can be less than the requested calendar-day range on weekends or when data is unavailable).

Common errors

CodeSymptomFix
401The request returns 401.Check that GOLDPRICE_API_KEY is set and send it as Authorization: Bearer ....
403The request returns 403 plan_gated.XAG is not included on Free. Use a Pro or Realtime Pro key and check pricing.
429The request returns 429.Honor Retry-After, cache repeated symbols, and reduce the schedule before increasing tier.

FAQ

Is silver available on the Free tier?

No. XAG spot and XAG history require Pro or Realtime Pro. Gold spot remains the Free-tier example.

How many calls does the example make?

One spot request and one daily-history request per run. A 15-minute schedule is about 5,760 calls per 30-day month before retries.

Why use Decimal?

The API sends numeric prices as strings. Decimal preserves decimal inputs and makes the rounding context explicit instead of introducing binary float rounding; choose a quantization policy before displaying or storing derived values.

How do I detect an old quote?

Check is_stale and retain computed_at. Apply an application-specific age policy to the timestamp before displaying or storing a quote.

Can an AI agent use the same silver data?

Yes. The goldprice.dev MCP server exposes the same product surface for supported plans. Use the API docs and the MCP setup guide to keep tool and tier assumptions current.

Can I use this in a commercial application?

Commercial use requires Pro or Realtime Pro with the attribution required by the terms. Keep the API key on your server.

Going further

  • Store the raw response beside each normalized bar for reproducibility.
  • Add a circuit breaker that stops retries when the service reports a stale quote.
  • Use the same Decimal unit boundary when valuing silver holdings by gram.

Next steps

Try the same setup in a different platform:

Browse all 13 tutorials →