TutorialsCode

Silver price in .NET

Get silver prices from goldprice.dev in C#/.NET with HttpClient, decimal parsing, a cache, and retries for rate limits.

23 Oct 2026 · 5 min read

To get silver prices in C#/.NET, call https://api.goldprice.dev/v1/spot/XAG-USD-SPOT with HttpClient and your goldprice.dev key in the X-API-Key header. Parse price strings into decimal fields with System.Text.Json. The example caches each symbol for 60 seconds and retries rate limited requests. Silver spot is quoted in US dollars per troy ounce. Free includes 5,000 calls a month with prices delayed by 15 minutes. Paid plans are live.

Get your goldprice.dev API key

Create a Free account at goldprice.dev/onboarding and copy your API key. Set it in the shell where you will run the app:

Shell
export GOLDPRICE_API_KEY=ga_live_replace_with_your_key_here

Free includes silver spot, 5,000 calls a month, and 10 requests a minute. Prices are delayed by 15 minutes. No credit card is required.

Create the project

The .NET base class library provides HttpClient for requests and System.Text.Json for parsing responses. Create a console app with no extra packages:

shell
dotnet new console -o GoldpriceDemocd GoldpriceDemo

Write the silver price client

Save this as GoldpriceClient.cs. The API returns prices as strings. The custom JsonConverter reads them into decimal fields to preserve decimal places.

SpotAsync() stores each symbol in a ConcurrentDictionary for 60 seconds. It makes at most three requests when responses keep returning 429, waiting longer between attempts. Other unsuccessful responses throw immediately.

The record also reads is_stale and computed_at.

GoldpriceClient.cs
// GoldpriceClient.cs// curl-equivalent: https://api.goldprice.dev/v1/spot/XAG-USD-SPOTusing System.Collections.Concurrent;using System.Globalization;using System.Net.Http.Json;using System.Text.Json;using System.Text.Json.Serialization;namespace GoldpriceDemo;/// Converts the API's string-encoded price fields to decimal without/// the precision loss a double round-trip would introduce.public sealed class DecimalStringConverter : JsonConverter<decimal>{    public override decimal Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)        => decimal.Parse(reader.GetString()!, CultureInfo.InvariantCulture);    public override void Write(Utf8JsonWriter writer, decimal value, JsonSerializerOptions options)        => writer.WriteStringValue(value.ToString());}public sealed record SpotResponse(    [property: JsonPropertyName("symbol")] string Symbol,    [property: JsonPropertyName("quote_currency")] string QuoteCurrency,    [property: JsonPropertyName("price"), JsonConverter(typeof(DecimalStringConverter))] decimal Price,    [property: JsonPropertyName("is_stale")] bool IsStale,    [property: JsonPropertyName("computed_at")] string ComputedAt);public sealed class GoldpriceRateLimitedException : Exception{    public GoldpriceRateLimitedException() : base("goldprice: 429 rate limited") { }}public sealed class GoldpriceClient{    private const string ApiBase = "https://api.goldprice.dev";    private static readonly TimeSpan Ttl = TimeSpan.FromSeconds(60);    private readonly HttpClient _http;    private readonly ConcurrentDictionary<string, (SpotResponse Data, DateTimeOffset Expires)> _cache = new();    public GoldpriceClient(HttpClient http)    {        var apiKey = Environment.GetEnvironmentVariable("GOLDPRICE_API_KEY")            ?? throw new InvalidOperationException("GOLDPRICE_API_KEY not set");        _http = http;        _http.BaseAddress = new Uri(ApiBase);        _http.Timeout = TimeSpan.FromSeconds(5);        _http.DefaultRequestHeaders.Add("X-API-Key", apiKey);    }    /// Fetches the latest spot price. Cached 60s per symbol, retries 3x on 429.    public async Task<SpotResponse> SpotAsync(string symbol = "XAG-USD-SPOT", CancellationToken ct = default)    {        if (_cache.TryGetValue(symbol, out var cached) && cached.Expires > DateTimeOffset.UtcNow)        {            return cached.Data;        }        for (var attempt = 0; attempt < 3; attempt++)        {            using var response = await _http.GetAsync($"/v1/spot/{symbol}", ct);            if (response.StatusCode == System.Net.HttpStatusCode.TooManyRequests)            {                if (attempt < 2)                {                    await Task.Delay(TimeSpan.FromSeconds(Math.Pow(2, attempt)), ct); // 1s, then 2s                }                continue;            }            if (!response.IsSuccessStatusCode)            {                throw new HttpRequestException($"goldprice: unexpected status {(int)response.StatusCode}");            }            var data = await response.Content.ReadFromJsonAsync<SpotResponse>(cancellationToken: ct)                ?? throw new JsonException("goldprice: empty response body");            _cache[symbol] = (data, DateTimeOffset.UtcNow.Add(Ttl));            return data;        }        throw new GoldpriceRateLimitedException();    }}

Run the silver price request

