# 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.

## 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.

File: `.env`

```shell
CXR_API_KEY=cxr_your_secret_key
```

## 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.

File: `RatesClient.cs`

```csharp
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);
    }
}
```

## 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.

File: `Program.cs`

```csharp
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();
```

## 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.

File: `Errors.cs`

```csharp
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);
}
```

## Format the amount for display

Use locale-aware currency formatting instead of adding a symbol manually.

File: `Format.cs`

```csharp
using System.Globalization;

var culture = CultureInfo.GetCultureInfo("de-DE");
Console.WriteLine(85.249105m.ToString("C", culture));
```

## Related links

- [API documentation](https://currencyexchangerate-api.com/docs.md)
- [All integration guides](https://currencyexchangerate-api.com/guides.md)
- [Get a free API key](https://currencyexchangerate-api.com/auth/login)
