> ## Documentation Index
> Fetch the complete documentation index at: https://docs.dncscrub.com/llms.txt
> Use this file to discover all available pages before exploring further.

# C# Examples

> Production-ready C# examples for integrating with DNCScrub APIs

# C# Code Examples

Production-ready C# examples for integrating with DNCScrub APIs.

## Prerequisites

* .NET 7 or later (the typed `ScrubResult` uses `DateOnly`, which `System.Text.Json` supports natively from .NET 7; on .NET 6 change those fields to `string?` or add a converter)
* No third-party packages required — all examples use built-in `System.Text.Json` and `System.Net.Http.Json`

<Note>
  These examples use [top-level statements](https://learn.microsoft.com/en-us/dotnet/csharp/fundamentals/program-structure/top-level-statements), available in C# 9+ / .NET 6+.
  Wrap the code in a `Main` method if you're targeting an older project style.
</Note>

## Scrub API — GET

Best for quick lookups of up to 50 phone numbers.

```csharp theme={null}
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 scrub = await client.GetFromJsonAsync<ScrubResponse>(url);

foreach (var result in scrub!.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 ScrubResponse(int Version, ScrubResult[] Results);

record ScrubResult(
    string Phone,
    string ResultCode,
    string? Reserved,
    string Reason,
    string RegionAbbrev,
    string Country,
    string Locale,
    string CarrierInfo,
    string? NewReassignedAreaCode,
    int? TZCode,
    string? CallingWindow,
    int? UTCOffset,
    bool DoNotCallToday,
    int? CallingTimeRestrictions,
    string? EBRType,
    bool IsWirelessOrVoIP,
    string LineType,
    DateOnly? EBRExpiresOn,
    DateOnly? WirelessPortDate,
    DateOnly? VoIPDate,
    string? PostalCode,
    string TZSource,
    bool IsCallAllowedNonATDS,
    bool IsCallAllowedATDS,
    bool IsCallAllowedAI
);
```

<Tip>
  See the [Output Guide](/api-reference/scrub/output-guide) for a full reference of result codes and response fields.
</Tip>

## Scrub API — POST

Use POST for batches larger than 50 phone numbers.

```csharp theme={null}
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"] = "8",
    ["output"] = "json"
};

var response = await client.PostAsync(
    "https://www.dncscrub.com/app/main/rpc/scrub",
    new FormUrlEncodedContent(formData)
);

response.EnsureSuccessStatusCode();
var scrub = await response.Content.ReadFromJsonAsync<ScrubResponse>();

foreach (var result in scrub!.Results)
{
    Console.WriteLine($"{result.Phone}: {result.ResultCode} — {result.LineType} — {result.Locale}, {result.RegionAbbrev}");
}

record ScrubResponse(int Version, ScrubResult[] Results);

record ScrubResult(
    string Phone,
    string ResultCode,
    string? Reserved,
    string Reason,
    string RegionAbbrev,
    string Country,
    string Locale,
    string CarrierInfo,
    string? NewReassignedAreaCode,
    int? TZCode,
    string? CallingWindow,
    int? UTCOffset,
    bool DoNotCallToday,
    int? CallingTimeRestrictions,
    string? EBRType,
    bool IsWirelessOrVoIP,
    string LineType,
    DateOnly? EBRExpiresOn,
    DateOnly? WirelessPortDate,
    DateOnly? VoIPDate,
    string? PostalCode,
    string TZSource,
    bool IsCallAllowedNonATDS,
    bool IsCallAllowedATDS,
    bool 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.

```csharp theme={null}
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.

```csharp theme={null}
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.

```csharp theme={null}
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.

```csharp theme={null}
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();
        var scrub = await response.Content.ReadFromJsonAsync<ScrubResponse>();
        return scrub?.Results ?? [];
    }

    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 ScrubResponse(int Version, ScrubResult[] Results);

record ScrubResult(
    string Phone,
    string ResultCode,
    string? Reserved,
    string Reason,
    string RegionAbbrev,
    string Country,
    string Locale,
    string CarrierInfo,
    string? NewReassignedAreaCode,
    int? TZCode,
    string? CallingWindow,
    int? UTCOffset,
    bool DoNotCallToday,
    int? CallingTimeRestrictions,
    string? EBRType,
    bool IsWirelessOrVoIP,
    string LineType,
    DateOnly? EBRExpiresOn,
    DateOnly? WirelessPortDate,
    DateOnly? VoIPDate,
    string? PostalCode,
    string TZSource,
    bool IsCallAllowedNonATDS,
    bool IsCallAllowedATDS,
    bool 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);
```

**Usage:**

```csharp theme={null}
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}");
```


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.