Save this as Program.cs and run dotnet run from the shell where you set GOLDPRICE_API_KEY. The program prints the silver price in US dollars per troy ounce and its computation timestamp.

Repeated calls on the same client return the cached record until its 60 second lifetime ends. Restarting the program clears this cache. The sample output is an example, and your response will carry its own price and timestamp.

Program.cs
using GoldpriceDemo;using var http = new HttpClient();var client = new GoldpriceClient(http);var spot = await client.SpotAsync("XAG-USD-SPOT");Console.WriteLine($"{spot.Symbol}-{spot.QuoteCurrency}: {spot.Price} (computed {spot.ComputedAt})");// XAG-USD: 54.020 (computed 2026-10-23T18:12:06.354573+00:00)

Switch metal or convert silver

Use SpotAsync() for silver, gold, or copper. Silver and copper spot symbols exist only in US dollars. Silver and gold are priced per troy ounce. Copper is priced per pound, so keep the unit visible when comparing results.

For silver in another currency, make a separate request to /v1/convert?from=XAG&to=EUR&amount=1&unit=gram. Conversion supports oz, gram, and kg. Without a key, prices are delayed by 15 minutes and the limit is 100 requests an hour per IP.

Program.cs · multi-currency
// Silver in USD per troy ounceawait client.SpotAsync("XAG-USD-SPOT");// Gold in USD per troy ounceawait client.SpotAsync("XAU-USD-SPOT");// Copper in USD per poundawait client.SpotAsync("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 console prints the symbol, currency, decimal price, and computation timestamp. The JSON shows the response a Free key receives, with the price as a string. Read is_stale and computed_at from the actual response before using a price.

Common errors

CodeWhat you seeFix
401goldprice: unexpected status 401 on the silver requestSet GOLDPRICE_API_KEY to a valid key from your account in the shell running the app. Avoid printing the key in logs. An unset variable makes the constructor throw before the request; an invalid key can produce this response.
404goldprice: unexpected status 404 with a not_found errorThe API has no quote for that symbol. Silver spot is quoted in US dollars, so XAG-EUR-SPOT answers 404. Use XAG-USD-SPOT, or convert with the conversion endpoint described in the API reference. A symbol the API does not know can answer 403 plan_gated, and a malformed one answers 400 invalid_symbol.
429All three attempts return 429, then SpotAsync() throws GoldpriceRateLimitedExceptionReduce request frequency and stagger bursts. Free allows 10 requests a minute and 5,000 calls a month. The cache only helps repeated calls on the same client after a result is stored. Separate processes and simultaneous cache misses can still make extra requests. See pricing for plan limits.
N/APrice deserialization fails or decimal values are parsed incorrectlyPrices arrive as JSON strings. Keep [JsonConverter(typeof(DecimalStringConverter))] on every price field. The sample parses with CultureInfo.InvariantCulture, so the server's locale cannot change how the decimal strings are read.

Going further

  • Check IsStale and display ComputedAt alongside the silver price
  • Handle missing Bid and Ask values when your plan does not include them
  • Add a conversion request for silver in another currency or unit using the API reference
  • Track cache hits, request failures, and rate limits to understand your app's quota use

Questions

How fresh are the silver prices?

Free and keyless silver prices are delayed by 15 minutes. Paid plans provide live prices. The example's 60 second cache controls when your app requests another response. Check is_stale and computed_at before displaying a result.

Will automatic refresh fit the free tier quota?

Free includes 5,000 calls a month and 10 requests a minute. Each request that reaches the API uses quota. Reuse the client, cache results, and fetch on demand. A local cache does not coordinate requests from separate processes.

Can I get silver prices in euros?

Yes. Use /v1/convert?from=XAG&to=EUR&amount=1&unit=gram to get silver in euros per gram. Silver spot symbols exist only in US dollars. Conversion also supports oz and kg. Without a key, prices are delayed by 15 minutes.

Why use a custom JsonConverter for silver prices?

The API returns price strings, while the client needs decimal values for calculations. DecimalStringConverter handles that conversion without first parsing through double. The converter parses with invariant culture, so decimal places are read the same on every server locale.

Can a web app reuse this client?

Yes. Reusing a client preserves its cache across requests. The ConcurrentDictionary supports concurrent access, but simultaneous cache misses can still send duplicate requests. Manage the underlying HttpClient lifetime using the linked Microsoft guidelines when adapting this console example.

Which other metals can this client request?

Use XAU-USD-SPOT for gold and HG-USD-SPOT for copper with the same SpotAsync() method. Silver and gold quotes are in US dollars per troy ounce. Copper is in US dollars per pound, so label the unit with each result.

Can Claude help me build the silver client?

Yes. Connect Claude to the goldprice.dev MCP server at https://api.goldprice.dev/v1/mcp/ without a key, or use npx @nusantara-ventures/goldprice-mcp with a key. Its get_spot_price tool supports silver. Ask Claude to build the client, then review its parsing, cache, and error handling.

Keep reading

Start with a free API key

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

Get a free key