C# / .NET · Email breach checks
Check email breaches in C# with HttpClient
The C# example posts an anonymous object to /v1/breaches/email with PostAsJsonAsync and deserializes the result into immutable records. Finowl returns breach fields in PascalCase, so a record declared as Breach(string Title, DateOnly BreachDate, string[] DataClasses, bool IsVerified) binds without attributes, and DateOnly gives you a real date instead of a string. Iterating result.Breaches then prints each breach and the categories of data it exposed.
A switch on response.StatusCode covers the cases that matter: 400 for an address that fails validation, 401 for a missing or wrong key, and 429, where the program reads the error code to tell a temporary rate limit from an exhausted credit balance. Rate limits trigger an await on the RetryAfter delta and another attempt. Anything else stops without retrying, because a 5xx lookup may already have run.
Steps
- 1
Create a console project with dotnet new console and replace Program.cs with the example.
- 2
Set FINOWL_API_KEY in your shell, or in launchSettings.json for local debugging only.
- 3
Run dotnet run -- someone@example.com to look up an address.
- 4
Read DataClasses on each Breach record to decide how strongly to warn the user.
- 5
Move the call into an injected FinowlClient when you wire it into ASP.NET Core.
dotnet new console -n FinowlQuickstart
cd FinowlQuickstartusing System.Net;
using System.Net.Http.Headers;
using System.Net.Http.Json;
var apiKey = Environment.GetEnvironmentVariable("FINOWL_API_KEY")
?? throw new InvalidOperationException("Set FINOWL_API_KEY first.");
using var http = new HttpClient
{
BaseAddress = new Uri("https://api.finowl.co"),
Timeout = TimeSpan.FromSeconds(15),
};
http.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", apiKey);
var email = args.Length > 0 ? args[0] : "alex@example.com";
for (var attempt = 1; attempt <= 3; attempt++)
{
using var response = await http.PostAsJsonAsync("/v1/breaches/email", new { email });
switch (response.StatusCode)
{
case HttpStatusCode.OK:
var result = await response.Content.ReadFromJsonAsync<EmailBreachResult>();
if (result is null || !result.Breached)
{
Console.WriteLine($"No known breaches for {email}.");
return;
}
foreach (var breach in result.Breaches)
{
var flag = breach.IsVerified ? "" : " (unverified)";
Console.WriteLine($"{breach.Title}, {breach.BreachDate:yyyy-MM-dd}{flag}");
Console.WriteLine($" exposed: {string.Join(", ", breach.DataClasses)}");
}
return;
case HttpStatusCode.BadRequest:
Console.Error.WriteLine("Finowl rejected the address as invalid_input.");
return;
case HttpStatusCode.Unauthorized:
Console.Error.WriteLine("FINOWL_API_KEY is missing or invalid.");
return;
case HttpStatusCode.TooManyRequests:
var error = await response.Content.ReadFromJsonAsync<ErrorEnvelope>();
if (error?.Error.Code == "quota_exceeded")
{
Console.Error.WriteLine("Out of Finowl credits.");
return;
}
var wait = response.Headers.RetryAfter?.Delta ?? TimeSpan.FromSeconds(5);
await Task.Delay(wait);
break;
default:
Console.Error.WriteLine($"Finowl returned {(int)response.StatusCode}; not retrying.");
return;
}
}
record Breach(string Title, DateOnly BreachDate, string[] DataClasses, bool IsVerified);
record EmailBreachResult(string Email, bool Breached, Breach[] Breaches);
record ErrorEnvelope(ErrorDetail Error);
record ErrorDetail(string Code);IN PRODUCTION
Production tips
In ASP.NET Core, run breach lookups from a BackgroundService fed by a Channel<T> rather than inside the registration endpoint, so the response to the user never waits on an external call.
Keep the API key in user secrets during development and in your host's secret store in production, exposed to the app as the FINOWL_API_KEY environment variable rather than in appsettings.json.
Cache results per normalized address with IMemoryCache or a distributed cache. Checking the same inbox on every login wastes credits and rarely changes the answer from one day to the next.
Each lookup costs 1 credit, with 100 free credits every month. See pricing and error codes.
A FEW GOOD QUESTIONS
Common questions
Related guides
- Check breached passwords in C# and .NET 8
- Predict gender from names in C# with .NET 8
- Check email breaches in Python with requests
- Check email breaches in Node.js with fetch
- Check email breaches in TypeScript with typed results
- Check email breaches in Go with net/http
- Email breach checks for fintech signups and logins
- Email breach checks for online stores and shopper logins
- Email breach checks for SaaS logins and admins
Check email breaches in C# with HttpClient
Grab an API key, paste the example and run it. 100 free credits every month.