C# Code Examples
Production-ready C# examples for integrating with DNCScrub APIs.Prerequisites
- .NET 6 or later
- No third-party packages required — all examples use built-in
System.Text.JsonandSystem.Net.Http.Json
These examples use top-level statements, available in C# 9+ / .NET 6+.
Wrap the code in a
Main method if you’re targeting an older project style.Scrub API — GET
Best for quick lookups of up to 50 phone numbers.using System.Net.Http.Json;
using var client = new HttpClient();
client.DefaultRequestHeaders.Add("loginId", "YOUR_API_KEY");
var phoneNumbers = "5039367187,7075276405";
var url = $"https://www.dncscrub.com/app/main/rpc/scrub?phoneList={phoneNumbers}&version=8&output=json";
var results = await client.GetFromJsonAsync<ScrubResult[]>(url);
foreach (var result in results!)
{
var callable = result.ResultCode switch
{
"C" or "E" or "O" or "X" => true, // Clean, EBR, or exemption
"W" or "G" or "H" or "Y" => true, // Wireless/VoIP — OK but may need TCPA consent
"D" or "P" or "B" or "I" or "M" => false, // DNC, blocked, or invalid
"L" or "F" or "V" => false, // Wireless-prohibited state
_ => false
};
Console.WriteLine($"{result.Phone}: {result.ResultCode} — {(callable ? "Callable" : "Do Not Call")} ({result.Locale}, {result.RegionAbbrev})");
}
record ScrubResult(
string Phone,
string ResultCode,
string Reason,
string RegionAbbrev,
string Country,
string Locale,
string LineType,
string IsWirelessOrVoIP,
string CallingWindow,
string UTCOffset,
string PostalCode,
string TZSource,
string IsCallAllowedNonATDS,
string IsCallAllowedATDS,
string IsCallAllowedAI
);
See the Output Guide for a full reference of result codes and response fields.
Scrub API — POST
Use POST for batches larger than 50 phone numbers.using System.Net.Http.Json;
using var client = new HttpClient();
client.DefaultRequestHeaders.Add("loginId", "YOUR_API_KEY");
var formData = new Dictionary<string, string>
{
["phoneList"] = "5039367187,7075276405,7072842774",
["version"] = "5",
["output"] = "json"
};
var response = await client.PostAsync(
"https://www.dncscrub.com/app/main/rpc/scrub",
new FormUrlEncodedContent(formData)
);
response.EnsureSuccessStatusCode();
var results = await response.Content.ReadFromJsonAsync<ScrubResult[]>();
foreach (var result in results!)
{
Console.WriteLine($"{result.Phone}: {result.ResultCode} — {result.LineType} — {result.Locale}, {result.RegionAbbrev}");
}
record ScrubResult(
string Phone,
string ResultCode,
string Reason,
string RegionAbbrev,
string Country,
string Locale,
string LineType,
string IsWirelessOrVoIP,
string CallingWindow,
string UTCOffset,
string PostalCode,
string TZSource,
string IsCallAllowedNonATDS,
string IsCallAllowedATDS,
string IsCallAllowedAI
);
TCPA Authority — Reassigned Number Check
Check whether a phone number has been reassigned to a new owner since consent was given. This uses carrier-level data for high accuracy.using System.Net.Http.Json;
using var client = new HttpClient();
client.DefaultRequestHeaders.Add("loginId", "YOUR_API_KEY");
var phoneNumber = "7075276405";
var consentDate = "20210209"; // YYYYMMDD format
var url = $"https://dataapi.dncscrub.com/v1.5/Data/TCPAAuthority?phoneNumber={phoneNumber}&date={consentDate}";
var result = await client.GetFromJsonAsync<TcpaAuthorityResult>(url);
var status = result!.IsReassigned switch
{
true => "REASSIGNED — Do not call (consent no longer valid)",
false => "Not reassigned — Safe to call",
null => "Unable to determine — Insufficient data"
};
Console.WriteLine($"{result.PhoneNumber}: {status}");
Console.WriteLine($" Carrier: {result.Carrier}");
Console.WriteLine($" Line type: {result.LineType}");
Console.WriteLine($" Location: {result.Locale}, {result.Region}");
record TcpaAuthorityResult(
string PhoneNumber,
bool? IsReassigned,
bool IsValid,
string LineType,
string Carrier,
string Locale,
string Region,
string Country,
string TZ,
string UTCOffset
);
Litigator Check
Check whether phone numbers belong to known TCPA litigators.using System.Net.Http.Json;
using var client = new HttpClient();
client.DefaultRequestHeaders.Add("loginId", "YOUR_API_KEY");
var url = "https://dataapi.dncscrub.com/v1.5/Scrub/litigator?phoneList=5039367187,7075276405";
var results = await client.GetFromJsonAsync<LitigatorResult[]>(url);
foreach (var result in results!)
{
if (result.IsLitigator)
Console.WriteLine($"{result.Phone}: LITIGATOR — Do not call");
else
Console.WriteLine($"{result.Phone}: Not a known litigator");
}
record LitigatorResult(long Phone, bool IsLitigator);
Internal DNC — Add / Remove
Add phone numbers to your organization’s private Internal Do Not Call list (also called Project DNC). Numbers on this list are automatically blocked during scrubs.using var client = new HttpClient();
client.DefaultRequestHeaders.Add("loginId", "YOUR_API_KEY");
// Add a number to your Internal DNC list
var response = await client.GetAsync(
"https://www.dncscrub.com/app/main/rpc/pdnc?phoneList=5039367187&actionType=add"
);
if (response.IsSuccessStatusCode)
Console.WriteLine("Number added to Internal DNC");
else
Console.WriteLine($"Failed: {response.StatusCode}");
// Remove a number from your Internal DNC list
await client.GetAsync(
"https://www.dncscrub.com/app/main/rpc/pdnc?phoneList=5039367187&actionType=remove"
);
Production Client with Error Handling
A reusable client class suitable for production use. Handles authentication errors, rate limiting, timeouts, and proper resource cleanup.using System.Net;
using System.Net.Http.Json;
class DncScrubClient : IDisposable
{
private readonly HttpClient _http;
public DncScrubClient(string apiKey)
{
_http = new HttpClient { Timeout = TimeSpan.FromSeconds(30) };
_http.DefaultRequestHeaders.Add("loginId", apiKey);
}
public async Task<ScrubResult[]> ScrubAsync(params string[] phoneNumbers)
{
var phoneList = string.Join(",", phoneNumbers);
var url = $"https://www.dncscrub.com/app/main/rpc/scrub?phoneList={phoneList}&version=8&output=json";
var response = await _http.GetAsync(url);
if (response.StatusCode == HttpStatusCode.Unauthorized)
throw new InvalidOperationException("Invalid API key.");
if ((int)response.StatusCode == 429)
throw new InvalidOperationException("Rate limit exceeded. Slow down requests.");
response.EnsureSuccessStatusCode();
return await response.Content.ReadFromJsonAsync<ScrubResult[]>() ?? [];
}
public async Task<TcpaAuthorityResult?> CheckReassignedAsync(string phoneNumber, string consentDate)
{
var url = $"https://dataapi.dncscrub.com/v1.5/Data/TCPAAuthority?phoneNumber={phoneNumber}&date={consentDate}";
return await _http.GetFromJsonAsync<TcpaAuthorityResult>(url);
}
public async Task<LitigatorResult[]> CheckLitigatorsAsync(params string[] phoneNumbers)
{
var phoneList = string.Join(",", phoneNumbers);
var url = $"https://dataapi.dncscrub.com/v1.5/Scrub/litigator?phoneList={phoneList}";
return await _http.GetFromJsonAsync<LitigatorResult[]>(url) ?? [];
}
public void Dispose() => _http.Dispose();
}
record ScrubResult(
string Phone, string ResultCode, string Reason,
string RegionAbbrev, string Country, string Locale,
string LineType, string IsWirelessOrVoIP,
string CallingWindow, string UTCOffset,
string PostalCode, string TZSource,
string IsCallAllowedNonATDS, string IsCallAllowedATDS, string IsCallAllowedAI
);
record TcpaAuthorityResult(
string PhoneNumber, bool? IsReassigned, bool IsValid,
string LineType, string Carrier, string Locale,
string Region, string Country, string TZ, string UTCOffset
);
record LitigatorResult(long Phone, bool IsLitigator);
using var client = new DncScrubClient("YOUR_API_KEY");
// Scrub
var scrubResults = await client.ScrubAsync("5039367187", "7075276405");
foreach (var r in scrubResults)
Console.WriteLine($"{r.Phone}: {r.ResultCode}");
// Check reassigned
var tcpa = await client.CheckReassignedAsync("7075276405", "20210209");
Console.WriteLine($"Reassigned: {tcpa?.IsReassigned}");
// Check litigators
var litigators = await client.CheckLitigatorsAsync("5039367187");
Console.WriteLine($"Litigator: {litigators[0].IsLitigator}");