Integration guide
Add currency exchange rates and conversion to C# and .NET 8
Use HttpClient, System.Text.Json, and IMemoryCache. Cache the latest response to its nextUpdateAt and keep credentials in server configuration.
1. Get a free API key
Sign up at https://currencyexchangerate-api.com/auth/login, then create a key under API keys in the console. The free plan includes 3,000 requests per month with no credit card. Store the secret as CXR_API_KEY in server-side environment configuration; never expose it in browser code.
.env
shellCXR_API_KEY=cxr_your_secret_key2. Create a reusable client and cache rates
Use the standard HTTP client. Cache every /latest response until nextUpdateAt: rates change at most once by then, and reusing the response saves quota. The helper also exposes /convert.
RatesClient.cs
C#using System.Globalization;using System.Net.Http.Headers;using System.Net.Http.Json;using Microsoft.Extensions.Caching.Memory; public record Latest( string Base, DateTimeOffset UpdatedAt, DateTimeOffset NextUpdateAt, Dictionary<string, decimal> Rates); public record Conversion( string From, string To, decimal Amount, decimal Rate, decimal Result, DateTimeOffset UpdatedAt); public sealed class RatesClient( HttpClient http, IMemoryCache cache, IConfiguration config){ const string Api = "https://api.currencyexchangerate-api.com/api/v1"; async Task<T> Get<T>(string path) { using var req = new HttpRequestMessage(HttpMethod.Get, Api + path); req.Headers.Authorization = new AuthenticationHeaderValue("Bearer", config["CXR_API_KEY"]); using var res = await http.SendAsync(req); if (!res.IsSuccessStatusCode) { var retryAfter = res.Headers.RetryAfter?.Delta?.TotalSeconds; throw new HttpRequestException( "API status " + (int)res.StatusCode + "; Retry-After " + retryAfter); } return (await res.Content.ReadFromJsonAsync<T>())!; } public async Task<Latest> GetLatest() { if (cache.TryGetValue("latest", out Latest? saved)) { return saved!; } var data = await Get<Latest>("/latest?base=USD&symbols=EUR,GBP"); cache.Set("latest", data, data.NextUpdateAt); return data; } public Task<Conversion> Convert(string from, string to, decimal amount) { var query = "from=" + Uri.EscapeDataString(from) + "&to=" + Uri.EscapeDataString(to) + "&amount=" + amount.ToString(CultureInfo.InvariantCulture); return Get<Conversion>("/convert?" + query); }}3. Use it in C# and .NET 8
Call the helper from a server route, controller, view, command, or script. Format converted values for the user’s locale.
Program.cs
C#using System.Globalization; var builder = WebApplication.CreateBuilder(args);builder.Services.AddMemoryCache();builder.Services.AddHttpClient<RatesClient>();var app = builder.Build(); app.MapGet("/convert", async (RatesClient rates) =>{ var result = await rates.Convert("EUR", "GBP", 100); var culture = CultureInfo.GetCultureInfo("en-GB"); return new { result, formatted = result.Result.ToString("C", culture) };}); app.Run();4. Handle API errors
A 401 means the key is invalid. A 429 can mean a rate limit or quota limit; read Retry-After in seconds before retrying. Other errors use application/problem+json.
Errors.cs
C#try{ var result = await rates.Convert("EUR", "GBP", 100);}catch (HttpRequestException e){ // e.g. "API status 429; Retry-After 30" Console.Error.WriteLine(e.Message);}5. Format the amount for display
Use locale-aware currency formatting instead of adding a symbol manually.
Format.cs
C#using System.Globalization; var culture = CultureInfo.GetCultureInfo("de-DE");Console.WriteLine(85.249105m.ToString("C", culture));