# API Concepts
Source: https://docs.dncscrub.com/api-reference/api-concepts
Before you start integrating with the CCC API, it's important to understand these key concepts.
## Projects and Campaigns
Your DNCScrub account is organized into a hierarchy of **Projects** and **Campaigns**. This structure allows you to organize your account into meaningful units so you can apply different compliance settings to each one as well as have reporting on each one. For example, you might create separate projects for Customer Service, Lead Generation, or Winbacks. You can also organize projects based on the type of scrub you wish to perform, such as having projects for Full Scrub, Litigator Only, or Wireless Only.
Using Projects and Campaigns is **optional** — if you choose not to use them, all scrubs are processed under the **Master Project** and **Default Campaign**.
| Parameter | Description |
| ------------ | ------------------------------------------------------------------------- |
| `projId` | Optional. Specifies the project in which the action should be performed. |
| `campaignId` | Optional. Specifies the campaign in which the action should be performed. |
## TLS Requirement
All API calls must be made with **TLS 1.2 or above**. Requests using older TLS
versions will be denied.
```csharp theme={null}
// C# - If not using modern clients, ensure TLS 1.2 is used
System.Net.ServicePointManager.SecurityProtocol = System.Net.SecurityProtocolType.Tls12;
```
## Atomic Operations
All operations are atomic by default, meaning that either all parts of a request complete successfully or none of them do. The default behavior can be overridden by passing the parameter `ignoreInvalid=1` to the API call.
For example, if you attempt to add multiple phone numbers to your Internal DNC
database and one phone number is invalid (e.g., "AAA" instead of a 10-digit
number), the **entire request will fail** and no numbers will be added. This
is why it's important to pass clean, well-structured data to the API.
### Best Practices for Atomic Operations
* Pass clean data to the API. Ensure all phone numbers are exactly 10 digits.
* Handle error responses appropriately in your code
* Consider batching requests to isolate potential failures
## Phone Number Format
All phone numbers must be:
* **10 digits** (no country code)
* **Numeric only** (no dashes, spaces, or special characters)
| Valid | Invalid |
| ------------ | ---------------- |
| `5039367187` | `503-936-7187` |
| `7075276405` | `1-707-527-6405` |
Each number in `phoneList` may carry two optional pipe-delimited fields:
`PHONE|ID|POSTALCODE`. `ID` is echoed back in `Reserved`; `POSTALCODE` (US ZIP
or Canadian postal code) makes the time zone and calling window follow the
contact's location instead of the area code. See [Unique
Identifiers](/api-reference/scrub/unique-identifier) and [Postal Code Time
Zones](/api-reference/scrub/scrub-single#postal-code-time-zones).
## Response Formats
### JSON Output
For the Full Scrub APIs, request JSON by adding `output=json` to your request:
```json theme={null}
[
{
"Phone": "7075276405",
"ResultCode": "D",
"Reason": "National (USA) 2003-06-01;;;",
"RegionAbbrev": "CA",
"Country": "US",
"Locale": "Santa Rosa",
"CarrierInfo": "9740;RBOC;\"AT&T California:AT&T California\"",
"LineType": "AllOther"
}
]
```
### CSV Output
For legacy reasons CSV is the default output format, or request it explicitly with \`output=csv':
```
7075276405,D,,National (USA) 2003-06-01;;;,CA,US,Santa Rosa,...
```
## HTTP Methods
| Method | When to Use |
| ------ | ----------------------------------------- |
| `GET` | For processing 10 or fewer phone numbers |
| `POST` | For processing more than 10 phone numbers |
If you will process more than 10 phone numbers, you **must** use HTTP POST
instead of HTTP GET. If you don't know how many phone numbers you will
process, use HTTP POST to be safe. we very large batches, consider automating
with
## Error Handling
Successful requests return HTTP status code `200`. Failed requests return `4xx` status codes with an error message in the response body. `502` can occur under heavy load and the recommendation is to retry these requests with exponential backoff.
| Status Code | Meaning |
| ----------- | ---------------------------------------------------------------------------- |
| `200` | Success |
| `400` | Bad Request - Invalid parameters |
| `401` | Unauthorized - Invalid or missing API key |
| `429` | Too Many Requests - Rate limit exceeded |
| `502` | Bad Gateway - Server overload or maintenance. Retry with exponential backoff |
# API Authentication
Source: https://docs.dncscrub.com/api-reference/authentication
CCC APIs support two authentication methods:
1. **API Key**: Passed in the request headers for every call. The API key is also referred to Was the LoginId.
2. **OAuth 2.0** Available for systems that require token-based authorization flows.
## API Key Authentication
In the DNCScrub portal, navigate to **User Admin**. Create a new user that will be used for API access.
* Give the user a distinct full name like "API User - Do Not Delete" so it won't be accidentally removed
* The recommended username is `apiuser` (though any username works)
* Set the user role to **Administrator**
After creating the user, click the **"Get API Key"** button. The API Key will be displayed in the "API Key" field and can be copied to your clipboard.
Save your API Key securely. You'll need it for all API calls.
## Using Your API Key
Include the API key in the HTTP header of every request:
| Header Key | Value |
| ---------- | ------------ |
| `loginId` | Your API Key |
### Example with cURL
```bash theme={null}
curl --location --request GET \
'https://www.dncscrub.com/app/main/rpc/scrub?phoneList=7075276405&version=8&output=json' \
--header 'loginId: YOUR_API_KEY_HERE'
```
### Example with JavaScript
```javascript theme={null}
fetch(
"https://www.dncscrub.com/app/main/rpc/scrub?phoneList=7075276405&version=8&output=json",
{
method: "GET",
headers: {
loginId: "YOUR_API_KEY_HERE",
},
}
);
```
### Example with C\#
```csharp theme={null}
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Add("loginId", "YOUR_API_KEY_HERE");
var response = await client.GetStringAsync(
"https://www.dncscrub.com/app/main/rpc/scrub?phoneList=7075276405&version=8&output=json"
);
}
```
Keep your API key secure and never expose it in client-side code or public
repositories.
## OAuth 2.0 Authentication
For enhanced security, CCC APIs support OAuth 2.0 authentication in addition to API key authentication.
Try the OAuth token endpoint directly in the API playground.
### OAuth Flow
```mermaid theme={null}
sequenceDiagram
autonumber
participant Client as Client System
participant OAuth as CCC OAuth Token Endpoint
(/v1.5/OAuth/token)
participant API as CCC Service API Endpoint
(Scrub API, IDNC API, etc.)
Client->>OAuth: Request token (client_secret as credentials)
OAuth-->>Client: Returns token (expires_in 86400s / 24 hours)
Client->>API: Call DNCScrub Service APIs
with Token in Authorization header
API-->>Client: DNCScrub API Response
```
Contact support to receive your OAuth client credentials.
Exchange credentials for an access token.
Include the access token in API requests.
Request a new token before it expires. Tokens are valid for 24 hours (`expires_in` is 86400 seconds). Always honor the `expires_in` value from the response rather than hard-coding a lifetime.
### Token Request
```bash theme={null}
curl --location --request POST 'https://dataapi.dncscrub.com/v1.5/OAuth/token' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'grant_type=client_credentials' \
--data-urlencode 'client_id=YOUR_ACCOUNT_ID' \
--data-urlencode 'client_secret=YOUR_CLIENT_SECRET'
```
#### Request Parameters
| Parameter | Condition | Description |
| --------------- | --------- | ---------------------------------------------- |
| `client_id` | Required | Your Account Id such as DEMO |
| `client_secret` | Required | An API Key generated from DNCScrub.com portal. |
| `grant_type` | Required | Must be set to `client_credentials` |
The token endpoint is versioned like every other Data API endpoint; `v1.1` through `v1.5` all work. The unversioned path `/oauth/token` does not exist.
#### Token Response
```json theme={null}
{
"token_type": "Bearer",
"expires_in": 86400,
"access_token": "YOUR_ACCESS_TOKEN"
}
```
### Using the Access Token
```bash theme={null}
curl --location --request GET 'https://www.dncscrub.com/app/main/rpc/scrub?phoneList=7075276405&version=8' \
--header 'Authorization: Bearer YOUR_ACCESS_TOKEN'
```
# Wireless ID Premium
Source: https://docs.dncscrub.com/api-reference/data/id-premium
GET https://dataapi.dncscrub.com/v1.4/Data/IDPremium
Premium phone identification including carrier and phone type information.
Returns the current telco carrier of a phone number. This is the most accurate carrier data that exists. It differs from the carrier data returned by a scrub in that data is the carrier originally assigned to a phone number and is doing a live dip into the telco systems.
## Request
### Headers
Your API Key (LoginId from your DNCScrub account)
### Query Parameters
10-digit phone number to look up
## Output parameters
| Field | Description |
| ----------- | ----------------------------------------------------------- |
| `Phone` | Ten digit phone number that was queried. Example 5039367188 |
| `PhoneType` | 1 character code identifying the phone type |
| `OCN` | Operating Company Number, 4 character alpha numeric |
| `TelcoName` | Name of telephone company provider, 50 character max. |
| `ODate` | Out Date, date stamp of last live lookup, YYYYMMDD format |
### PhoneType values
| Value | Description |
| ----- | ------------- |
| `N` | Not available |
| `L` | Land Line |
| `V` | VoIP |
| `W` | Wireless |
| `O` | Other |
## Example Request
```bash cURL theme={null}
curl --location --request GET \
'https://dataapi.dncscrub.com/v1.4/Data/IDPremium
?phone=5039367187' \
--header 'loginId: YOUR_API_KEY'
```
```javascript JavaScript theme={null}
const response = await fetch(
'https://dataapi.dncscrub.com/v1.4/Data/IDPremium?phone=5039367187',
{
method: 'GET',
headers: {
'loginId': 'YOUR_API_KEY'
}
}
);
const data = await response.json();
console.log(data);
```
```csharp C# theme={null}
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Add("loginId", "YOUR_API_KEY");
var response = await client.GetAsync(
"https://dataapi.dncscrub.com/v1.4/Data/IDPremium?phone=5039367187"
);
var result = await response.Content.ReadAsStringAsync();
Console.WriteLine(result);
}
```
```json Response theme={null}
{
"Phone": "2548787052",
"PhoneType": "W",
"OCN": "6529",
"TelcoName": "T-MOBILE USA, INC.",
"ODate": "20260204"
}
```
# Data APIs Overview
Source: https://docs.dncscrub.com/api-reference/data/overview
Phone data enrichment, verification, and intelligence services
The Data APIs provide comprehensive phone number intelligence, including carrier information, line type detection, and identity verification services.
## Available Endpoints
Append phone number information based on name and address data.
Determines whether a phone number is associated with a residential or business line.
Verifies phone number ownership by matching against name and address data.
Premium phone identification including carrier and phone type information.
Check real-time phone line status to determine if a number is connected or
disconnected.
Retrieves usage statistics for verification or residential/business lookups within a date range.
## Authentication
All Data API endpoints require authentication via the `loginId` header. See [Authentication](/api-reference/authentication) for details.
## Base URL
```
https://dataapi.dncscrub.com/v1.5/Data/
```
# Real-Time Disconnect
Source: https://docs.dncscrub.com/api-reference/data/real-time-disconnect
GET https://dataapi.dncscrub.com/v1.4/Data/RealTimeDisconnect
Check real-time phone line status to determine if a number is connected or disconnected.
## Request
### Headers
Your API Key (LoginId from your DNCScrub account)
### Query Parameters
10-digit phone number to check
## Output parameters
| Field | Description |
| ----------- | ------------------------------------------------------------------------------------------- |
| `Phone` | Ten digit phone number that was queried. Example 5039367188 |
| `Status` | See Status Table below |
| `ErrorText` | Descriptive message of exceptional circumstance. This field is populated if Status is Error |
### Status Table
| Status | Description |
| ------------------- | ----------------------------------------- |
| `connected` | Typically connected |
| `connected-75` | Connected 75% of the time |
| `pending` | Not completed yet |
| `disconnected` | Typically disconnected |
| `disconnected-70` | Disconnected 70% of the time |
| `busy` | Busy |
| `unreachable` | Not reachable |
| `invalid phone` | Phone not valid |
| `restricted` | Can't be dialed |
| `invalid-format` | Phone or zip are not in a valid format |
| `invalid-phone` | Phone number is not valid |
| `bad-zip-code` | Zip code is not valid |
| `serverunavailable` | \ contact support |
| `ERROR` | See ErrorText parameter for error message |
## Example Request
```bash cURL theme={null}
curl --location --request GET \
'https://dataapi.dncscrub.com/v1.4/Data/RealTimeDisconnect
?phoneNumber=5039365190' \
--header 'loginId: YOUR_API_KEY'
```
```javascript JavaScript theme={null}
const response = await fetch(
'https://dataapi.dncscrub.com/v1.4/Data/RealTimeDisconnect?phoneNumber=5039365190',
{
method: 'GET',
headers: {
'loginId': 'YOUR_API_KEY'
}
}
);
const data = await response.json();
console.log(data);
```
```csharp C# theme={null}
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Add("loginId", "YOUR_API_KEY");
var response = await client.GetAsync(
"https://dataapi.dncscrub.com/v1.4/Data/RealTimeDisconnect?phoneNumber=5039365190"
);
var result = await response.Content.ReadAsStringAsync();
Console.WriteLine(result);
}
```
```json Response theme={null}
{
"Phone": "5039365190",
"Status": "connected",
"ErrorText": ""
}
```
# Business Verify ID
Source: https://docs.dncscrub.com/api-reference/data/res-or-business
GET https://dataapi.dncscrub.com/v1.4/Data/ResOrBusiness
Determines whether a phone number is associated with a residential or business line.
## Request
### Headers
Your API Key (LoginId from your DNCScrub account)
### Query Parameters
10-digit phone number to check
## Output parameters
| Field | Description |
| --------------- | ----------------------------------------------------------- |
| `Phone` | Ten digit phone number that was queried. Example 5039367188 |
| `ResOrBusiness` | One character code indicating status |
### ResOrBusiness values
| Value | Description |
| ----- | ------------------------------------------------------- |
| `R` | Residential |
| `B` | Business |
| `U` | Unknown. The record type was not able to be determined. |
## Example Request
```bash cURL theme={null}
curl --location --request GET \
'https://dataapi.dncscrub.com/v1.4/Data/ResOrBusiness
?phone=7072842774' \
--header 'loginId: YOUR_API_KEY'
```
```javascript JavaScript theme={null}
const response = await fetch(
'https://dataapi.dncscrub.com/v1.4/Data/ResOrBusiness?phone=7072842774',
{
method: 'GET',
headers: {
'loginId': 'YOUR_API_KEY'
}
}
);
const data = await response.json();
console.log(data);
```
```csharp C# theme={null}
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Add("loginId", "YOUR_API_KEY");
var response = await client.GetAsync(
"https://dataapi.dncscrub.com/v1.4/Data/ResOrBusiness?phone=7072842774"
);
var result = await response.Content.ReadAsStringAsync();
Console.WriteLine(result);
}
```
```json Response theme={null}
{
"Phone": "7072842774",
"ResOrBusiness": "B"
}
```
# Reverse Phone ID Append
Source: https://docs.dncscrub.com/api-reference/data/reverse-phone-id-append
GET https://dataapi.dncscrub.com/v1.4/Data/PhoneIDAppend
Appends phone number information based on name and address data
## Request
### Headers
Your API Key (LoginId from your DNCScrub account)
### Query Parameters
First name
Last name
Street address
City name
State abbreviation
ZIP code
## Output parameters
| Field | Description |
| --------------- | -------------------------------------- |
| `Phone` | Appended 10-digit phone number |
| `FirstName` | First name associated with the address |
| `LastName` | Last name associated with the address |
| `MiddleInitial` | Middle initial |
| `BusinessName` | Business name if applicable |
| `Address1` | Primary address line |
| `Address2` | Secondary address line |
| `City` | City name |
| `State` | State abbreviation |
| `Zip` | ZIP code |
| `Score` | Quality/confidence score |
| `Category` | Classification category |
| `DPV` | Delivery Point Validation code |
| `Rectype` | Record type |
| `Telconame` | Telecommunications company name |
| `DACode` | Delivery Area code |
## Example Request
```bash cURL theme={null}
curl --location --request GET \
'https://dataapi.dncscrub.com/v1.4/Data/PhoneIDAppend
?FirstName=John
&LastName=Consumer
&Address1=123%20Birch%20St
&City=Beaverton
&State=OR
&Zip=97008' \
--header 'loginId: YOUR_API_KEY'
```
```javascript JavaScript theme={null}
const response = await fetch(
'https://dataapi.dncscrub.com/v1.4/Data/PhoneIDAppend?FirstName=John&LastName=Consumer&Address1=123%20Birch%20St&City=Beaverton&State=OR&Zip=97008',
{
method: 'GET',
headers: {
'loginId': 'YOUR_API_KEY'
}
}
);
const data = await response.json();
console.log(data);
```
```csharp C# theme={null}
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Add("loginId", "YOUR_API_KEY");
var response = await client.GetAsync(
"https://dataapi.dncscrub.com/v1.4/Data/PhoneIDAppend?FirstName=John&LastName=Consumer&Address1=123%20Birch%20St&City=Beaverton&State=OR&Zip=97008"
);
var result = await response.Content.ReadAsStringAsync();
Console.WriteLine(result);
}
```
```json Response theme={null}
{
"Score": 100,
"Category": "I ",
"LastName": "CONSUMER",
"FirstName": "JOHN",
"MiddleInitial": "W",
"BusinessName": "",
"Address1": "123 BIRCH ST",
"Address2": "",
"City": "BEAVERTON",
"State": "OR",
"Zip": "97008",
"DPV": "Y",
"Phone": "7075276405",
"Rectype": "R",
"Telconame": "",
"DACode": " ",
"ResponseCode": null
}
```
# Usage Statistics
Source: https://docs.dncscrub.com/api-reference/data/usage
GET https://dataapi.dncscrub.com/v1.4/Data/Usage
Retrieves usage statistics for verification or residential/business lookups within a date range.
## Request
### Headers
Your API Key (LoginId from your DNCScrub account)
### Query Parameters
The type of usage to retrieve: `verification` or `ResOrBusiness`
Start date in YYYYMMDD format
End date in YYYYMMDD format
## Output parameters
| Field | Description |
| --------- | ------------------------------------------ |
| `Status` | The status or category of the usage record |
| `Request` | The count of requests for this status |
### Status values
When `type` is `verification`, the `Status` field contains the verification category (CategoryPhoneMatch).
When `type` is `ResOrBusiness`, the `Status` field contains the record type:
| Value | Description |
| ----- | ------------------------------------------------------- |
| `R` | Residential |
| `B` | Business |
| `U` | Unknown. The record type was not able to be determined. |
## Example Request #1 (Verification)
```bash cURL theme={null}
curl --location --request GET \
'https://dataapi.dncscrub.com/v1.4/Data/Usage
?startDate=20260101
&endDate=20260131
&type=verification' \
--header 'loginId: YOUR_API_KEY'
```
```javascript JavaScript theme={null}
const response = await fetch(
'https://dataapi.dncscrub.com/v1.4/Data/Usage?startDate=20260101&endDate=20260131&type=verification',
{
method: 'GET',
headers: {
'loginId': 'YOUR_API_KEY'
}
}
);
const data = await response.json();
console.log(data);
```
```csharp C# theme={null}
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Add("loginId", "YOUR_API_KEY");
var response = await client.GetAsync(
"https://dataapi.dncscrub.com/v1.4/Data/Usage?startDate=20260101&endDate=20260131&type=verification"
);
var result = await response.Content.ReadAsStringAsync();
Console.WriteLine(result);
}
```
## Example Request #2 (ResOrBusiness)
```bash cURL theme={null}
curl --location --request GET \
'https://dataapi.dncscrub.com/v1.4/Data/Usage
?startDate=20260101
&endDate=20260131
&type=ResOrBusiness' \
--header 'loginId: YOUR_API_KEY'
```
```javascript JavaScript theme={null}
const response = await fetch(
'https://dataapi.dncscrub.com/v1.4/Data/Usage?startDate=20260101&endDate=20260131&type=ResOrBusiness',
{
method: 'GET',
headers: {
'loginId': 'YOUR_API_KEY'
}
}
);
const data = await response.json();
console.log(data);
```
```csharp C# theme={null}
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Add("loginId", "YOUR_API_KEY");
var response = await client.GetAsync(
"https://dataapi.dncscrub.com/v1.4/Data/Usage?startDate=20260101&endDate=20260131&type=ResOrBusiness"
);
var result = await response.Content.ReadAsStringAsync();
Console.WriteLine(result);
}
```
```json Response (Verification) theme={null}
[
{
"Status": "Y",
"Request": 8038
},
{
"Status": "L",
"Request": 1242
},
{
"Status": "U",
"Request": 4389
},
{
"Status": "YX",
"Request": 2703
},
{
"Status": "YP",
"Request": 3696
},
{
"Status": "N",
"Request": 940
},
{
"Status": "",
"Request": 23
},
{
"Status": "V",
"Request": 3
},
{
"Status": "YP*",
"Request": 1
}
]
```
```json Response (ResOrBusiness) theme={null}
[
{
"Status": "R",
"Request": 69591
},
{
"Status": "B",
"Request": 11772
},
{
"Status": "U",
"Request": 6108
}
]
```
# Right Party ID
Source: https://docs.dncscrub.com/api-reference/data/verification
GET https://dataapi.dncscrub.com/v1.4/Data/Verification
Verify phone number ownership by matching against name and address data
Returns if a name and/or address matches a phone number. The most common use case of this API is to determine if the person that gave you permission to call is the current phone number owner.
## Request
### Headers
Your API Key (LoginId from your DNCScrub account)
### Query Parameters
10-digit phone number to verify
First name to match against
Last name to match against (required if consentDate not provided)
Street address
City name
State abbreviation
ZIP code
Consent date in YYYYMMDD format (required if lastName not provided)
Optional reference ID for tracking
The more fields provided, the more accurate the response will be.
## Output parameters
| Field | Description |
| ------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `Phone` | Ten digit phone number that was queried. Example 5039367188 |
| `ReferenceID` | Internal customer referenced ID that was passed in the API submission |
| `VerificationCode` | Up to 4 character code identifying the verification level. This is the field to use for match verification. The Match Type and Match Level are only provided for analytics. |
| `PhoneType` | 1 character code identifying the phone type |
| `MatchType` | See Match Table below |
| `MatchLevel` | See Match Table below |
### VerificationCode values
| Code | Description |
| ----- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `N` | Name does not match specified phone number |
| `YA` | Name matches specified phone number and full address match |
| `YPA` | Name matches specified phone number and partial address match |
| `YL` | Name matches and phone number is land line |
| `Y` | Name matches the specified phone number and no address match |
| `YP*` | Only provided if consent date provided. Confirmed the ownership of the phone has not changed since the consent date; however not able to confirm phone owner's name. |
| `YX` | The identify was verified for the number using high confidence proprietary sources (utility, financial). |
| `U` | Unknown. No records exist to make a conclusion about the phone number and name. |
### PhoneType values
| Value | Description |
| ----- | ------------- |
| `N` | Not available |
| `L` | Land Line |
| `V` | VoIP |
| `W` | Wireless |
| `O` | Other |
### Match Table
| Category | MatchType | MatchLevel | Description |
| -------------------------- | --------- | ---------- | ----------------------------------------------------------------------------- |
| | N/A | N/A | Not available |
| IP = Individual with phone | IP | 100 | Exact First, Exact Last, Exact Street Address, Unit W/A, Zip, Phone |
| | IP | 101 | Fuzzy First, Exact Last, Exact Street Address, Unit W/A, Zip, Phone |
| | IP | 102 | Exact First, Fuzzy Last, Exact Street Address, Unit W/A, Zip, Phone |
| | IP | 103 | Fuzzy First, Fuzzy Last, Exact Street Address, Unit W/A, Zip, Phone |
| | IP | 104 | Exact First, Exact Last, Exact Street Address, Unit Missing, Zip, Phone |
| | IP | 105 | Fuzzy First, Exact Last, Exact Street Address, Unit Missing, Zip, Phone |
| | IP | 106 | Exact First, Fuzzy Last, Exact Street Address, Unit Missing, Zip, Phone |
| | IP | 107 | Fuzzy First, Fuzzy Last, Exact Street Address, Unit Missing, Zip, Phone |
| | IP | 108 | Exact First, Exact Last, Fuzzy Street Address, Zip, Phone |
| | IP | 109 | Fuzzy First, Exact Last, Fuzzy Street Address, Zip, Phone |
| | IP | 110 | Exact First, Fuzzy Last, Fuzzy Street Address, Zip, Phone |
| | IP | 111 | Fuzzy First, Fuzzy Last, Fuzzy Street Address, Zip, Phone |
| | IP | 121 | Fuzzy First, Strong Last, Exact Street Address, Unit W/A, Zip, Phone |
| | IP | 131 | Fuzzy Nickname First, Strong Last, Exact Street Address, Unit W/A, Zip, Phone |
| HP = Household with phone | HP | 200 | Exact Last, Exact Street Address, Unit W/A, Zip, Phone |
| | HP | 201 | Fuzzy Last, Exact Street Address, Unit W/A, Zip, Phone |
| | HP | 202 | Exact Last, Exact Street Address, Unit Missing, Zip, Phone |
| | HP | 203 | Fuzzy Last, Exact Street Address, Unit Missing, Zip, Phone |
| | HP | 204 | Exact Last, Fuzzy Street Address, Zip, Phone |
| | HP | 205 | Fuzzy Last, Fuzzy Street Address, Zip, Phone |
| | HP | 206 | Fuzzy Last, Exact Street Address, Unit W/A, Zip, Phone |
| AP = Address with phone | AP | 300 | Exact Street Address, Unit W/A, Zip, Phone |
| | AP | 301 | Exact Street Address, Unit Missing, Zip, Phone |
| | AP | 302 | Fuzzy Street Address, Zip, Phone |
| NP = Name/Phone | NP | 400 | Exact First, Exact Last, Phone |
| | NP | 401 | Fuzzy First, Exact Last, Phone |
| | NP | 402 | Exact First, Fuzzy Last, Phone |
| | NP | 403 | Fuzzy First, Fuzzy Last, Phone |
| LP = Last Name/Phone | LP | 450 | Exact Last, Phone |
| | LP | 451 | Fuzzy Last, Phone |
| FP = First Name/Phone | FP | 460 | Exact First, Phone |
| | FP | 461 | Fuzzy First, Phone |
| | FP | 462 | Fuzzy First, Phone, names reversed |
| ZP = Zip/Phone | ZP | 500 | Zip, Phone |
| P = Phone | P | 900 | Phone Verified |
| None | X | 900 | No match found |
| None | X | 999 | No match found |
## Example Request
```bash cURL theme={null}
curl --location --request GET \
'https://dataapi.dncscrub.com/v1.4/Data/Verification
?phone=5039365190
&FirstName=John
&LastName=Consumer
&Address1=123%20Birch%20St
&City=Beaverton
&State=OR
&PostalCode=97008
&ReferenceID=DEMO' \
--header 'loginId: YOUR_API_KEY'
```
```javascript JavaScript theme={null}
const response = await fetch(
'https://dataapi.dncscrub.com/v1.4/Data/Verification?phone=5039365190&FirstName=John&LastName=Consumer&Address1=123%20Birch%20St&City=Beaverton&State=OR&PostalCode=97008&ReferenceID=DEMO',
{
method: 'GET',
headers: {
'loginId': 'YOUR_API_KEY'
}
}
);
const data = await response.json();
console.log(data);
```
```csharp C# theme={null}
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Add("loginId", "YOUR_API_KEY");
var response = await client.GetAsync(
"https://dataapi.dncscrub.com/v1.4/Data/Verification?phone=5039365190&FirstName=John&LastName=Consumer&Address1=123%20Birch%20St&City=Beaverton&State=OR&PostalCode=97008&ReferenceID=DEMO"
);
var result = await response.Content.ReadAsStringAsync();
Console.WriteLine(result);
}
```
```json Response theme={null}
{
"Phone": "5039365190",
"ReferenceID": "DEMO",
"VerificationCode": "U",
"PhoneType": "W",
"MatchType": "X",
"MatchLevel": "900"
}
```
# Is Time Legal to Call
Source: https://docs.dncscrub.com/api-reference/geoscrub/is-time-legal
POST /v1.5/GeoScrub/IsTimeLegalToCall
Check if a call is permitted at a specific date and time
## Request Parameters
| Parameter | Type | Required | Description |
| --------------------------- | -------- | -------- | -------------------------------------------------------------------------------------------------------------- |
| `PhoneNumber` | string | Yes | The phone number to check |
| `CallProposedDateTimeInUTC` | datetime | No | The proposed call time in UTC. **Defaults to current UTC time if not provided or null.** |
| `DNCProjId` | string | No | DNCScrub project ID for custom calling hours. If provided, must be a valid project accessible by your account. |
The `CallProposedDateTimeInUTC` parameter is optional. If omitted or set to null, the API will use the current UTC time, making it easy to check if a call is legal right now without having to calculate the current time yourself.
## How calling windows are determined
`IsCallPermitted` is `true` when the proposed time falls inside one of the legal calling windows for the called party's local time. Windows are resolved in priority order:
1. **Project-level override** — calling-hour rules you've configured against your `DNCProjId` for a given state in the DNCScrub Portal. Use this when your brand wants stricter rules than law requires.
2. **State law overlay** — state-specific telephone solicitation curfews tracked by Contact Center Compliance. For example, Alabama is 8 AM – 8 PM with no Sunday calls; California is 9 AM – 9 PM all 7 days; Florida is 8 AM – 8 PM. State laws are maintained by our in-house compliance counsel and updated as legislation changes — no client-side change is required.
3. **Federal baseline** — applied when no state overlay exists. **US numbers default to FCC TCPA: 8 AM – 9 PM, all 7 days, called-party local time.** Canadian numbers default to CRTC: 9 AM – 9:30 PM weekdays, 10 AM – 6 PM weekends.
A state with no Sunday calling allowed (e.g. AL/LA/MS) returns `IsCallPermitted = false` for any Sunday timestamp.
The response reflects **residential telephone solicitation** curfews. B2B calls have different rules in some states (full exemptions, narrower windows, etc.) — this API does not apply B2B exemptions. If your call list is exclusively to businesses, apply that logic on your side.
## Response Fields
Every input phone produces exactly one row in the response. Inspect `Status` to decide how to handle each row.
| Field | Type | Description |
| --------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `PhoneNumber` | string | The 10-digit phone number the row applies to |
| `IsCallPermitted` | boolean | `true` only when `Status` is `"OK"` and the proposed call time falls within a legal calling window. **Always `false` for any non-OK status, so dialers that ignore `Status` still fail closed.** |
| `SecondsInCallWindow` | integer | Seconds remaining in the legal calling window after the proposed time. Meaningful only when `IsCallPermitted` is `true` |
| `Status` | string | Outcome code for the row. See the table below |
| `StatusMessage` | string | Human-readable explanation when `Status` is not `"OK"`. `null` when `Status` is `"OK"` |
### Status Values
| Status | Meaning | Recommended client action |
| ----------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------- |
| `OK` | Row processed successfully. `IsCallPermitted` and `SecondsInCallWindow` are valid. | Use the result. |
| `INVALID_PHONE` | Phone number failed format validation (not 10 digits, not numeric, etc.). | Skip; flag the source list for cleanup. |
| `INVALID_PROJECT` | The `DNCProjId` on the row is unknown or not accessible by your account. | Verify the project id; skip the row. |
| `INVALID_DATE` | `CallProposedDateTimeInUTC` is outside the supported range (more than 50 years from today). | Verify the date; skip the row. |
| `TOLL_FREE` | Phone is in a toll-free NANP area code (8YY: 800, 833, 844, 855, 866, 877, 888 today; future-reserved 822/880-884/886/887/889 also blocked). Non-geographic, so legal call times cannot be determined. | Skip; do not retry. Filter from source list. |
| `UNKNOWN_NXX` | The NPA-NXX is not in our prefix master list. Because the master list is refreshed from definitive telco data, this almost always means the NXX is unassigned/invalid (a number that does not ring anyone). | Skip; flag the source list for cleanup. |
We deliberately do not guess a timezone for `UNKNOWN_NXX` numbers: a wrong "legal to call" answer driven by a guessed timezone is TCPA exposure, and silently approving calls to nonworking numbers would hide data quality problems on your side.
Per-row `Status` replaces the older behavior where a single bad phone caused the entire batch to return HTTP 400. The endpoint now returns 200 with one row per input phone; inspect `Status` to decide which rows are usable. HTTP 400 is still returned for batch-level errors (missing body, empty list, more than 1000 phones).
# Legal Call Times for Date
Source: https://docs.dncscrub.com/api-reference/geoscrub/legal-call-times
POST /v1.5/GeoScrub/LegalCallTimesForDate
Get the legal calling windows for a phone number on a specific date
## How calling windows are determined
The endpoint returns the legal calling windows for the called party's local time, applying these rules in priority order:
1. **Project-level override** — calling-hour rules you've configured against your `DNCProjId` for a given state in the DNCScrub Portal. Use this when your brand wants stricter rules than law requires.
2. **State law overlay** — state-specific telephone solicitation curfews tracked by Contact Center Compliance. For example, Alabama is 8 AM – 8 PM with no Sunday calls; California is 9 AM – 9 PM all 7 days; Florida is 8 AM – 8 PM. State laws are maintained by our in-house compliance counsel and updated as legislation changes — no client-side change is required.
3. **Federal baseline** — applied when no state overlay exists. **US numbers default to FCC TCPA: 8 AM – 9 PM, all 7 days, called-party local time.** Canadian numbers default to CRTC: 9 AM – 9:30 PM weekdays, 10 AM – 6 PM weekends.
A state row with `00:00–00:00` for a given day means **no calling allowed that day** (e.g. Alabama, Louisiana, Mississippi forbid Sunday telephone solicitations). The response will include zero windows for that day.
The response reflects **residential telephone solicitation** curfews. B2B calls have different rules in some states (full exemptions, narrower windows, etc.) — this API does not apply B2B exemptions. If your call list is exclusively to businesses, apply that logic on your side.
## Response Fields
Every input phone produces exactly one entry in `LegalCallTimes`. Inspect `Status` to decide how to handle each row.
| Field | Type | Description |
| ----------------- | ------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `PhoneNumber` | string | The 10-digit phone number the row applies to |
| `ValidTimesInUTC` | array | List of `{ StartInUTC, EndInUTC }` windows during which the number can legally be called. **Empty array for any non-OK status, so dialers that ignore `Status` still fail closed.** |
| `Status` | string | Outcome code for the row. See the table below |
| `StatusMessage` | string | Human-readable explanation when `Status` is not `"OK"`. `null` when `Status` is `"OK"` |
### Status Values
| Status | Meaning | Recommended client action |
| ----------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------- |
| `OK` | Row processed successfully. `ValidTimesInUTC` lists the legal call windows. | Use the result. |
| `INVALID_PHONE` | Phone number failed format validation. | Skip; flag the source list for cleanup. |
| `INVALID_PROJECT` | The `DNCProjId` on the row is unknown or not accessible by your account. | Verify the project id; skip the row. |
| `INVALID_DATE` | `Date` is outside the supported range or contains a time component. | Verify the date; skip the row. |
| `TOLL_FREE` | Phone is in a toll-free NANP area code (8YY). Non-geographic. | Skip; do not retry. Filter from source list. |
| `UNKNOWN_NXX` | The NPA-NXX is not in our prefix master list. Because the master list is refreshed from definitive telco data, this almost always means the NXX is unassigned/invalid. | Skip; flag the source list for cleanup. |
We deliberately do not guess a timezone for `UNKNOWN_NXX` numbers: a wrong "legal to call" answer driven by a guessed timezone is TCPA exposure, and silently approving calls to nonworking numbers would hide data quality problems on your side.
Per-row `Status` replaces the older behavior where a single bad phone caused the entire batch to return HTTP 400. The endpoint now returns 200 with one row per input phone; inspect `Status` to decide which rows are usable. HTTP 400 is still returned for batch-level errors (missing body, empty list, more than 1000 phones).
# GeoScrub Overview
Source: https://docs.dncscrub.com/api-reference/geoscrub/overview
Timezone lookup and legal calling time validation for compliance
The GeoScrub APIs help you comply with time-of-day calling restrictions by providing timezone information and legal calling window validation for phone numbers.
## Why GeoScrub Matters
Federal and state telephone solicitation laws restrict when you can contact consumers. The TCPA establishes a baseline of 8 AM to 9 PM in the consumer's local time, but many states have stricter rules. GeoScrub eliminates the guesswork by:
* Determining the timezone for any North American phone number
* Calculating legal calling windows based on federal and state regulations
* Accounting for holidays and state-specific restrictions
## Available Endpoints
Returns timezone information for one or more phone numbers.
Get the legal calling windows for a phone number on a specific date.
Check if a call is permitted at a specific date and time.
## Key Features
* **State-Specific Rules**: Automatically applies state telephone solicitation regulations
* **Holiday Awareness**: Accounts for state-restricted holidays
* **DST Handling**: Properly handles Daylight Saving Time transitions
* **Batch Processing**: Check multiple phone numbers in a single request
## Base URL
```
https://dataapi.dncscrub.com/v1.5/GeoScrub/
```
# Get Timezone Info
Source: https://docs.dncscrub.com/api-reference/geoscrub/timezone-info
POST /v1.5/GeoScrub/GetTimeZoneInfo
Returns timezone information for one or more North American phone numbers
## Response Fields
Every input phone produces exactly one row in the response. Inspect `Status` to decide how to handle each row.
| Field | Type | Description |
| -------------------------------------------------------------------------------------------------------------------------------------- | ------- | ----------------------------------------------------------------------------------------------------------- |
| `PhoneNumber` | string | The 10-digit phone number the row applies to |
| `TZName`, `StateProvince`, `UTCOffset`, `UTCOffsetInMinutes`, `HasDST`, `NextStartDateDST`, `EndStartDateDST`, `LATA`, `RateCenterLIR` | various | Timezone metadata. Populated only when `Status` is `"OK"`; left at default / null values for any non-OK row |
| `Status` | string | Outcome code for the row. See the table below |
| `StatusMessage` | string | Human-readable explanation when `Status` is not `"OK"`. `null` when `Status` is `"OK"` |
### Status Values
| Status | Meaning | Recommended client action |
| --------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------- |
| `OK` | Row processed successfully. Timezone fields are valid. | Use the result. |
| `INVALID_PHONE` | Phone number failed format validation. | Skip; flag the source list for cleanup. |
| `TOLL_FREE` | Phone is in a toll-free NANP area code (8YY). Non-geographic, so no timezone exists. | Skip; do not retry. |
| `UNKNOWN_NXX` | The NPA-NXX is not in our prefix master list. Because the master list is refreshed from definitive telco data, this almost always means the NXX is unassigned/invalid. | Skip; flag the source list for cleanup. |
Per-row `Status` replaces the older behavior where a single bad phone caused the entire batch to return HTTP 400. The endpoint now returns 200 with one row per input phone; inspect `Status` to decide which rows are usable. HTTP 400 is still returned for batch-level errors (missing body, empty list, more than 1000 phones).
# Litigator API
Source: https://docs.dncscrub.com/api-reference/litigator/overview
High-performance API for checking phone numbers against the litigator list
# High Performance Litigator API
The Litigator API is a specialized, high-performance endpoint for checking if phone numbers are associated with known TCPA litigators.
This API **only** checks the litigator list. It does not check Federal/State DNC databases, line type, Internal DNC, EBR, or calling time restrictions. If you need full DNC checking, use the [Full Scrub API](/api-reference/scrub/overview) instead.
## When to Use This API
* You need **high-performance** litigator checking only
* You want to pre-screen numbers before full scrubbing
* Your workflow only requires litigator identification
## Endpoint
```
https://dataapi.dncscrub.com/v1.4/scrub/litigator
```
## Authentication
Include your API key in the `loginId` header or as a query parameter.
## Parameters
| Parameter | Required | Description |
| ----------- | -------- | ---------------------------------------------- |
| `phoneList` | Yes | Comma-separated list of 10-digit phone numbers |
| `loginId` | Yes | Your API Key (header or query parameter) |
If submitting more than 100 phone numbers, you **must** use HTTP POST with JSON body instead of HTTP GET.
## Example: HTTP GET
```bash cURL theme={null}
curl --location --request GET \
'https://dataapi.dncscrub.com/v1.4/scrub/litigator?phoneList=5039367187,7075276405&loginId=YOUR_API_KEY'
```
```bash cURL (loginId in header) theme={null}
curl --location --request GET \
'https://dataapi.dncscrub.com/v1.4/scrub/litigator?phoneList=5039367187,7075276405' \
--header 'loginId: YOUR_API_KEY'
```
```javascript JavaScript theme={null}
const response = await fetch(
'https://dataapi.dncscrub.com/v1.4/scrub/litigator?phoneList=5039367187,7075276405',
{
method: 'GET',
headers: { 'loginId': 'YOUR_API_KEY' }
}
);
const data = await response.json();
```
### Response
```json theme={null}
[
{
"Phone": 5039367187,
"IsLitigator": true
},
{
"Phone": 7075276405,
"IsLitigator": false
}
]
```
## Example: HTTP POST (for 100+ numbers)
Use HTTP POST with a JSON body for large batches:
```bash cURL theme={null}
curl --location --request POST \
'https://dataapi.dncscrub.com/v1.4/scrub/litigator' \
--header 'Content-Type: application/json' \
--data-raw '{
"phoneList": "2675466417,5039367187",
"loginId": "YOUR_API_KEY"
}'
```
```javascript JavaScript theme={null}
const response = await fetch(
'https://dataapi.dncscrub.com/v1.4/scrub/litigator',
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
'loginId': 'YOUR_API_KEY'
},
body: JSON.stringify({
phoneList: '2675466417,5039367187'
})
}
);
```
### Response
```json theme={null}
[
{
"Phone": 2675466417,
"IsLitigator": true
},
{
"Phone": 5039367187,
"IsLitigator": true
}
]
```
## Response Fields
| Field | Type | Description |
| ------------- | ------- | ---------------------------------------------------------------------------- |
| `Phone` | Number | The phone number that was checked |
| `IsLitigator` | Boolean | `true` if the number is associated with a known litigator, `false` otherwise |
## Processing the Response
```javascript theme={null}
const results = await response.json();
const litigators = results.filter(r => r.IsLitigator);
const safe = results.filter(r => !r.IsLitigator);
console.log(`Litigators found: ${litigators.length}`);
console.log(`Safe numbers: ${safe.length}`);
// Take action on litigator numbers
litigators.forEach(r => {
console.log(`WARNING: ${r.Phone} is a known litigator!`);
});
```
## Security Best Practice
For additional security, pass the `loginId` in the HTTP header instead of the query string:
```bash theme={null}
curl --location --request GET \
'https://dataapi.dncscrub.com/v1.4/scrub/litigator?phoneList=5039367187,7075276405' \
--header 'loginId: YOUR_API_KEY'
```
This prevents the API key from appearing in server logs and browser history.
## Example Use Case
The following diagram illustrates a common workflow for businesses collecting opt-in leads, showing how the Litigator API and [Reassigned Authority API](/api-reference/reassigned/overview) work together to maintain TCPA compliance:
### Workflow Summary
1. **At checkout** - When a customer opts in to receive marketing messages, immediately scrub against the Litigator List to avoid known litigators
2. **Save the lead** - Store the opt-in with the consent date
3. **Wait 30 days** - Phone numbers can be reassigned at any time; waiting helps identify reassignments
4. **Scrub against Reassigned List** - Before contacting, check if the number has been reassigned since consent was given
5. **Optional re-check** - Scrub against the Litigator List again (litigator status can change)
6. **Repeat monthly** - Continue this process every 30 days to maintain compliance
# Litigator Scrub Single Number
Source: https://docs.dncscrub.com/api-reference/litigator/scrub-get
GET https://dataapi.dncscrub.com/v1.5/Scrub/litigator
Check phone numbers against the litigator database using GET request
Check a list of phone numbers against the litigator database using an HTTP GET request. Use this method for small batches (up to 100 phone numbers).
For batches larger than 100 phone numbers, use the [POST
method](/api-reference/litigator/scrub-post) instead.
## Request
### Headers
Your API Key (LoginId from your DNCScrub account)
### Query Parameters
Comma-separated list of 10-digit phone numbers to check (maximum 100 numbers
for GET requests, up to 10,000 for POST)
Optional campaign ID for tracking purposes
Optional project ID for tracking purposes
Output format: `JsonArray` (default) or `JsonObject` for Zapier compatibility
## Example Request
```bash cURL theme={null}
curl --location --request GET \
'https://dataapi.dncscrub.com/v1.5/Scrub/litigator?phoneList=5039367187,7075276405' \
--header 'loginId: YOUR_API_KEY'
```
```bash cURL (loginId in query) theme={null}
curl --location --request GET \
'https://dataapi.dncscrub.com/v1.5/Scrub/litigator?phoneList=5039367187,7075276405&loginId=YOUR_API_KEY'
```
```javascript JavaScript theme={null}
const response = await fetch(
"https://dataapi.dncscrub.com/v1.5/Scrub/litigator?phoneList=5039367187,7075276405",
{
method: "GET",
headers: { loginId: "YOUR_API_KEY" },
}
);
const data = await response.json();
console.log(data);
```
```csharp C# theme={null}
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Add("loginId", "YOUR_API_KEY");
var phoneNumbers = "5039367187,7075276405";
var url = $"https://dataapi.dncscrub.com/v1.5/Scrub/litigator?phoneList={phoneNumbers}";
var response = await client.GetStringAsync(url);
Console.WriteLine(response);
}
```
```json Response theme={null}
[
{
"Phone": 5039367187,
"IsLitigator": true
},
{
"Phone": 7075276405,
"IsLitigator": false
}
]
```
## Response Fields
The 10-digit phone number that was checked
`true` if the phone number is associated with a known TCPA litigator, `false`
otherwise
## Error Responses
| Status | Description |
| ---------------- | ---------------------------------------------------------- |
| 400 Bad Request | Invalid phone number format or missing required parameters |
| 401 Unauthorized | Invalid or missing API key |
| 404 Not Found | Endpoint not found or invalid URL |
## Processing the Response
```javascript theme={null}
const results = await response.json();
// Filter litigator numbers
const litigators = results.filter((r) => r.IsLitigator);
const safe = results.filter((r) => !r.IsLitigator);
console.log(`Litigators found: ${litigators.length}`);
console.log(`Safe numbers: ${safe.length}`);
// Flag litigator numbers
litigators.forEach((r) => {
console.log(`WARNING: ${r.Phone} is a known litigator`);
});
```
## Security Best Practice
For additional security, pass the `loginId` in the HTTP header rather than as a query parameter. This prevents your API key from appearing in server logs and browser history.
# Litigator Scrub Multiple Numbers
Source: https://docs.dncscrub.com/api-reference/litigator/scrub-post
POST https://dataapi.dncscrub.com/v1.5/Scrub/litigator
Check phone numbers against the litigator database using POST request
Check a list of phone numbers against the litigator database using an HTTP POST request. Use this method for large batches (over 50 phone numbers, up to 10,000).
## Request
### Headers
API Key
Must be `application/json`
### Request Body
Comma-separated list of 10-digit phone numbers to check (up to 10,000 numbers)
Optional campaign ID for tracking purposes
Optional project ID for tracking and settings purposes
Optional Output format: `JsonArray` (default) or `JsonObject`. By default
returns `JsonArray`.
## Example Request
```bash cURL theme={null}
curl --location --request POST \
'https://dataapi.dncscrub.com/v1.5/Scrub/litigator' \
--header 'Content-Type: application/json' \
--header 'loginId: YOUR_API_KEY' \
--data-raw '{
"PhoneList": "2675466417,5039367187,7075276405"
}'
```
```bash cURL (loginId in body) theme={null}
curl --location --request POST \
'https://dataapi.dncscrub.com/v1.5/Scrub/litigator' \
--header 'Content-Type: application/json' \
--data-raw '{
"PhoneList": "2675466417,5039367187,7075276405",
"LoginId": "YOUR_API_KEY"
}'
```
```javascript JavaScript theme={null}
const response = await fetch(
"https://dataapi.dncscrub.com/v1.5/Scrub/litigator",
{
method: "POST",
headers: {
"Content-Type": "application/json",
loginId: "YOUR_API_KEY",
},
body: JSON.stringify({
PhoneList: "2675466417,5039367187,7075276405",
}),
}
);
const data = await response.json();
console.log(data);
```
```csharp C# theme={null}
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Add("loginId", "YOUR_API_KEY");
var content = new StringContent(
JsonSerializer.Serialize(new { PhoneList = "2675466417,5039367187,7075276405" }),
Encoding.UTF8,
"application/json"
);
var response = await client.PostAsync(
"https://dataapi.dncscrub.com/v1.5/Scrub/litigator",
content
);
var result = await response.Content.ReadAsStringAsync();
Console.WriteLine(result);
}
```
```json Response theme={null}
[
{
"Phone": 2675466417,
"IsLitigator": true
},
{
"Phone": 5039367187,
"IsLitigator": true
},
{
"Phone": 7075276405,
"IsLitigator": false
}
]
```
## Response Fields
The 10-digit phone number that was checked
`true` if the phone number is associated with a known TCPA litigator, `false`
otherwise
## Error Responses
| Status | Description |
| ---------------- | --------------------------------------------------------------------------- |
| 400 Bad Request | Invalid phone number format, malformed JSON, or missing required parameters |
| 401 Unauthorized | Invalid or missing API key |
| 404 Not Found | Endpoint not found or invalid URL |
## Batch Processing Example
When processing large lists, you may want to batch and process results:
```javascript theme={null}
async function checkLitigators(phoneNumbers) {
// Join phone numbers into comma-separated string
const phoneList = phoneNumbers.join(",");
const response = await fetch(
"https://dataapi.dncscrub.com/v1.5/Scrub/litigator",
{
method: "POST",
headers: {
"Content-Type": "application/json",
loginId: "YOUR_API_KEY",
},
body: JSON.stringify({ PhoneList: phoneList }),
}
);
const results = await response.json();
// Separate litigators from safe numbers
const litigators = results.filter((r) => r.IsLitigator);
const safe = results.filter((r) => !r.IsLitigator);
return {
litigators: litigators.map((r) => r.Phone),
safe: safe.map((r) => r.Phone),
totalChecked: results.length,
};
}
// Usage
const phones = ["2675466417", "5039367187", "7075276405"];
const result = await checkLitigators(phones);
console.log(`Found ${result.litigators.length} litigators`);
```
## Security Best Practice
For additional security, pass the `loginId` in the HTTP header rather than in the JSON body. This prevents your API key from appearing in application logs.
# Validate Authentication
Source: https://docs.dncscrub.com/api-reference/other/auth-validate
GET /v1.5/Auth/Validate
Validate your loginId and optionally verify campaign or project access
# Compliance Guide API
Source: https://docs.dncscrub.com/api-reference/other/compliance-guide
Access compliance guidance and regulatory information
# Compliance Guide API
The Compliance Guide API provides programmatic access to compliance rules and regulatory information.
For detailed API documentation, contact [support@dnc.com](mailto:support@dnc.com).
## Overview
The Compliance Guide API helps you:
* Understand calling time restrictions by state
* Access current regulatory requirements
* Build compliance rules into your systems
## Use Cases
* Determine allowed calling hours for a phone number
* Check state-specific regulations
* Build compliance dashboards
## Getting Started
Contact [support@dnc.com](mailto:support@dnc.com) for:
* API access and credentials
* Complete documentation
* Implementation assistance
# Global Connect API
Source: https://docs.dncscrub.com/api-reference/other/global-connect
International phone number validation and compliance
# Global Connect API
The Global Connect API extends CCC compliance capabilities to international phone numbers.
For detailed API documentation, contact [support@dnc.com](mailto:support@dnc.com).
## Supported Countries
Global Connect supports phone number validation and compliance checking for numbers outside North America.
## Features
* International number validation
* Country-specific compliance rules
* Carrier identification
* Line type detection
## Use Cases
* Validate international phone numbers
* Check country-specific DNC lists
* Identify international carriers
* Support global calling campaigns
## Getting Started
Contact [support@dnc.com](mailto:support@dnc.com) to:
* Discuss your international requirements
* Get pricing information
* Receive API documentation
# Global Connect Query
Source: https://docs.dncscrub.com/api-reference/other/global-connect-query
GET /v1.5/gc/Query
Get information about international phone numbers
# Get OAuth Token
Source: https://docs.dncscrub.com/api-reference/other/oauth-token
POST /v1.5/OAuth/token
Obtain an OAuth 2.0 access token for API authentication
# Create or Update Project
Source: https://docs.dncscrub.com/api-reference/other/project-create
POST https://www.dncscrub.com/app/main/rpc/project
Create a new Project or update an existing Project's settings
Programmatically create new Projects or update existing ones. Projects are the
top-level container in DNCScrub for organizing campaigns, scrub options, and
Internal DNC lists.
If the supplied `project_code` already exists, the endpoint updates the
existing Project. If it does not exist, a new Project is created with a
default Campaign.
## Request
### Headers
Your API Key
### Query / Form Parameters
Project code to insert or update. Will be uppercased and trimmed.
If your account has auto-prefixing enabled, the prefix `_` is added
automatically when missing.
Pass `projId=` instead of `project_code` to operate on the Master
Project.
Display name of the Project.
FTC Org Id or SAN. When supplied on a new Project, the value is validated
against the FTC; if a SAN is supplied, the corresponding Org Id is resolved
and stored.
Internal handler override. The endpoint normally infers this:
* `insert_project` - new project (auto-selected when `project_code` does not exist)
* `update_project` - update existing project (auto-selected when it exists)
* `deactivate_project` - mark project inactive
* `reactivate_project` - reactivate an inactive project
Pass `xml` to return a full XML document describing the resulting Project,
its Campaigns, and (for SmartBlock-enabled accounts) SmartBlock settings.
Free-form project notes.
Inherit the Master Project's Internal DNC / DNM database.
Inherit the Master Project's EBR / override database.
Inherit the Master Project's DNC policy.
Inherit the Master Project's national DNC subscription.
Inherit the Master Project's training materials.
## Example Request
```bash cURL (Create) theme={null}
curl --location --request POST \
'https://www.dncscrub.com/app/main/rpc/project' \
--header 'loginId: YOUR_API_KEY' \
--data-urlencode 'project_code=ACME_Q4' \
--data-urlencode 'project_name=ACME Q4 Outbound' \
--data-urlencode 'nat_dnc_org_id=12345678'
```
```bash cURL (Update) theme={null}
curl --location --request POST \
'https://www.dncscrub.com/app/main/rpc/project' \
--header 'loginId: YOUR_API_KEY' \
--data-urlencode 'project_code=ACME_Q4' \
--data-urlencode 'project_name=ACME Q4 (renamed)'
```
```bash cURL (Create + XML response) theme={null}
curl --location --request POST \
'https://www.dncscrub.com/app/main/rpc/project?output=xml' \
--header 'loginId: YOUR_API_KEY' \
--data-urlencode 'project_code=ACME_Q4' \
--data-urlencode 'project_name=ACME Q4 Outbound'
```
```javascript JavaScript theme={null}
const body = new URLSearchParams({
project_code: "ACME_Q4",
project_name: "ACME Q4 Outbound",
nat_dnc_org_id: "12345678",
});
const res = await fetch("https://www.dncscrub.com/app/main/rpc/project", {
method: "POST",
headers: {
loginId: "YOUR_API_KEY",
"Content-Type": "application/x-www-form-urlencoded",
},
body,
});
console.log(res.status); // 201 on create, 200 on update
```
```csharp C# theme={null}
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Add("loginId", "YOUR_API_KEY");
var form = new FormUrlEncodedContent(new[]
{
new KeyValuePair("project_code", "ACME_Q4"),
new KeyValuePair("project_name", "ACME Q4 Outbound"),
new KeyValuePair("nat_dnc_org_id", "12345678"),
});
var res = await client.PostAsync(
"https://www.dncscrub.com/app/main/rpc/project", form);
}
```
## Response
| Status Code | Meaning |
| ----------- | ------------------------------------------------------------------- |
| `200` | Project updated successfully (no body unless `output=xml`) |
| `201` | Project created successfully (no body unless `output=xml`) |
| `400` | Validation or save error - reason phrase contains the error message |
| `403` | Project exists but is inactive (use `handler=reactivate_project`) |
When `output=xml` is supplied, the response body is an XML document rooted at
`...`
containing the Project, its Campaigns, and any FTC Org Id metadata that was
just resolved.
## Reactivating an Inactive Project
If `project_code` matches an inactive Project, the endpoint returns `403
Inactive Project` unless you explicitly request reactivation:
```bash theme={null}
curl --location --request POST \
'https://www.dncscrub.com/app/main/rpc/project' \
--header 'loginId: YOUR_API_KEY' \
--data-urlencode 'project_code=ACME_Q4' \
--data-urlencode 'project_name=ACME Q4 Outbound' \
--data-urlencode 'handler=reactivate_project'
```
## Master Project Operations
Pass `projId=` (with no `project_code`) to update settings on your
account's Master Project:
```bash theme={null}
curl --location --request POST \
'https://www.dncscrub.com/app/main/rpc/project' \
--header 'loginId: YOUR_API_KEY' \
--data-urlencode 'projId=YOUR_ACCT_ID' \
--data-urlencode 'nat_dnc_org_id=12345678'
```
## Listing All Projects
There is no separate list endpoint - this same endpoint returns a full project
enumeration when you target the Master Project with `output=xml` and no fields
to update. Because no fields change, the call is read-only:
```bash theme={null}
curl --location --request GET \
'https://www.dncscrub.com/app/main/rpc/project?projId=YOUR_ACCT_ID&output=xml' \
--header 'loginId: YOUR_API_KEY'
```
The XML response lists every Project the account can access (including
cross-account projects), each Project's Campaigns, and each Campaign's status.
To list a single Project instead, pass that Project's `projId` rather than your
account ID.
To get details for a single Project, pass that Project's `projId`:
```bash theme={null}
curl --location --request GET \
'https://www.dncscrub.com/app/main/rpc/project?projId=ACME_Q4&output=xml' \
--header 'loginId: YOUR_API_KEY'
```
## Best Practices
The same request creates a Project on first call and updates it on
subsequent calls. Use the HTTP status code (`201` vs `200`) to tell the
cases apart.
Adding `output=xml` to a create request returns the new Project's full
record (including the auto-created default Campaign) so you don't need a
follow-up call to get its IDs.
Supplying `nat_dnc_org_id` on a new Project triggers FTC validation. Make
sure the Org Id (or SAN) is correct, or the create will fail with an FTC
error message.
Project codes are uppercased automatically. Avoid the `_` character in your
raw code if your account uses auto-prefixing - the prefix delimiter is
`_`.
# Rate Limits
Source: https://docs.dncscrub.com/api-reference/other/rate-limits
API rate limits and best practices
All APIs have rate limits to ensure fair usage and system stability.
## Standard Rate Limits
| API | Rate Limit | Max Batch Size |
| ------------------------- | --------------------- | ---------------- |
| Scrub API (GET) | 200 requests/minute | 10 numbers |
| Scrub API (POST) | 200 requests/minute | 10,000 numbers |
| Litigator-Only API (GET) | 1,000 requests/minute | 10 numbers |
| Litigator-Only API (POST) | 1,000 requests/minute | 10,000 numbers |
| Reassigned APIs | 1,000 requests/minute | 1,000 numbers |
| TrustCall | 100 requests/minute | 50 numbers (add) |
## Exceeding the Rate Limit
Limits are enforced per client IP address over a one-minute window. Requests over the limit are
rejected with HTTP `429 Too Many Requests` and this body:
```json theme={null}
{"error":"rate_limit_exceeded","message":"Rate limit exceeded. Slow down and retry after 60 seconds."}
```
Key on the status code rather than parsing the body: the `429` is returned by our edge gateway,
which labels the body `Content-Type: text/html`. Wait 60 seconds before retrying; a tight retry loop
keeps the window full and extends the block.
## Average API Response Times
Average response time per request. Unless otherwise noted (for example, the 1,000-number batch row), times are measured for a single phone number. These are averages measured by third-party monitoring services. Outliers will exist that are both faster and slower.
| API | Average Response Time |
| ------------------------------------ | --------------------- |
| Full Scrub API (1 number) | 600ms |
| Full Scrub API (1,000 numbers) | 1200ms |
| Litigator-Only API (1 number) | 400ms |
| Reassigned Authority Plus (1 number) | 700ms |
| Reassigned Authority (1 number) | 500ms |
| RND Basic (1 number) | 700ms |
| Right Party ID (1 number) | 1600ms |
## HTTP Method Requirements
| Numbers | Required Method |
| ------- | --------------- |
| 1-10 | GET or POST |
| 11+ | POST required |
Requests with more than 10 phone numbers **must** use HTTP POST. GET requests
will fail. If you don't know your payload size, use HTTP POST to prevent
future issue.
## Retry Example
**You must plan what your system will do in the event of a network or service outage.** Our recommendation is to implement retries with exponential backoff.
```javascript theme={null}
async function scrubWithRetry(phoneNumbers, apiKey, maxRetries = 5) {
const baseUrl = "https://www.dncscrub.com/scrub";
const url = `${baseUrl}?phone=${phoneNumbers.join(",")}`;
const baseDelay = 1000; // Start with 1 second
for (let attempt = 1; attempt <= maxRetries; attempt++) {
let response;
try {
response = await fetch(url, { headers: { loginId: apiKey } });
} catch (networkError) {
// fetch throws on DNS/connection failures; treat like a 5xx and retry
response = { ok: false, status: 0 };
}
if (response.ok) {
return await response.json();
}
const retryable = response.status === 429 || response.status >= 500 || response.status === 0;
if (retryable && attempt < maxRetries) {
// 429 = rate limited: wait out the one-minute window before retrying
// 5xx / network error = transient failure: exponential backoff 1s, 2s, 4s, 8s, 16s
const delay =
response.status === 429 ? 60000 : baseDelay * Math.pow(2, attempt - 1);
console.log(
`Request failed with ${response.status || "network error"}. Retrying in ${
delay / 1000
}s (attempt ${attempt}/${maxRetries})...`
);
await new Promise((resolve) => setTimeout(resolve, delay));
continue;
}
throw new Error(`Request failed with status ${response.status}`);
}
throw new Error("Max retries exceeded");
}
// Usage
const results = await scrubWithRetry(
["5551234567", "5559876543"],
"your-api-key"
);
```
## Best Practices
Instead of making 100 requests with 1 number each, make 1 request with 100
numbers.
If you receive a 5xx response, wait and retry with exponential backoff. If
you receive a 429, you have exceeded your rate limit: wait 60 seconds, then
retry.
Cache scrub results to avoid re-checking the same numbers unnecessarily.
Consider what your system will do in the event of a network or service
outage. Implement retry logic with exponential backoff and have a fallback
plan for when the API is unavailable.
For very large batches of phone numbers where real-time checking is not
needed, consider using SFTP file upload instead of the API. This is more
efficient for processing millions of records.
## File Upload Limits for SFTP or Web Portal
| Product | Max Rows Per File | Max File Size |
| ------------------------- | ----------------- | ------------- |
| Reassigned Authority Plus | 1,000,000 | 500MB |
| Reassigned Authority | 10,000,000 | 650MB |
| DNC Scrub | 15,000,000 | 800MB |
# State Emergencies
Source: https://docs.dncscrub.com/api-reference/other/state-emergencies
GET /v1.5/ComplianceGuide/StateEmergenciesRestricted
Get all states currently under emergency calling restrictions
# State Restricted Holidays
Source: https://docs.dncscrub.com/api-reference/other/state-holidays
GET /v1.5/ComplianceGuide/StateRestrictedHolidays
Get all states and their restricted holidays for telephone solicitations
# API Overview
Source: https://docs.dncscrub.com/api-reference/overview
Welcome to the DNCScrub API Documentation
Our APIs provide a set of RESTful services for integrating TCPA Compliance, Do-Not-Call Compliance, Call Deliverability, and Data Enhancement directly into your applications. These APIs let you scrub phone numbers against Federal and State DNC lists, maintain Internal DNC and Existing Business Relationship lists, manage your Caller ID, and automate compliance and call deliverability workflows at scale. This documentation will help you understand each API, how they work, and how to integrate them into your dialing platform, CRM, or internal tools.
## Available APIs
Scrub phone numbers against National DNC (US and Canada), State DNC (US), Litigator lists, and
your Internal DNC database.
Identify phone numbers reassigned to maintain TCPA compliance.
High-performance Litigator-only API for scrubbing phone numbers against known TCPA
litigators and those who have filed other consumer-protection lawsuits.
Manage your Caller ID and Call Deliverability.
Enhance your phone number data with carrier information, line type detection, and identity verification services.
Check the timezone and legal calling times for a phone number.
## Getting Started
1. **Get an API Key** - Create an API user in the DNCScrub portal and generate an API key
2. **Review Authentication** - All API calls require your API key in the HTTP header
3. **Make Your First Call** - Start with the Scrub API to check phone numbers
## Requirements
1. To scrub against Federal DNC list, whether US or Canada, you must have a valid FTC SAN.
2. Your DNCScrub account must be active and subscribed to the services you wish to use.
3. All API calls must be made using HTTPS with TLS 1.2 or above.
# Reassigned Authority API
Source: https://docs.dncscrub.com/api-reference/reassigned/authority
Check if a phone number has been reassigned after a given consent date
# Reassigned Authority API
The Reassigned Authority API identifies if a mobile phone number has been reassigned after a given date. The API uses authoritative data provided directly from carriers.
## Endpoint
```
https://dataapi.dncscrub.com/v1.5/Data/TCPAAuthority
```
## Authentication
Include your API key in the `loginId` HTTP header:
```bash theme={null}
--header 'loginId: YOUR_API_KEY'
```
## Parameters
| Parameter | Required | Description |
| ------------- | -------- | ---------------------------------------------------------------------- |
| `phoneNumber` | Yes | 10-digit phone number (no leading 1 or +) |
| `date` | Yes | Consent date to check against |
| `useSandbox` | No | Set to `true` to use sandbox mode for testing (returns random results) |
### Date Formats
The `date` parameter accepts multiple formats:
| Format | Example |
| ------------ | ------------ |
| `MM/DD/YYYY` | `09/29/2021` |
| `YYYY-MM-DD` | `2021-09-29` |
| `MM/DD/YY` | `09/29/21` |
| `YYYYMMDD` | `20210929` |
## Single Number Request (GET)
```bash cURL theme={null}
curl --location --request GET \
'https://dataapi.dncscrub.com/v1.5/Data/TCPAAuthority?phoneNumber=7075276405&date=20210209' \
--header 'loginId: YOUR_API_KEY'
```
```javascript JavaScript theme={null}
const response = await fetch(
"https://dataapi.dncscrub.com/v1.5/Data/TCPAAuthority?phoneNumber=7075276405&date=20210209",
{
headers: { loginId: "YOUR_API_KEY" },
}
);
const result = await response.json();
```
```csharp C# theme={null}
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Add("loginId", "YOUR_API_KEY");
var response = await client.GetStringAsync(
"https://dataapi.dncscrub.com/v1.5/Data/TCPAAuthority?phoneNumber=7075276405&date=20210209"
);
}
```
### Response
```json theme={null}
{
"PhoneNumber": "7075276405",
"IsReassigned": false,
"IsValid": true,
"LineType": "Landline",
"Carrier": "AT&T California",
"Locale": "Santa Rosa",
"Region": "CA",
"Country": "US",
"TZ": "America/Los_Angeles",
"UTCOffset": "-420"
}
```
## Multiple Number Request (POST)
For checking multiple numbers, use HTTP POST with a JSON array:
```bash theme={null}
curl --location --request POST \
'https://dataapi.dncscrub.com/v1.5/Data/TCPAAuthority' \
--header 'loginId: YOUR_API_KEY' \
--header 'Content-Type: application/json' \
--data-raw '[
{
"phoneNumber": "7075276405",
"date": "20210209"
},
{
"phoneNumber": "5039367187",
"date": "20210209"
}
]'
```
### Response
```json theme={null}
[
{
"PhoneNumber": "7075276405",
"IsReassigned": false,
"IsValid": true,
"LineType": "Landline",
"Carrier": "AT&T California",
"Locale": "Santa Rosa",
"Region": "CA",
"Country": "US",
"TZ": "America/Los_Angeles",
"UTCOffset": "-420"
},
{
"PhoneNumber": "5039367187",
"IsReassigned": false,
"IsValid": true,
"LineType": "Wireless",
"Carrier": "Verizon Wireless",
"Locale": "Portland",
"Region": "OR",
"Country": "US",
"TZ": "America/Los_Angeles",
"UTCOffset": "-420"
}
]
```
## Response Fields
| Field | Type | Description |
| -------------- | ------------ | ------------------------------------------------------------------------- |
| `PhoneNumber` | String | The phone number checked |
| `IsReassigned` | Boolean/null | `true` = reassigned, `false` = not reassigned, `null` = insufficient data |
| `IsValid` | Boolean | `true` if the number is callable, `false` if invalid |
| `LineType` | String | `Wireless`, `VoIP`, `Landline`, `Paging`, or `Unknown` |
| `Carrier` | String | Original carrier the number was assigned to |
| `Locale` | String | City based on original assignment |
| `Region` | String | State/region based on original assignment |
| `Country` | String | Two-digit ISO country code |
| `TZ` | String | Timezone in IANA format (e.g., `America/Los_Angeles`) |
| `UTCOffset` | String | UTC offset in minutes |
## Understanding IsReassigned
The phone number was reassigned to a new person **after** the consent date you provided.
**Action:** Do not call this number. Your consent is no longer valid.
The phone number has **not** been reassigned since the consent date.
**Action:** Safe to call - your consent is still valid.
There is insufficient data to determine if the number was reassigned.
**Action:** Proceed with caution. Consider additional verification.
## Rate Limits
| Limit | Value |
| --------------------- | ------- |
| Requests per minute | 100 |
| Numbers per request | 1,000 |
| Average response time | \~569ms |
## C# Class Definitions
```csharp theme={null}
public class TCPAAuthorityRequestDTO
{
public string PhoneNumber { get; set; }
public string Date { get; set; }
}
public class TCPAAuthorityResponseDTO
{
public string PhoneNumber { get; set; }
public bool? IsReassigned { get; set; }
public bool IsValid { get; set; }
public string LineType { get; set; }
public string Carrier { get; set; }
public string Locale { get; set; }
public string Region { get; set; }
public string Country { get; set; }
public string TZ { get; set; }
public string UTCOffset { get; set; }
}
```
# Reassigned Authority (GET)
Source: https://docs.dncscrub.com/api-reference/reassigned/authority-get
GET https://dataapi.dncscrub.com/v1.5/Data/TCPAAuthority
Check if a phone number has been reassigned since a given consent date
Check if a phone number has been reassigned since a given consent date using the TCPA Authority API. This API uses authoritative data provided directly from carriers.
The date input should be the consent date the customer gave the calling party
consent to be called. If `IsReassigned` returns `true`, **do not call the
number**.
## Request
### Headers
Your API Key (LoginId from your DNCScrub account)
### Query Parameters
10-digit North American phone number (without leading 1 or +)
Consent date to check reassignment against. Supported formats: `MM/DD/YYYY`,
`YYYY-MM-DD`, `MM/DD/YY`, or `YYYYMMDD`
(Optional) Set to `true` to use sandbox mode for testing (returns random
results)
## Example Request
```bash cURL theme={null}
curl --location --request GET \
'https://dataapi.dncscrub.com/v1.5/Data/TCPAAuthority?phoneNumber=7075276405&date=20210209' \
--header 'loginId: YOUR_API_KEY'
```
```javascript JavaScript theme={null}
const response = await fetch(
"https://dataapi.dncscrub.com/v1.5/Data/TCPAAuthority?phoneNumber=7075276405&date=20210209",
{
method: "GET",
headers: { loginId: "YOUR_API_KEY" },
}
);
const data = await response.json();
console.log(data);
```
```csharp C# theme={null}
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Add("loginId", "YOUR_API_KEY");
var url = "https://dataapi.dncscrub.com/v1.5/Data/TCPAAuthority?phoneNumber=7075276405&date=20210209";
var response = await client.GetStringAsync(url);
Console.WriteLine(response);
}
```
```json Response theme={null}
{
"PhoneNumber": "7075276405",
"IsReassigned": false,
"IsValid": true,
"LineType": "Landline",
"Carrier": "AT&T California",
"Locale": "Santa Rosa",
"Region": "CA",
"Country": "US",
"TZ": "America/Los_Angeles",
"UTCOffset": "-420"
}
```
## Response Fields
The phone number that was checked
Indicates if the phone was reassigned after the consent date: - `true` -
Reassigned after the date. **Do not call.** - `false` - Not reassigned. Safe
to call. - `null` - Insufficient information to determine reassignment status.
`true` if the phone number is valid and callable, `false` if not valid
Type of phone line: `Wireless`, `VoIP`, `Landline`, `Paging`, or `Unknown`
Original carrier the phone number was assigned to
City based on original phone number assignment
State/region based on original phone number assignment
Two-digit ISO country code
Timezone in ISO IANA format (e.g., `America/Los_Angeles`)
UTC offset in minutes. Use this to calculate the local time at the phone
number.
## Error Responses
| Status | Description |
| ---------------- | -------------------------------------------------------------------------------- |
| 400 Bad Request | Invalid phone number format, invalid date format, or missing required parameters |
| 401 Unauthorized | Invalid or missing API key |
| 403 Forbidden | Account not authorized for this API or insufficient credits |
## Processing the Response
```javascript theme={null}
const result = await response.json();
if (result.IsReassigned === true) {
console.log("DO NOT CALL - Number has been reassigned");
} else if (result.IsReassigned === false) {
console.log("Safe to call - Number has not been reassigned");
console.log(`Line type: ${result.LineType}`);
console.log(`Carrier: ${result.Carrier}`);
} else {
console.log("Insufficient data to determine reassignment status");
}
```
# Reassigned Authority Plus API
Source: https://docs.dncscrub.com/api-reference/reassigned/authority-plus
Enhanced reassigned number detection with additional data points
# Reassigned Authority Plus API
Reassigned Authority Plus (Enhanced RND) combines CCC's authoritative carrier data with the FCC Reassigned Number Database to provide the most accurate reassignment determination available.
## Endpoint
```
https://dataapi.dncscrub.com/v1.5/Data/EnhancedRND
```
## Authentication
Include your API key in the `loginId` HTTP header:
```bash theme={null}
--header 'loginId: YOUR_API_KEY'
```
## Parameters
| Parameter | Required | Description |
| ------------- | -------- | ---------------------------------------------------------------------- |
| `phoneNumber` | Yes | 10-digit phone number (no leading 1 or +) |
| `date` | Yes | Consent date to check against |
| `useSandbox` | No | Set to `true` to use sandbox mode for testing (returns random results) |
| `projId` | No | Project identifier for tracking purposes |
### Date Formats
The `date` parameter accepts multiple formats:
| Format | Example |
| ------------ | ------------ |
| `MM/DD/YYYY` | `09/29/2021` |
| `YYYY-MM-DD` | `2021-09-29` |
| `MM/DD/YY` | `09/29/21` |
| `YYYYMMDD` | `20210929` |
## Single Number Request (GET)
```bash cURL theme={null}
curl --location --request GET \
'https://dataapi.dncscrub.com/v1.5/Data/EnhancedRND?phoneNumber=7075276405&date=20211109' \
--header 'loginId: YOUR_API_KEY'
```
```javascript JavaScript theme={null}
const response = await fetch(
"https://dataapi.dncscrub.com/v1.5/Data/EnhancedRND?phoneNumber=7075276405&date=20211109",
{
headers: { loginId: "YOUR_API_KEY" },
}
);
const result = await response.json();
```
```csharp C# theme={null}
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Add("loginId", "YOUR_API_KEY");
var response = await client.GetStringAsync(
"https://dataapi.dncscrub.com/v1.5/Data/EnhancedRND?phoneNumber=7075276405&date=20211109"
);
}
```
### Response
```json theme={null}
{
"PhoneNumber": "7075276405",
"IsReassigned": false,
"HasSafeHarbor": true,
"CCCIsReassigned": false,
"IsSandBox": false
}
```
## Multiple Number Request (POST)
For checking multiple numbers, use HTTP POST with a JSON body:
```bash theme={null}
curl --location --request POST \
'https://dataapi.dncscrub.com/v1.5/Data/EnhancedRND' \
--header 'loginId: YOUR_API_KEY' \
--header 'Content-Type: application/json' \
--data-raw '{
"Data": [
{ "phoneNumber": "7075276405", "date": "20211109" },
{ "phoneNumber": "5039367187", "date": "20211109" }
],
"UseSandbox": false,
"ProjId": "Demo"
}'
```
### Response
```json theme={null}
[
{
"PhoneNumber": "7075276405",
"IsReassigned": false,
"HasSafeHarbor": true,
"CCCIsReassigned": false,
"IsSandBox": false
},
{
"PhoneNumber": "5039367187",
"IsReassigned": false,
"HasSafeHarbor": true,
"CCCIsReassigned": false,
"IsSandBox": false
}
]
```
## Response Fields
| Field | Type | Description |
| ----------------- | ------------ | -------------------------------------------------------------------------------- |
| `PhoneNumber` | String | The phone number checked |
| `IsReassigned` | Boolean/null | Combined result: `true` = reassigned, `false` = not reassigned, `null` = unknown |
| `HasSafeHarbor` | Boolean | `true` if FCC safe harbor exemption may be available |
| `CCCIsReassigned` | Boolean/null | Result from CCC's carrier data only (for informational purposes) |
| `IsSandBox` | Boolean | `true` if response was generated in sandbox mode, `false` for production data |
## Data Source Comparison
| Feature | FCC RND | CCC Carrier Data | Authority Plus (Combined) |
| ---------------- | ---------------- | ---------------- | ------------------------- |
| Data Start Date | Jan 27, 2021 | July 2018 | July 2018 |
| Update Frequency | Monthly | Daily | Daily |
| Coverage | All FCC carriers | Major carriers | Best of both |
## Rate Limits
| Limit | Value |
| ------------------- | ----- |
| Numbers per request | 1,000 |
## Enhanced Features
Reassigned Authority Plus includes:
* Daily updates
* Enhanced accuracy for edge cases
* Extended historical data
## Use Cases
* Safe harbor required
* High-value compliance scenarios
* Enhanced audit trail requirements
* Consent dates go further back than January 2021
## Getting Started
[Schedule a meeting](https://www.dnc.com/schedule-meeting/) to:
1. Discuss your compliance requirements
2. Get pricing information
## Related APIs
Basic reassigned number API using FCC Reassigned Number Database.
Test phone numbers for development
# Reassigned Authority (POST)
Source: https://docs.dncscrub.com/api-reference/reassigned/authority-post
POST https://dataapi.dncscrub.com/v1.5/Data/TCPAAuthority
Check multiple phone numbers for reassignment since a given consent date
Check multiple phone numbers for reassignment since given consent dates using the TCPA Authority API. Use POST for batch processing up to 1,000 numbers per request.
For single number lookups, you can use the [GET
method](/api-reference/reassigned/authority-get) instead.
## Request
### Headers
Your API Key (LoginId from your DNCScrub account)
Must be `application/json`
### Request Body
Array of phone number and date pairs to check
10-digit North American phone number (without leading 1 or +)
Consent date in format `YYYYMMDD`, `MM/DD/YYYY`, `YYYY-MM-DD`, or
`MM/DD/YY`
(Optional) Set to `true` to use sandbox mode for testing (returns random
results)
## Example Request
```bash cURL theme={null}
curl --location --request POST \
'https://dataapi.dncscrub.com/v1.5/Data/TCPAAuthority' \
--header 'loginId: YOUR_API_KEY' \
--header 'Content-Type: application/json' \
--data-raw '{
"Data": [
{
"PhoneNumber": "7075276405",
"Date": "20210209"
},
{
"PhoneNumber": "5039367187",
"Date": "20210209"
}
]
}'
```
```javascript JavaScript theme={null}
const response = await fetch(
"https://dataapi.dncscrub.com/v1.5/Data/TCPAAuthority",
{
method: "POST",
headers: {
"Content-Type": "application/json",
loginId: "YOUR_API_KEY",
},
body: JSON.stringify({
Data: [
{ PhoneNumber: "7075276405", Date: "20210209" },
{ PhoneNumber: "5039367187", Date: "20210209" },
],
}),
}
);
const data = await response.json();
console.log(data);
```
```csharp C# theme={null}
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Add("loginId", "YOUR_API_KEY");
var requestData = new
{
Data = new[]
{
new { PhoneNumber = "7075276405", Date = "20210209" },
new { PhoneNumber = "5039367187", Date = "20210209" }
}
};
var content = new StringContent(
JsonSerializer.Serialize(requestData),
Encoding.UTF8,
"application/json"
);
var response = await client.PostAsync(
"https://dataapi.dncscrub.com/v1.5/Data/TCPAAuthority",
content
);
var result = await response.Content.ReadAsStringAsync();
Console.WriteLine(result);
}
```
```json Response theme={null}
[
{
"PhoneNumber": "7075276405",
"IsReassigned": false,
"IsValid": true,
"LineType": "Landline",
"Carrier": "AT&T California",
"Locale": "Santa Rosa",
"Region": "CA",
"Country": "US",
"TZ": "America/Los_Angeles",
"UTCOffset": "-420"
},
{
"PhoneNumber": "5039367187",
"IsReassigned": false,
"IsValid": true,
"LineType": "Wireless",
"Carrier": "Verizon Wireless",
"Locale": "Portland",
"Region": "OR",
"Country": "US",
"TZ": "America/Los_Angeles",
"UTCOffset": "-420"
}
]
```
## Response Fields
Each object in the response array contains:
The phone number that was checked
Indicates if the phone was reassigned after the consent date: - `true` -
Reassigned after the date. **Do not call.** - `false` - Not reassigned. Safe
to call. - `null` - Insufficient information to determine reassignment status.
`true` if the phone number is valid and callable, `false` if not valid
Type of phone line: `Wireless`, `VoIP`, `Landline`, `Paging`, or `Unknown`
Original carrier the phone number was assigned to
City based on original phone number assignment
State/region based on original phone number assignment
Two-digit ISO country code
Timezone in ISO IANA format (e.g., `America/Los_Angeles`)
UTC offset in minutes
## Error Responses
| Status | Description |
| ---------------- | ----------------------------------------------------------- |
| 400 Bad Request | Invalid request body, phone number format, or date format |
| 401 Unauthorized | Invalid or missing API key |
| 403 Forbidden | Account not authorized for this API or insufficient credits |
## Batch Processing Example
```javascript theme={null}
async function checkReassignedNumbers(phoneRecords) {
const response = await fetch(
"https://dataapi.dncscrub.com/v1.5/Data/TCPAAuthority",
{
method: "POST",
headers: {
"Content-Type": "application/json",
loginId: "YOUR_API_KEY",
},
body: JSON.stringify({ Data: phoneRecords }),
}
);
const results = await response.json();
// Categorize results
const safeToCall = results.filter((r) => r.IsReassigned === false);
const doNotCall = results.filter((r) => r.IsReassigned === true);
const unknown = results.filter((r) => r.IsReassigned === null);
return {
safeToCall: safeToCall.map((r) => r.PhoneNumber),
doNotCall: doNotCall.map((r) => r.PhoneNumber),
unknown: unknown.map((r) => r.PhoneNumber),
};
}
// Usage
const records = [
{ PhoneNumber: "7075276405", Date: "20210209" },
{ PhoneNumber: "5039367187", Date: "20210209" },
];
const result = await checkReassignedNumbers(records);
console.log("Safe to call:", result.safeToCall.length);
console.log("Do not call:", result.doNotCall.length);
```
# Reassigned Authority Plus (GET)
Source: https://docs.dncscrub.com/api-reference/reassigned/enhanced-rnd-get
GET https://dataapi.dncscrub.com/v1.5/Data/EnhancedRND
Reassigned Authority Plus - Enhanced reassigned number check combining carrier and FCC data
Reassigned Authority Plus (Enhanced RND) combines CCC's authoritative carrier data with the FCC Reassigned Number Database to provide the most accurate reassignment determination available.
**Why Authority Plus?** The FCC Reassigned Number Database only has data from
January 27, 2021. CCC's carrier data goes back to **July 2018** and is updated
**daily** (vs monthly for FCC data).
## Request
### Headers
Your API Key (LoginId from your DNCScrub account)
### Query Parameters
10-digit North American phone number (without leading 1 or +)
Consent date to check reassignment against. Supported formats: `MM/DD/YYYY`,
`YYYY-MM-DD`, `MM/DD/YY`, or `YYYYMMDD`
(Optional) Set to `true` to use sandbox mode for testing (returns random
results)
Project identifier for tracking purposes
## Example Request
```bash cURL theme={null}
curl --location --request GET \
'https://dataapi.dncscrub.com/v1.5/Data/EnhancedRND?phoneNumber=7075276405&date=20211109' \
--header 'loginId: YOUR_API_KEY'
```
```javascript JavaScript theme={null}
const response = await fetch(
"https://dataapi.dncscrub.com/v1.5/Data/EnhancedRND?phoneNumber=7075276405&date=20211109",
{
method: "GET",
headers: { loginId: "YOUR_API_KEY" },
}
);
const data = await response.json();
console.log(data);
```
```csharp C# theme={null}
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Add("loginId", "YOUR_API_KEY");
var url = "https://dataapi.dncscrub.com/v1.5/Data/EnhancedRND?phoneNumber=7075276405&date=20211109";
var response = await client.GetStringAsync(url);
Console.WriteLine(response);
}
```
```json Response theme={null}
{
"PhoneNumber": "7075276405",
"IsReassigned": false,
"HasSafeHarbor": true,
"CCCIsReassigned": false,
"IsSandBox": false
}
```
## Response Fields
The phone number that was checked
**Combined result** from FCC Reassigned Number Database plus CCC's carrier
data. This is the field you should use to determine if to place the call: -
`true` - Reassigned. **Do not call.** - `false` - Not reassigned. Safe to
call. - `null` - Insufficient information from both sources.
`true` if an FCC safe harbor exemption may be available
Result from CCC's internal carrier data only. **For informational purposes
only** - use `IsReassigned` for your call decision.
`true` if the response was generated in sandbox mode (test data), `false` for production data.
## Error Responses
| Status | Description |
| ---------------- | -------------------------------------------------------------------------------- |
| 400 Bad Request | Invalid phone number format, invalid date format, or missing required parameters |
| 401 Unauthorized | Invalid or missing API key |
## Data Source Comparison
| Feature | FCC RND | CCC Carrier Data | Enhanced RND (Combined) |
| ---------------- | ----------------------------- | --------------------- | ----------------------- |
| Data Start Date | Jan 27, 2021 | July 2018 | July 2018 |
| Update Frequency | Monthly | Daily | Daily |
| Coverage | All carriers reporting to FCC | Major mobile carriers | Best of both |
## Processing the Response
```javascript theme={null}
const result = await response.json();
// Always use IsReassigned for call decisions (combined result)
if (result.IsReassigned === true) {
console.log("DO NOT CALL - Number has been reassigned");
} else if (result.IsReassigned === false) {
console.log("Safe to call");
if (result.HasSafeHarbor) {
console.log("FCC Safe Harbor protection available");
}
} else {
console.log("Unable to determine - insufficient data");
}
// CCCIsReassigned is for informational/debugging purposes
console.log(`CCC internal data says: ${result.CCCIsReassigned}`);
```
# Reassigned Authority Plus (POST)
Source: https://docs.dncscrub.com/api-reference/reassigned/enhanced-rnd-post
POST https://dataapi.dncscrub.com/v1.5/Data/EnhancedRND
Reassigned Authority Plus - Enhanced reassigned number check combining carrier and FCC data
Batch check multiple phone numbers using TCPA Authority Plus (Enhanced RND), which combines CCC's authoritative carrier data with the FCC Reassigned Number Database.
For single number lookups, use the [GET
method](/api-reference/reassigned/enhanced-rnd-get) instead.
## Request
### Headers
Your API Key (LoginId from your DNCScrub account)
Must be `application/json`
### Request Body
Array of phone number objects to check (maximum 1,000 per request)
10-digit North American phone number (without leading 1 or +)
Consent date in format `YYYYMMDD`, `MM/DD/YYYY`, `YYYY-MM-DD`, or `MM/DD/YY`
(Optional) Set to `true` to use sandbox mode for testing
Project identifier for tracking purposes
## Example Request
```bash cURL theme={null}
curl --location --request POST \
'https://dataapi.dncscrub.com/v1.5/Data/EnhancedRND' \
--header 'loginId: YOUR_API_KEY' \
--header 'Content-Type: application/json' \
--data-raw '{
"Data": [
{ "phoneNumber": "7075276405", "date": "20211109" },
{ "phoneNumber": "5039367187", "date": "20211109" }
]
}'
```
```javascript JavaScript theme={null}
const response = await fetch(
"https://dataapi.dncscrub.com/v1.5/Data/EnhancedRND",
{
method: "POST",
headers: {
"Content-Type": "application/json",
loginId: "YOUR_API_KEY",
},
body: JSON.stringify({
Data: [
{ phoneNumber: "7075276405", date: "20211109" },
{ phoneNumber: "5039367187", date: "20211109" },
],
}),
}
);
const data = await response.json();
console.log(data);
```
```csharp C# theme={null}
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Add("loginId", "YOUR_API_KEY");
var requestData = new
{
Data = new[]
{
new { phoneNumber = "7075276405", date = "20211109" },
new { phoneNumber = "5039367187", date = "20211109" }
}
};
var content = new StringContent(
JsonSerializer.Serialize(requestData),
Encoding.UTF8,
"application/json"
);
var response = await client.PostAsync(
"https://dataapi.dncscrub.com/v1.5/Data/EnhancedRND",
content
);
var result = await response.Content.ReadAsStringAsync();
Console.WriteLine(result);
}
```
```json Response theme={null}
[
{
"PhoneNumber": "7075276405",
"IsReassigned": false,
"HasSafeHarbor": true,
"CCCIsReassigned": false,
"IsSandBox": false
},
{
"PhoneNumber": "5039367187",
"IsReassigned": false,
"HasSafeHarbor": true,
"CCCIsReassigned": false,
"IsSandBox": false
}
]
```
## Response Fields
Each object in the response array contains:
The phone number that was checked
**Combined result** - use this field to determine if to place the call: -
`true` - Reassigned. **Do not call.** - `false` - Not reassigned. Safe to
call. - `null` - Insufficient information.
`true` if an FCC safe harbor exemption may be available
Result from CCC's carrier data only. For informational purposes.
`true` if the response was generated in sandbox mode (test data), `false` for production data.
## Error Responses
| Status | Description |
| ---------------- | ------------------------------------------------------------------------------------------------------------ |
| 400 Bad Request | Invalid request - missing/empty `Data` property, more than 1,000 phone numbers, or invalid phone/date format |
| 401 Unauthorized | Invalid or missing API key |
## Batch Processing Example
```javascript theme={null}
async function checkEnhancedRND(phoneRecords) {
const response = await fetch(
"https://dataapi.dncscrub.com/v1.5/Data/EnhancedRND",
{
method: "POST",
headers: {
"Content-Type": "application/json",
loginId: "YOUR_API_KEY",
},
body: JSON.stringify({ Data: phoneRecords }),
}
);
const results = await response.json();
// Categorize by IsReassigned (the combined result)
const safeToCall = results.filter((r) => r.IsReassigned === false);
const doNotCall = results.filter((r) => r.IsReassigned === true);
const unknown = results.filter((r) => r.IsReassigned === null);
// Numbers with safe harbor protection
const withSafeHarbor = safeToCall.filter((r) => r.HasSafeHarbor);
return {
safeToCall: safeToCall.map((r) => r.PhoneNumber),
doNotCall: doNotCall.map((r) => r.PhoneNumber),
unknown: unknown.map((r) => r.PhoneNumber),
safeHarborCount: withSafeHarbor.length,
};
}
// Usage
const records = [
{ phoneNumber: "7075276405", date: "20211109" },
{ phoneNumber: "5039367187", date: "20211109" },
];
const result = await checkEnhancedRND(records);
console.log(`Safe to call: ${result.safeToCall.length}`);
console.log(`With safe harbor: ${result.safeHarborCount}`);
```
# File Formats
Source: https://docs.dncscrub.com/api-reference/reassigned/file-formats
Batch file processing formats for TCPA reassignment checking
# TCPA File Formats
For high-volume batch processing, you can submit files for reassignment checking instead of using the real-time API.
For complete file format specifications, contact [support@dnc.com](mailto:support@dnc.com).
## Available File Formats
### RND Basic File Format
For basic reassigned number checking:
* CSV format
* Phone number and consent date columns
* Batch processing with results file
### TCPA Authority File Format
For full TCPA Authority checking:
* CSV or delimited format
* Multiple date formats supported
* Comprehensive result data
### TCPA Authority Plus File Format
Enhanced format with additional fields:
* Extended data columns
* Reference ID support
* Enhanced result fields
## File Processing Workflow
Format your file according to the specification with phone numbers and consent dates.
Upload via the DNCScrub portal or SFTP.
Files are processed and results are generated.
Retrieve your results file with reassignment status for each number.
## Sample File Structure
```csv theme={null}
PhoneNumber,ConsentDate,ReferenceId
7075276405,2021-02-09,ACCT-001
5039367187,2021-03-15,ACCT-002
7072842774,2020-12-01,ACCT-003
```
## Getting Started
Contact support to receive:
* Complete file format specifications
* SFTP credentials (if applicable)
* Processing schedule information
# Reassigned Scrub
Source: https://docs.dncscrub.com/api-reference/reassigned/overview
APIs for identifying reassigned phone numbers and maintaining TCPA compliance
# TCPA & Reassigned Numbers
In a number of scenarios the TCPA (Telephone Consumer Protection Act) requires businesses to have consent before calling consumers. When a phone number is reassigned to a new person, your previous consent is no longer valid as consent is tied to an individual, not a specific phone number.
Our Reassigned Authority APIs help you identify reassigned phone numbers to maintain compliance.
## Why Reassigned Number Detection Matters
Calling a reassigned number without the new owner's consent can result in
**TCPA violations** with statutory damages of \$500–\$1,500 per call plus the
consumer can file a private right of action lawsuit.
When a consumer gives you consent to call them, that consent is tied to:
* That specific person
* That specific phone number
If the number is later reassigned to someone else, you no longer have consent to call it.
## Available APIs
Enhanced reassigned number detection with additional data points. Uses both
the FCC Reassigned Number Database plus more frequently updated carrier
deactivation data. Goes further back than the FCC Reassigned Number
Database.
Basic reassigned number data using only the FCC's Reassigned Number
database.
Reassigned number detection based on carrier deactivation data.
## File Formats for SFTP or Web Portal
Batch file processing formats for bulk reassignment checking doing via SFTP or
Web Portal
## How It Works
1. **Store the consent date** when a consumer gives you permission to call
2. **Before calling**, check if the number has been reassigned since that date
3. **If reassigned**, do not call - the number now belongs to someone else
## Example Workflow
```javascript theme={null}
// When consumer provides consent
const consentRecord = {
phoneNumber: "7075276405",
consentDate: "2023-06-15",
consentType: "written",
};
// Before calling, check if reassigned
const response = await fetch(
`https://dataapi.dncscrub.com/v1.5/Data/TCPAAuthority?phoneNumber=${consentRecord.phoneNumber}&date=${consentRecord.consentDate}`,
{
headers: { loginId: "YOUR_API_KEY" },
}
);
const result = await response.json();
if (result.IsReassigned === true) {
console.log("DO NOT CALL - Number has been reassigned");
} else if (result.IsReassigned === false) {
console.log("Safe to call - Number has not been reassigned");
} else {
console.log("Unable to determine - Proceed with caution");
}
```
## Key Response Values
| IsReassigned | Meaning | Action |
| ------------ | -------------------------------------------- | --------------- |
| `true` | Number was reassigned after the consent date | **Do not call** |
| `false` | Number has not been reassigned | Safe to call |
| `null` | Insufficient data to determine | Use caution |
## Additional Information Returned
The TCPA Authority API also returns useful phone number information:
* **Line Type** - Wireless, VoIP, Landline, or Paging
* **Carrier** - Original carrier assignment
* **Location** - City, region, country
* **Timezone** - For calling time compliance
## Example Use Case
The following diagram illustrates a common workflow for businesses collecting opt-in leads, showing how both the [Litigator API](/api-reference/litigator/overview) and Reassigned Authority API work together to maintain TCPA compliance:
### Workflow Summary
1. **At checkout** - When a customer opts in to receive marketing messages, immediately scrub against the Litigator List to avoid known litigators
2. **Save the lead** - Store the opt-in with the consent date
3. **Wait 30 days** - Phone numbers can be reassigned at any time; waiting helps identify reassignments
4. **Scrub against Reassigned List** - Before contacting, check if the number has been reassigned since consent was given
5. **Optional re-check** - Scrub against the Litigator List again (litigator status can change)
6. **Repeat monthly** - Continue this process every 30 days to maintain compliance
# RND Basic API
Source: https://docs.dncscrub.com/api-reference/reassigned/rnd-basic
Basic Reassigned Number Database API
# RND Basic API
The RND (Reassigned Number Database) Basic API provides a streamlined interface for checking if phone numbers have been reassigned using the FCC Reassigned Number Database.
## Endpoint
```
https://dataapi.dncscrub.com/v1.5/Data/RNDBasic
```
## Authentication
Include your API key in the `loginId` HTTP header:
```bash theme={null}
--header 'loginId: YOUR_API_KEY'
```
## Parameters
| Parameter | Required | Description |
| ------------- | -------- | ---------------------------------------------------------------------- |
| `phoneNumber` | Yes | 10-digit phone number (no leading 1 or +) |
| `date` | Yes | Consent date to check against |
| `useSandbox` | No | Set to `true` to use sandbox mode for testing (returns random results) |
| `projId` | No | Project identifier for tracking purposes |
### Date Formats
The `date` parameter accepts multiple formats:
| Format | Example |
| ------------ | ------------ |
| `MM/DD/YYYY` | `09/29/2021` |
| `YYYY-MM-DD` | `2021-09-29` |
| `MM/DD/YY` | `09/29/21` |
| `YYYYMMDD` | `20210929` |
## Single Number Request (GET)
```bash cURL theme={null}
curl --location --request GET \
'https://dataapi.dncscrub.com/v1.5/Data/RNDBasic?phoneNumber=7075276405&date=20211109' \
--header 'loginId: YOUR_API_KEY'
```
```javascript JavaScript theme={null}
const response = await fetch(
"https://dataapi.dncscrub.com/v1.5/Data/RNDBasic?phoneNumber=7075276405&date=20211109",
{
headers: { loginId: "YOUR_API_KEY" },
}
);
const result = await response.json();
```
```csharp C# theme={null}
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Add("loginId", "YOUR_API_KEY");
var response = await client.GetStringAsync(
"https://dataapi.dncscrub.com/v1.5/Data/RNDBasic?phoneNumber=7075276405&date=20211109"
);
}
```
### Response
```json theme={null}
{
"PhoneNumber": "7075276405",
"IsReassigned": false,
"HasSafeHarbor": true,
"IsSandBox": false
}
```
## Multiple Number Request (POST)
For checking multiple numbers, use HTTP POST with a JSON body:
```bash theme={null}
curl --location --request POST \
'https://dataapi.dncscrub.com/v1.5/Data/RNDBasic' \
--header 'loginId: YOUR_API_KEY' \
--header 'Content-Type: application/json' \
--data-raw '{
"Data": [
{ "phoneNumber": "7075276405", "date": "20211109" },
{ "phoneNumber": "5039367187", "date": "20211109" }
],
"UseSandbox": false,
"ProjId": "Demo"
}'
```
### Response
```json theme={null}
[
{
"PhoneNumber": "7075276405",
"IsReassigned": false,
"HasSafeHarbor": true,
"IsSandBox": false
},
{
"PhoneNumber": "5039367187",
"IsReassigned": false,
"HasSafeHarbor": true,
"IsSandBox": false
}
]
```
## Response Fields
| Field | Type | Description |
| --------------- | ------------ | ----------------------------------------------------------------------------- |
| `PhoneNumber` | String | The phone number checked |
| `IsReassigned` | Boolean/null | `true` = reassigned, `false` = not reassigned, `null` = unknown |
| `HasSafeHarbor` | Boolean | `true` if FCC safe harbor exemption may be available |
| `IsSandBox` | Boolean | `true` if response was generated in sandbox mode, `false` for production data |
## Rate Limits
| Limit | Value |
| ------------------- | ----- |
| Numbers per request | 1,000 |
## Use Cases
* Basic reassignment detection
* Cost-effective compliance checking
* Safe harbor verification
## Getting Started
Contact our support team to:
1. Get your API credentials
2. Access Postman collection samples
## Related Documentation
Enhanced reassigned number API with carrier data and extended historical coverage
Test phone numbers for development
# RND Basic (GET)
Source: https://docs.dncscrub.com/api-reference/reassigned/rnd-basic-get
GET https://dataapi.dncscrub.com/v1.5/Data/RNDBasic
Query the FCC Reassigned Number Database for single number lookup
Query the FCC Reassigned Number Database (RND) to check if a phone number has been reassigned after a given date.
The FCC Reassigned Number Database only has complete data after **January 27,
2021**. Numbers with consent dates prior to this date will typically return a
blank `IsReassigned` value indicating insufficient data.
## Request
### Headers
Your API Key (LoginId from your DNCScrub account)
### Query Parameters
10-digit North American phone number (without leading 1 or +)
Consent date to check reassignment against. Supported formats: `MM/DD/YYYY`,
`YYYY-MM-DD`, `MM/DD/YY`, or `YYYYMMDD`
(Optional) Set to `true` to use sandbox mode for testing (returns random
results)
Project identifier for tracking purposes
## Example Request
```bash cURL theme={null}
curl --location --request GET \
'https://dataapi.dncscrub.com/v1.5/Data/RNDBasic?phoneNumber=7075276405&date=20211109' \
--header 'loginId: YOUR_API_KEY'
```
```javascript JavaScript theme={null}
const response = await fetch(
"https://dataapi.dncscrub.com/v1.5/Data/RNDBasic?phoneNumber=7075276405&date=20211109",
{
method: "GET",
headers: { loginId: "YOUR_API_KEY" },
}
);
const data = await response.json();
console.log(data);
```
```csharp C# theme={null}
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Add("loginId", "YOUR_API_KEY");
var url = "https://dataapi.dncscrub.com/v1.5/Data/RNDBasic?phoneNumber=7075276405&date=20211109";
var response = await client.GetStringAsync(url);
Console.WriteLine(response);
}
```
```json Response theme={null}
{
"PhoneNumber": "7075276405",
"IsReassigned": false,
"HasSafeHarbor": true,
"IsSandBox": false
}
```
## Response Fields
The phone number that was checked
Indicates if the phone was reassigned after the consent date based on FCC
data: - `true` (or `1`) - Reassigned after the date. **Do not call.** -
`false` (or `0`) - Not reassigned. - `null` (blank) - Insufficient data in the
FCC database to determine.
`true` if an FCC safe harbor exemption may be available for this number
`true` if the response was generated in sandbox mode (test data), `false` for production data.
## Error Responses
| Status Code | Description |
| ---------------- | -------------------------------------------------------------------------------- |
| 400 Bad Request | Invalid phone number format, invalid date format, or missing required parameters |
| 401 Unauthorized | Invalid or missing API key |
## Processing the Response
```javascript theme={null}
const result = await response.json();
if (result.IsReassigned === true) {
console.log("DO NOT CALL - Number has been reassigned per FCC data");
} else if (result.IsReassigned === false) {
console.log("Safe to call - Number has not been reassigned");
if (result.HasSafeHarbor) {
console.log("FCC Safe Harbor exemption may be available");
}
} else {
console.log(
"Insufficient FCC data - consider using TCPA Authority for older consent dates"
);
}
```
## When to Use RND Basic vs TCPA Authority
| Feature | RND Basic | TCPA Authority |
| ---------------- | ----------------------------------- | -------------------------------------- |
| Data Source | FCC Reassigned Number Database only | Carrier data + FCC data |
| Data Coverage | January 27, 2021 onwards | July 2018 onwards |
| Update Frequency | Monthly | Daily |
| Additional Data | Safe harbor only | Line type, carrier, location, timezone |
| Cost | Lower | Higher |
For comprehensive coverage, especially with older consent dates, consider using [TCPA Authority](/api-reference/reassigned/authority-get) instead.
# RND Basic (POST)
Source: https://docs.dncscrub.com/api-reference/reassigned/rnd-basic-post
POST https://dataapi.dncscrub.com/v1.5/Data/RNDBasic
Batch query the FCC Reassigned Number Database
Batch query the FCC Reassigned Number Database (RND) to check if multiple phone numbers have been reassigned after given dates.
The FCC Reassigned Number Database only has complete data after **January 27, 2021**. Numbers with consent dates prior to this date will typically return a blank `IsReassigned` value.
## Request
### Headers
Your API Key (LoginId from your DNCScrub account)
Must be `application/json`
### Request Body
Array of phone number objects to check (maximum 1,000 per request)
10-digit North American phone number (without leading 1 or +)
Consent date in format `YYYYMMDD`, `MM/DD/YYYY`, `YYYY-MM-DD`, or `MM/DD/YY`
(Optional) Set to `true` to use sandbox mode for testing
Project identifier for tracking purposes
## Example Request
```bash cURL theme={null}
curl --location --request POST \
'https://dataapi.dncscrub.com/v1.5/Data/RNDBasic' \
--header 'loginId: YOUR_API_KEY' \
--header 'Content-Type: application/json' \
--data-raw '{
"Data": [
{ "phoneNumber": "5039367187", "date": "20211014" },
{ "phoneNumber": "7075276405", "date": "20211122" }
]
}'
```
```javascript JavaScript theme={null}
const response = await fetch(
'https://dataapi.dncscrub.com/v1.5/Data/RNDBasic',
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
'loginId': 'YOUR_API_KEY'
},
body: JSON.stringify({
Data: [
{ phoneNumber: '5039367187', date: '20211014' },
{ phoneNumber: '7075276405', date: '20211122' }
]
})
}
);
const data = await response.json();
console.log(data);
```
```csharp C# theme={null}
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Add("loginId", "YOUR_API_KEY");
var requestData = new
{
Data = new[]
{
new { phoneNumber = "5039367187", date = "20211014" },
new { phoneNumber = "7075276405", date = "20211122" }
}
};
var content = new StringContent(
JsonSerializer.Serialize(requestData),
Encoding.UTF8,
"application/json"
);
var response = await client.PostAsync(
"https://dataapi.dncscrub.com/v1.5/Data/RNDBasic",
content
);
var result = await response.Content.ReadAsStringAsync();
Console.WriteLine(result);
}
```
```json Response theme={null}
[
{
"PhoneNumber": "5039367187",
"IsReassigned": false,
"HasSafeHarbor": true,
"IsSandBox": false
},
{
"PhoneNumber": "7075276405",
"IsReassigned": false,
"HasSafeHarbor": true,
"IsSandBox": false
}
]
```
## Response Fields
Each object in the response array contains:
The phone number that was checked
Indicates if the phone was reassigned after the consent date:
* `true` - Reassigned. **Do not call.**
* `false` - Not reassigned.
* `null` - Insufficient FCC data.
`true` if an FCC safe harbor exemption may be available
`true` if the response was generated in sandbox mode (test data), `false` for production data.
## Error Responses
| Status Code | Description |
| ---------------- | ----------------------------------------------------------------------------------------------------------- |
| 400 Bad Request | The `data` property is missing or empty, more than 1,000 phone numbers, or invalid phone number/date format |
| 401 Unauthorized | Invalid or missing API key |
## Batch Processing Example
```javascript theme={null}
async function checkRNDBasic(phoneRecords) {
const response = await fetch(
'https://dataapi.dncscrub.com/v1.5/Data/RNDBasic',
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
'loginId': 'YOUR_API_KEY'
},
body: JSON.stringify({ data: phoneRecords })
}
);
const results = await response.json();
// Categorize results
const safeToCall = results.filter(r => r.IsReassigned === false);
const doNotCall = results.filter(r => r.IsReassigned === true);
const unknown = results.filter(r => r.IsReassigned === null);
console.log(`Safe: ${safeToCall.length}`);
console.log(`Do Not Call: ${doNotCall.length}`);
console.log(`Unknown (insufficient FCC data): ${unknown.length}`);
return { safeToCall, doNotCall, unknown };
}
// Usage
const records = [
{ phoneNumber: '5039367187', date: '20211014' },
{ phoneNumber: '7075276405', date: '20211122' }
];
await checkRNDBasic(records);
```
# Test Numbers
Source: https://docs.dncscrub.com/api-reference/reassigned/test-numbers
Test phone numbers for Reassigned Authority Plus or Basic RND API development
# Reassigned Authority Plus and Basic RND Test Numbers
Use these test phone numbers during development to verify your integration with the Reassigned Authority Plus or Basic RND APIs.
These test numbers work regardless if the sandbox is used. Querying these
numbers will incur a billable event unless you are using the sandbox.
## Numbers That Return Reassigned
These phone numbers always return as reassigned regardless of the date:
| Phone Number |
| ------------ |
| 5555551212 |
| 5555551234 |
| 5555554321 |
| 5555559876 |
| 5555558765 |
| 5555555678 |
| 5555558769 |
| 5555557654 |
## Numbers That Return Not Reassigned
These phone numbers always return as not reassigned regardless of the date:
| Phone Number |
| ------------ |
| 5556551234 |
| 5556554321 |
| 5556559876 |
| 5556558765 |
| 5556555678 |
| 5556558769 |
| 5556557654 |
## Example Requests
### Reassigned Number Example
```bash theme={null}
curl --location 'https://dataapi.dncscrub.com/v1.5/Data/EnhancedRND' \
--header 'loginId: {loginId}' \
--header 'Content-Type: application/json' \
--data '{
"UseSandbox": true,
"ProjId": "DVLP01",
"Data": [
{
"phoneNumber": "5555551212",
"date": "20220807"
}
]
}'
```
**Response:**
```json theme={null}
[
{
"PhoneNumber": "5555551212",
"IsReassigned": true,
"HasSafeHarbor": false,
"CCCIsReassigned": true
}
]
```
### Not Reassigned Number Example
```bash theme={null}
curl --location 'https://dataapi.dncscrub.com/v1.5/Data/EnhancedRND' \
--header 'loginId: {loginId}' \
--header 'Content-Type: application/json' \
--data '{
"UseSandbox": true,
"ProjId": "DVLP01",
"Data": [
{
"phoneNumber": "5556551234",
"date": "20220807"
}
]
}'
```
**Response:**
```json theme={null}
[
{
"PhoneNumber": "5556551234",
"IsReassigned": false,
"HasSafeHarbor": true,
"CCCIsReassigned": false
}
]
```
## Testing Best Practices
Make sure to test both reassigned and not reassigned responses to ensure
your application handles each case correctly.
Test with various date formats to ensure your system correctly formats dates
for the API.
# Compliance for AI Voice Agents
Source: https://docs.dncscrub.com/api-reference/scrub/ai-voice-agents
One API call tells your AI dialer whether it may place this call right now — consent, DNC, wireless, holidays and calling hours, resolved to a single flag
AI voice agents are the most tightly regulated way to place an outbound call.
The FCC ruled in February 2024 that an AI-generated voice is an *artificial
voice* under the TCPA. That puts every AI marketing call under 47 U.S.C.
§227(b): **prior express written consent from the person called, for wireless
and residential landlines alike, with no existing-business-relationship
exemption.** Get it wrong and the exposure is \$500–\$1,500 per call, class-wide.
DNCScrub already holds the three things an AI dialer needs to answer "may I
place this call right now?": the consent you captured, every DNC list, and the
destination's calling hours. With `version=8` the Scrub API returns that answer
as one field, `IsCallAllowedAI`.
Save express written consent as a Permission EBR the moment you capture it
Scrub before dialing; place the call only when `IsCallAllowedAI` is `true`
Add to Internal DNC when the consumer says stop — the next scrub returns `0`
## What `IsCallAllowedAI` checks
`IsCallAllowedAI` is `true` only when **every** row below is satisfied. The flag is
computed per number at scrub time.
| Check | Condition for `1` | Source of truth |
| --------------------------------- | ------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------- |
| Express written consent | A **Permission (`P`) EBR** is on file for this number and campaign (`EBRType` is `P`) | Consent you stored via the [EBR and Consent API](/api-reference/scrub/ebr-list) |
| Consent still valid | `ResultCode` is `E`, `O`, `G` or `H` — the consent is current and not superseded by a later opt-out | EBR expiry rules, Internal DNC precedence |
| Not on a DNC list without consent | Implied by the above — a number on the National/State DNC with valid consent returns `O`; without consent returns `D` → `false` | National DNC, state DNC lists, Internal DNC, litigator lists |
| Wireless-prohibited states | `ResultCode` is not `L`, `F` or `V` (`L` cannot occur with consent on file, listed for consistency with the other flags) | State law (WY, NJ, TX, LA, AZ) |
| Holidays and emergencies | `DoNotCallToday` is `false` | State restricted holidays, declared states of emergency |
| Calling hours | The destination's current local time is inside `CallingWindow` | State and federal calling windows, DST, and — when you pass a postal code — the contact's actual location |
Anything else returns `false`. In particular:
* A clean number with **no** consent on file (`ResultCode` `C`) is `false`. Clean is
not consent.
* A Sale (`S`) or Inquiry (`I`) EBR is `false`. An EBR is a DNC exemption, not
consent for an artificial voice.
* Wireless and VoIP numbers are `true` when a Permission EBR is on file. Express
written consent covers §227(b) for wireless.
`IsCallAllowedAI` is the strictest of the three `version=8` flags. If your
agent is `true` here it is also `true` for `IsCallAllowedATDS` and
`IsCallAllowedNonATDS`. See [Is the call
allowed?](/api-reference/scrub/output-guide#is-the-call-allowed) for how the
three relate.
## The loop
When the consumer opts in (web form, checkbox with the required
disclosures, signed agreement), write it to DNCScrub immediately. Set
`dateOfLastContact` to the date consent was given and keep your evidence
reference in `referenceNum`.
```bash theme={null}
curl --request POST 'https://www.dncscrub.com/app/main/rpc/ebr' \
--header 'loginId: YOUR_API_KEY' \
--header 'Content-Type: application/json' \
--data '{
"ebrList": [{
"phoneNumber": "5039367181",
"type": "P",
"dateOfLastContact": "2026-08-15",
"referenceNum": "consent-form-84213"
}]
}'
```
You can also do this in the same request as the scrub — see
[Scrub + Add EBR](/api-reference/scrub/scrub-ebr).
Immediately before the agent dials, scrub the number with `version=8`.
Pass the contact's postal code as the third pipe field so calling hours
follow where the person actually is, not where their area code was
assigned.
```bash theme={null}
curl 'https://www.dncscrub.com/app/main/rpc/scrub?phoneList=5039367181|lead-8841|10001&version=8&output=json' \
--header 'loginId: YOUR_API_KEY'
```
Place the call only if `IsCallAllowedAI` is `true`.
When the consumer asks not to be called again, add the number to your
[Internal DNC](/api-reference/scrub/internal-dnc). Because the Internal DNC
entry is newer than the consent, the next scrub returns `IsCallAllowedAI`
`false` — no code change on your side. See [Opt-outs and
opt-ins](/api-reference/scrub/opt-outs-and-opt-ins) for the precedence
rules.
## Example
A consumer who gave express written consent on 2026-08-15, scrubbed from an AI
agent at 2 PM Eastern with their postal code:
```python Python theme={null}
import requests
def may_ai_call(phone: str, lead_id: str, postal_code: str) -> bool:
r = requests.get(
"https://www.dncscrub.com/app/main/rpc/scrub",
params={
"phoneList": f"{phone}|{lead_id}|{postal_code}",
"version": "8",
"output": "json",
},
headers={"loginId": "YOUR_API_KEY"},
timeout=10,
)
r.raise_for_status()
result = r.json()["results"][0]
return result["IsCallAllowedAI"] is True
if may_ai_call("5039367181", "lead-8841", "10001"):
start_ai_call("5039367181")
```
```javascript JavaScript theme={null}
const res = await fetch(
`https://www.dncscrub.com/app/main/rpc/scrub?phoneList=5039367181|lead-8841|10001&version=8&output=json`,
{ headers: { loginId: "YOUR_API_KEY" } }
);
const { results: [result] } = await res.json();
if (result.IsCallAllowedAI === true) {
await startAiCall("5039367181");
} else {
// Inspect result.ResultCode, result.EBRType, result.DoNotCallToday,
// result.CallingWindow to see which condition failed.
}
```
```json Consent on file theme={null}
{
"version": 8,
"results": [
{
"Phone": "5039367181",
"ResultCode": "G",
"Reserved": "lead-8841",
"Reason": ";;;W",
"RegionAbbrev": "OR",
"Country": "US",
"Locale": "Portland",
"CarrierInfo": "5820;WIRELESS;\"Verizon Wireless:Verizon Wireless\"",
"NewReassignedAreaCode": null,
"TZCode": 35,
"CallingWindow": "8:00-21:00;8:00-21:00;8:00-21:00",
"UTCOffset": -240,
"DoNotCallToday": false,
"CallingTimeRestrictions": 4,
"EBRType": "P",
"IsWirelessOrVoIP": true,
"LineType": "Wireless",
"EBRExpiresOn": null,
"WirelessPortDate": null,
"VoIPDate": null,
"PostalCode": "10001",
"TZSource": "postalCode",
"IsCallAllowedNonATDS": true,
"IsCallAllowedATDS": true,
"IsCallAllowedAI": true
}
]
}
```
```json No consent on file theme={null}
{
"version": 8,
"results": [
{
"Phone": "5039367181",
"ResultCode": "W",
"Reserved": "lead-8841",
"Reason": ";;;W",
"RegionAbbrev": "OR",
"Country": "US",
"Locale": "Portland",
"CarrierInfo": "5820;WIRELESS;\"Verizon Wireless:Verizon Wireless\"",
"NewReassignedAreaCode": null,
"TZCode": 35,
"CallingWindow": "8:00-21:00;8:00-21:00;8:00-21:00",
"UTCOffset": -240,
"DoNotCallToday": false,
"CallingTimeRestrictions": 4,
"EBRType": null,
"IsWirelessOrVoIP": true,
"LineType": "Wireless",
"EBRExpiresOn": null,
"WirelessPortDate": null,
"VoIPDate": null,
"PostalCode": "10001",
"TZSource": "postalCode",
"IsCallAllowedNonATDS": true,
"IsCallAllowedATDS": false,
"IsCallAllowedAI": false
}
]
}
```
Same number, same time. A live agent could dial it; an AI agent may not until
consent is on file.
## Building an agent framework or LLM tool?
* **Gate in the dialer loop, not in the model.** Call the REST endpoint
directly from the code that places the call, immediately before dialing. Do
not route the check through an LLM tool call — that adds seconds of latency
and puts a non-deterministic step in front of a compliance decision.
* **Deterministic, not advisory.** `IsCallAllowedAI` is computed from rules and
data, never from a model. Treat it as a hard gate in code, not as context for
the agent to reason about.
* **Cheap to call.** The flags add no database work; a single-number scrub is
one round trip. Scrub at dial time, every time — consent, DNC status and
calling hours all change.
* **Log the response.** Store the full scrub row with the call record. It is
your evidence that consent existed and hours were respected when the call was
placed.
## What this flag does not cover
Roughly 35 million US numbers are reassigned every year. If the number was
reassigned after your consent was captured, the consent came from someone
who no longer has that phone — and this flag cannot see that. Before
dialing on stored consent, check the number against the FCC Reassigned
Number Database via [Reassigned Authority
Plus](/api-reference/reassigned/authority-plus) (pass the consent date);
a clear result earns the FCC's safe harbor. This is a separate API call —
the Full Scrub API does not perform reassigned-number checks.
Several states (California, Utah, Colorado and others) and pending FCC rules
require that an artificial or AI caller identify itself and, in some cases,
disclose that the voice is synthetic. That concerns what the call *says*,
which the scrub cannot see. Build the disclosure into your agent's opening.
FCC rules require prerecorded and artificial-voice telemarketing calls to
offer an automated opt-out (for example, "press 9 or say stop") that
immediately ends the call and records the request. Wire that request to the
[Internal DNC](/api-reference/scrub/internal-dnc) API.
DNCScrub stores the fact that consent exists for a number and campaign. It
does not verify that the consent language named your brand, covered AI or
prerecorded calls, or satisfies a particular state's disclosure
requirements. Review your consent capture with counsel; store it as
Permission only when it meets the standard for the consumer's jurisdiction.
Appointment reminders, fraud alerts and similar informational calls have
different consent standards (prior express consent, not written). The flag
assumes a marketing call; a `0` does not by itself mean an informational
call is prohibited. Use `ResultCode`, `LineType` and `CallingWindow` and
apply your own policy.
Recording or transcribing the call is governed by state wiretap law, not
the TCPA, and is outside the scrub.
`IsCallAllowedAI` encodes DNC status, stored consent, line type and calling
hours — the data DNCScrub holds. It does not check whether the number has
been [reassigned](/api-reference/reassigned/authority-plus) since consent was
captured (see below). It is not legal advice and does not replace review of
your consent process and call scripts by counsel.
# EBR and Consent Master
Source: https://docs.dncscrub.com/api-reference/scrub/ebr-list
POST https://www.dncscrub.com/app/main/rpc/ebr
Manage Existing Business Relationship records
An Existing Business Relationship (EBR) provides an exemption to DNC rules under certain conditions. The EBR API allows you to add and manage EBR records for phone numbers. In addition the EBR API can be used to store Consent. A consent record is a Permission "P" EBR record — use this type whenever a consumer opts in with **express written consent** (for example, a signed web consent form or a consent checkbox with the required disclosures). You should ensure you have the proper consent from the customer for the customer's jurisdiction before sending this. This will allow you to contact the customer for the purposes of marketing and sales until you remove the Permission EBR or Add to Internal DNC.
Handling a consumer who opted out and later opts back in? See
[Handling Opt-Outs and Opt-Ins](/api-reference/scrub/opt-outs-and-opt-ins)
for how Permission EBRs and the Internal DNC list interact.
To add or refresh EBR records and scrub numbers in a single request, use
[Scrub + Add EBR](/api-reference/scrub/scrub-ebr) instead of calling this
endpoint separately.
## Request
### Headers
Your API Key
Must be `application/json`
### Request Body
When set to `1`, if an EBR record already exists for the phone number being
added and the existing EBR is "better" than the one being added, the existing
EBR will not be overwritten. Federal EBR expiration dates are used to
determine which EBR is better (longer remaining validity = better).
Array of EBR records to add.
10-digit phone number(s). For multiple numbers, comma-separate them (e.g., `"5039367187,7075276405"`).
EBR type:
* `S` - Sale/Purchase
* `I` - Inquiry
* `P` - Permission
* `T` - Trial (currently only for Newspaper Trials in North Dakota)
Date of last contact in `MM/DD/YYYY` format (e.g., `"11/11/2020"`).
Date when written obligation ends (New Jersey only).
Your internal tracking string.
Company/product/brand name used to establish the EBR.
Email address (100 characters max).
## Example Request
```bash cURL theme={null}
curl --location 'https://www.dncscrub.com/app/main/rpc/ebr' \
--header 'loginId: YOUR_API_KEY' \
--header 'Content-Type: application/json' \
--data '{
"ebrList": [
{
"phoneNumber": "5039367187",
"type": "I",
"dateOfLastContact": "11/11/2020"
}
]
}'
```
```javascript JavaScript theme={null}
const response = await fetch("https://www.dncscrub.com/app/main/rpc/ebr", {
method: "POST",
headers: {
loginId: "YOUR_API_KEY",
"Content-Type": "application/json",
},
body: JSON.stringify({
ebrList: [
{
phoneNumber: "5039367187",
type: "I",
dateOfLastContact: "11/11/2020",
},
],
}),
});
```
```csharp C# theme={null}
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Add("loginId", "YOUR_API_KEY");
var ebrData = new
{
ebrList = new[]
{
new
{
phoneNumber = "5039367187",
type = "I",
dateOfLastContact = "11/11/2020"
}
}
};
var content = new StringContent(
JsonSerializer.Serialize(ebrData),
Encoding.UTF8,
"application/json"
);
var response = await client.PostAsync(
"https://www.dncscrub.com/app/main/rpc/ebr",
content
);
}
```
```json Response (Success) theme={null}
{
"success": true
}
```
## Add Multiple EBRs
Add multiple EBR records in a single request:
```bash theme={null}
curl --location 'https://www.dncscrub.com/app/main/rpc/ebr' \
--header 'loginId: YOUR_API_KEY' \
--header 'Content-Type: application/json' \
--data '{
"ebrList": [
{
"phoneNumber": "5039367187",
"type": "S",
"dateOfLastContact": "06/14/2023"
},
{
"phoneNumber": "7072842774",
"type": "I",
"dateOfLastContact": "07/02/2023"
}
]
}'
```
This adds:
1. Phone `5039367187` with a Sale EBR dated 06/14/2023
2. Phone `7072842774` with an Inquiry EBR dated 07/02/2023
## Multiple Phone Numbers Per Record
You can also add the same EBR to multiple phone numbers in one record:
```json theme={null}
{
"ebrList": [
{
"phoneNumber": "5039367187,7075276405",
"type": "I",
"dateOfLastContact": "11/11/2020"
}
]
}
```
## Preserve Better EBR Records
Use `keepBetterEBR` to prevent overwriting existing EBR records that have longer remaining validity:
```json theme={null}
{
"keepBetterEBR": 1,
"ebrList": [
{
"phoneNumber": "5039367187",
"type": "I",
"dateOfLastContact": "11/11/2024"
}
]
}
```
When `keepBetterEBR` is set to `1`, the system compares federal and state EBR
expiration dates. If the existing EBR expires later than the new one would,
the existing record is preserved. This is useful when importing EBR data to
avoid accidentally downgrading your compliance coverage.
## Response
| Status Code | Meaning |
| ----------- | ----------------------------------------- |
| `200` | Success |
| `4xx` | Error - response body contains the reason |
## EBR Types
| Type | Description |
| ---- | ---------------------------------------------------------------------------------------------------------------------------------- |
| `S` | Sale/Purchase — consumer bought or transacted with you |
| `I` | Inquiry — consumer asked about your products or services |
| `P` | Permission — consumer gave **express written consent** to be contacted (opt-in). Only this type can override an Internal DNC entry |
| `T` | Trial (currently only for Newspaper Trials in North Dakota) |
## EBR Expiration
EBR exemptions expire based on federal rules:
| EBR Type | Expiration Period |
| ------------------- | --------------------------------------- |
| Sale/Purchase (`S`) | 18 months from date of last transaction |
| Inquiry (`I`) | 3 months from date of inquiry |
State rules may vary. Some states have shorter exemption periods or additional
requirements.
## Best Practices
Use the `referenceNum` parameter to store your internal tracking ID for
audit purposes.
The `dateOfLastContact` should be the actual date of the business
relationship event, not the current date.
Select the appropriate EBR type - using the wrong type could result in
compliance issues. In particular, opt-ins backed by express written
consent must be sent as Permission (`P`) — a Sale or Inquiry EBR will not
override an Internal DNC entry.
When bulk importing EBR records, use `keepBetterEBR: 1` to preserve existing
records with longer validity periods and avoid accidentally reducing your
compliance coverage.
# Internal DNC List
Source: https://docs.dncscrub.com/api-reference/scrub/internal-dnc
GET https://www.dncscrub.com/app/main/rpc/pdnc
Add or remove phone numbers from your Internal DNC list
Manage your Internal Do Not Call (IDNC) list programmatically. The IDNC list is your organization's private DNC database, separate from national and state DNC lists.
If a consumer on your Internal DNC list later opts back in with express
written consent, see
[Handling Opt-Outs and Opt-Ins](/api-reference/scrub/opt-outs-and-opt-ins)
— remove them from Internal DNC and record a Permission EBR.
## Request
### Headers
Your API Key
### Query Parameters
The 10-digit phone number(s) to add or remove. For multiple numbers,
comma-separate them (e.g., `5039367187,7075276405`)
Action to perform:
* `add` - Add numbers to Internal DNC list
* `remove` - Remove numbers from Internal DNC list (requires an elevated role,
see below)
* `count` - Get the count of numbers in your IDNC database
* `status` - Check if a number is on your Internal DNC list
**`remove` requires an elevated role.** The Supervisor and Administrator roles
can remove numbers from your Internal DNC list. The Agent role cannot unless
removal has been enabled for Agents on your account. `add`, `status`, and
`count` work for every role.
Create API users as **Administrator**, as described in
[API Authentication](/api-reference/authentication).
Optional Project ID of the Internal DNC list.
Only applies to `actionType=add`. Controls behavior when the request contains
an invalid phone number:
* `0` / `false` (default) - Abort the entire import on the first invalid
number. No numbers are added and a 4xx error is returned.
* `1` / `true` - Skip invalid numbers and import the valid ones.
## Example Request
```bash cURL (Add) theme={null}
curl --location --request GET \
'https://www.dncscrub.com/app/main/rpc/pdnc?phoneList=5039367187&actionType=add' \
--header 'loginId: YOUR_API_KEY'
```
```bash cURL (Remove) theme={null}
curl --location --request GET \
'https://www.dncscrub.com/app/main/rpc/pdnc?phoneList=5039367187&actionType=remove' \
--header 'loginId: YOUR_API_KEY'
```
```bash cURL (Status, JSON) theme={null}
curl --location --request GET \
'https://www.dncscrub.com/app/main/rpc/pdnc?phoneList=5039367187&actionType=status' \
--header 'loginId: YOUR_API_KEY' \
--header 'Content-Type: application/json'
```
```javascript JavaScript theme={null}
// Add a phone number
await fetch(
"https://www.dncscrub.com/app/main/rpc/pdnc?phoneList=5039367187&actionType=add",
{
method: "GET",
headers: { loginId: "YOUR_API_KEY" },
}
);
// Remove a phone number
await fetch(
"https://www.dncscrub.com/app/main/rpc/pdnc?phoneList=5039367187&actionType=remove",
{
method: "GET",
headers: { loginId: "YOUR_API_KEY" },
}
);
```
```csharp C# theme={null}
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Add("loginId", "YOUR_API_KEY");
// Add a phone number
var addResponse = await client.GetAsync(
"https://www.dncscrub.com/app/main/rpc/pdnc?phoneList=5039367187&actionType=add"
);
// Remove a phone number
var removeResponse = await client.GetAsync(
"https://www.dncscrub.com/app/main/rpc/pdnc?phoneList=5039367187&actionType=remove"
);
}
```
```json Response (add/remove, JSON mode) theme={null}
{ "message": "success" }
```
```json Response (status, JSON mode) theme={null}
[
{
"phone": "5039367187",
"onList": true,
"addedOn": "2024-03-15",
"lastModifiedOn": "2024-03-15"
},
{
"phone": "7075276405",
"onList": false,
"addedOn": null,
"lastModifiedOn": null
}
]
```
```json Response (count, JSON mode) theme={null}
{ "count": 1523, "lastModifiedOn": "2024-03-15" }
```
```text Response (status, plain text) theme={null}
5039367187,2024-03-15,2024-03-15
```
## Response
Responses are `text/plain` by default. To receive JSON instead, include the
request header `Content-Type: application/json` — all four actions (and error
responses, as `{ "error": "..." }`) then return JSON.
| Status Code | Meaning |
| ----------- | ------------------------------------------------------------------------------------------------------------- |
| `200` | Success - see per-action formats below |
| `403` | Your API key lacks the permission for this action - see [Insufficient Permissions](#insufficient-permissions) |
| `4xx` | Error - Response body contains error message |
### `add` / `remove`
Plain text mode returns an empty body with HTTP 200. JSON mode returns:
```json theme={null}
{ "message": "success" }
```
### `status`
JSON mode returns an array with one object per phone number:
```json theme={null}
[
{ "phone": "5039367187", "onList": true, "addedOn": "2024-03-15", "lastModifiedOn": "2024-03-15" },
{ "phone": "7075276405", "onList": false, "addedOn": null, "lastModifiedOn": null },
{ "phone": "150393671", "invalid": true, "onList": false, "addedOn": null, "lastModifiedOn": null }
]
```
Use the `onList` boolean to determine membership. A number that isn't exactly
10 digits is reported with `"invalid": true`.
Plain text mode returns one line per number, `,,`
with dates as `YYYY-MM-DD`. A number **not** on your Internal DNC list has
empty dates:
```
5039367187,,
```
Numbers must be exactly 10 digits (no `+1`, country code, or punctuation).
In plain text mode, a number in any other format is silently skipped — it
produces no output line at all, and if every number is skipped the response
body is empty. Use JSON mode to have invalid numbers reported explicitly.
### `count`
JSON mode:
```json theme={null}
{ "count": 1523, "lastModifiedOn": "2024-03-15" }
```
Plain text mode returns a single line, `,` — for
example `1523,2024-03-15`. An account whose Internal DNC list has never had
numbers added returns `0,` (or `{ "count": 0, "lastModifiedOn": null }` in
JSON mode).
## Multiple Phone Numbers
Add or remove multiple phone numbers by comma-separating them:
```bash theme={null}
curl --location --request GET \
'https://www.dncscrub.com/app/main/rpc/pdnc?phoneList=5039367187,7075276405,7072842774&actionType=add' \
--header 'loginId: YOUR_API_KEY'
```
## Add to Specific Project
To add a phone number to a specific project's IDNC list:
```bash theme={null}
curl --location --request GET \
'https://www.dncscrub.com/app/main/rpc/pdnc?phoneList=5039367187&actionType=add&projId=YOUR_PROJECT_ID' \
--header 'loginId: YOUR_API_KEY'
```
## Error Handling
If you pass an invalid phone number, the API returns an error:
**Request:**
```
https://www.dncscrub.com/app/main/rpc/pdnc?phoneList=BADNUMBER&actionType=add
```
**Response (HTTP 4xx):**
```
Error importing or updating phone numbers. Check that the numbers are of a probable format: BADNUMBER
```
### Insufficient Permissions
`actionType=remove` with an API key belonging to an Agent is rejected by
default, unless removal has been enabled for Agents on your account:
**Response (HTTP 403):**
```
You do not have sufficient permissions to perform: delete_pdnc
```
`delete_pdnc` is the internal name of the permission that `remove` requires.
The same key can still `add`, `status`, and `count` — those are available to
every role. Use an Administrator API key to remove numbers.
### Skipping Invalid Numbers
By default, a single bad number aborts the entire `add` request. To import the
valid numbers and silently skip invalid ones, pass `ignoreInvalid=1`:
```bash theme={null}
curl --location --request GET \
'https://www.dncscrub.com/app/main/rpc/pdnc?phoneList=5039367187,BADNUMBER,7075276405&actionType=add&ignoreInvalid=1' \
--header 'loginId: YOUR_API_KEY'
```
The two valid numbers are added; `BADNUMBER` is skipped.
## Best Practices
Always validate that phone numbers are exactly 10 digits before making the
API call.
Adding a number that already exists won't cause an error - it simply has no
effect (idempotent). Note this means re-adding a number does **not**
refresh its added-on date, which matters when EBR/consent records are also
present — see [Handling Opt-Outs and Opt-Ins](/api-reference/scrub/opt-outs-and-opt-ins).
When a consumer on your Internal DNC list opts back in with express
written consent, remove them from the list (`actionType=remove`) and add a
Permission EBR with the consent date. See
[Handling Opt-Outs and Opt-Ins](/api-reference/scrub/opt-outs-and-opt-ins).
Removing a number that doesn't exist has no effect and won't cause an error.
If you have multiple campaigns or clients, use the `projId` parameter to
organize your IDNC lists.
# Handling Opt-Outs and Opt-Ins
Source: https://docs.dncscrub.com/api-reference/scrub/opt-outs-and-opt-ins
How Internal DNC and Permission EBR records work together when a consumer opts out and later opts back in
Consumers change their minds. A person may ask to be placed on your Do Not Call
list today and opt back in next month through a web form. This guide explains
how DNCScrub's Internal DNC list and EBR/Consent records work together so the
scrub result always reflects the consumer's **most recent** choice — and the
exact API calls to make for each event.
## The two lists involved
| List | What it represents | API |
| ----------------------- | ------------------------------------------------------------------------------------------------- | ------------------------------------------------------ |
| **Internal DNC (IDNC)** | The consumer asked *your organization* not to call them | [Internal DNC List](/api-reference/scrub/internal-dnc) |
| **EBR / Consent** | You have an exemption to DNC rules — a purchase, an inquiry, or the consumer's express permission | [EBR and Consent](/api-reference/scrub/ebr-list) |
A phone number can have records on **both** lists at the same time. When that
happens, the scrubber decides which one wins using the rules below.
**Use a Permission (`P`) EBR for opt-ins backed by express written consent** —
for example, a signed web consent form, a checked consent box with the
required disclosures, or a recorded verbal agreement where allowed. Sale
(`S`) and Inquiry (`I`) EBRs represent business activity, not consent, and
they do **not** override an Internal DNC entry.
## How the scrubber decides: dates matter
When a number is on your Internal DNC list *and* has a Permission EBR, the
scrubber compares dates:
* If the Permission EBR's `dateOfLastContact` (the consent date) is **later**
than the date the number was added to your Internal DNC list, the consent
wins. The number is returned as callable with an **EBR Override** result
code (`O`).
* If the Internal DNC entry is **newer** than the consent, the opt-out wins and
the number is returned as Internal DNC (`P` result code) — not callable.
In other words: **the most recent expression of the consumer's intent wins**,
as long as the dates you send are accurate.
Sale and Inquiry EBRs never override an Internal DNC entry, regardless of
dates. Only a Permission EBR — express consent — can do that.
## Recommended lifecycle
A typical sequence, using a consumer who opts out through your dialer or CRM
disposition and later opts back in through a web consent form:
Add the number to your Internal DNC list:
```bash theme={null}
curl --request GET \
'https://www.dncscrub.com/app/main/rpc/pdnc?phoneList=5039367187&actionType=add' \
--header 'loginId: YOUR_API_KEY'
```
Scrubs now return the number as Internal DNC (`P`) — do not call.
Do **two** things:
**1. Add a Permission EBR** with `dateOfLastContact` set to the actual
date the consumer gave consent:
```bash theme={null}
curl --request POST 'https://www.dncscrub.com/app/main/rpc/ebr' \
--header 'loginId: YOUR_API_KEY' \
--header 'Content-Type: application/json' \
--data '{
"ebrList": [
{
"phoneNumber": "5039367187",
"type": "P",
"dateOfLastContact": "07/15/2026",
"referenceNum": "consent-form-84213"
}
]
}'
```
**2. Remove the number from your Internal DNC list:**
```bash theme={null}
curl --request GET \
'https://www.dncscrub.com/app/main/rpc/pdnc?phoneList=5039367187&actionType=remove' \
--header 'loginId: YOUR_API_KEY'
```
Scrubs now return the number as callable under the Permission EBR.
Add the number back to your Internal DNC list (same call as step 1). The
new Internal DNC entry is dated later than the consent, so the opt-out
wins again.
## Why remove the Internal DNC entry on opt-in?
Strictly speaking, a Permission EBR dated after the Internal DNC entry already
overrides it — the scrubber's date comparison handles that. But we still
recommend removing the Internal DNC entry when the consumer opts back in, for
one important reason:
**Adding a number that is already on your Internal DNC list does not refresh
its added-on date.** The add is idempotent — the record keeps its original
date. So if you leave the stale Internal DNC entry in place and the consumer
later opts out *again*, your new "add" would be a no-op against the old entry,
the Permission EBR would still look newer, and the number would keep scrubbing
as callable. That is a compliance risk.
Removing the entry on opt-in and adding a fresh one on the next opt-out keeps
the dates truthful in both directions.
Keep the Permission EBR in place when the consumer opts out again — there is
no need to delete it. The newer Internal DNC entry takes precedence, and the
EBR record preserves your audit trail of the earlier consent.
## Rules of thumb
* **Opt-out** → add to Internal DNC.
* **Opt-in with express written consent** → add a Permission (`P`) EBR *and*
remove the number from Internal DNC.
* **Purchase or inquiry** → add a Sale (`S`) or Inquiry (`I`) EBR. These
create DNC exemptions for numbers on the National/state registries but never
override your Internal DNC list.
* **Always send true event dates.** `dateOfLastContact` must be the date
consent was actually given — not the date you happened to load the record.
The scrubber's precedence logic is only as accurate as the dates you send,
so load opt-outs and opt-ins promptly.
* **Keep records for your audit trail.** Use `referenceNum` on EBR records to
tie the consent back to the form submission or recording that proves it.
# Output Guide
Source: https://docs.dncscrub.com/api-reference/scrub/output-guide
Complete reference for result codes and response fields both for API and Batch Scrub
This guide provides a complete reference for understanding the Scrub API response fields and result codes. These fields
are also the same as in our batch scrub processing that can be either done thru the DNCScrub web portal or SFTP.
Whether a call is permissible depends on the call's content. We recommend each caller review the [Consent
Chart](https://www.dncscrub.com/compliance-guide/consent-chart) in our compliance guide with their legal counsel. Our responses are oriented around the call's content being a marketing message.
## Result Codes
The `ResultCode` field indicates the overall scrub result for a phone number:
### Clean
| Code | Name | Description |
| ---- | ------------------ | -------------------------------------------------------------------------------- |
| `C` | Clean | Phone number is not on any DNC list, is not Wireless or VoP, and is safe to call |
| `X` | Industry Exemption | Industry exemption applied to an otherwise DNC number |
### Wireless \ VoIP Indicators
| Code | Name | Description |
| ---- | ---------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `W` | Wireless | Wireless number not in any DNC database. Not in a state that restricts solicitations to wireless numbers. |
| `L` | Wireless Prohibited | Wireless number in a US state that does not allow telephone solicitation to wireless numbers, even if manually dialed (States: WY, NJ, TX, LA, and AZ) |
| `F` | EBR + Wireless Restricted | Valid EBR and Wireless number in a US state that does not allow telephone solicitation to wireless numbers, even if manually dialed (States: WY, NJ, TX, LA, and AZ) |
| `G` | EBR + Wireless/VoIP | Valid EBR and US Wireless or VoIP number, not on any DNC database (version 2+). Still cannot be called from a predictive dialer as EBRs do not constitute an exemption to those rules |
| `H` | EBR Override + Wireless/VoIP | Wireless or VoIP number that is also a valid EBR, overriding an otherwise DNC number |
| `V` | EBR Override + Wireless Restricted | Valid EBR overriding an otherwise DNC number that is also a Wireless number in a US state that does not allow telephone solicitation to wireless numbers, even if manually dialed (States: WY, NJ, TX, LA, and AZ) |
### EBR (Existing Business Relationship)
| Code | Name | Description |
| ---- | ------------ | ------------------------------------------------------------------------------------------------------------------------------------------------ |
| `E` | EBR Valid | Currently valid EBR, not on a Do Not Call list. Number can be called |
| `O` | EBR Override | EBR Override was applied to an otherwise Do Not Call number (including an explicit EBR overriding a number in Project DNC). Number can be called |
### VoIP
VoIP should be treated the same way as wireless. Federal and state laws that apply to Wireless
apply to VoIP as well.
| Code | Name | Description |
| ---- | ---- | ---------------------------------------------------------------------------------------------------------------------------------- |
| `Y` | VoIP | VoIP number not in any DNC databases (or it has been overridden by an industry exemption). Requires VoIP scrubbing to be purchased |
### Industry Exemptions
| Code | Name | Description |
| ---- | ------------------ | ----------------------------------------------------- |
| `X` | Industry Exemption | Industry exemption applied to an otherwise DNC number |
### Do Not Call
| Code | Name | Description |
| ---- | ------------ | ----------------------------------------------------------------------------------------------------------------------------------------- |
| `D` | Do Not Call | Phone number is on a DNC database. The `Reason` field provides additional details. Litigator numbers have "Litigator" in the Reason field |
| `P` | Internal DNC | Internal DNC (also called Project DNC) database match. No further checks are performed once a number is found as Internal DNC |
### Invalid or Blocked
| Code | Name | Description |
| ---- | --------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `B` | Blocked | Number is in an area code not covered by the National Subscription on this project, is in a configured no-call area code, or no exemption was available in a pre-recorded call campaign |
| `I` | Invalid | Area code is not active, reserved, or is a special use phone number pattern (e.g., 555-5555) |
| `M` | Malformed | Number is not 10 numerical digits |
## Response Fields
Types below are for `version=8` JSON (see [JSON response
shape](#json-response-shape)); earlier versions return every value as a string.
### Phone Information
| Field | Type | Description |
| ------------ | ------------- | ------------------------------------------------------------------------- |
| `Phone` | String | The phone number that was scrubbed |
| `ResultCode` | String | The scrub result code (see above) |
| `Reserved` | String / null | Your unique identifier if provided, otherwise `null` (v5–7: empty string) |
| `Reason` | String | Detailed reason for the result code |
### Location Information
| Field | Type | Description |
| -------------- | ------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `RegionAbbrev` | String | State/province abbreviation for the number's **area code** — where the number is geographically from (e.g., "CA", "NY"). This is not necessarily the state DNC registry it is listed on; see [Reason Field Format](#reason-field-format). |
| `Country` | String | Country code (e.g., "US", "CA") |
| `Locale` | String | City or locality name |
### Carrier Information
| Field | Type | Description |
| ------------------ | ------- | ---------------------------------------------------- |
| `CarrierInfo` | String | Carrier information in format: `ID;TYPE;"Name:Name"` |
| `LineType` | String | `Wireless`, `VoIP`, or `AllOther` |
| `IsWirelessOrVoIP` | Boolean | `true` if wireless or VoIP |
### Timezone Information
| Field | Type | Description |
| ------------------------- | ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `TZCode` | Integer | Timezone code (see [Timezone Codes](#timezone-codes)) |
| `UTCOffset` | Integer | UTC offset in minutes, adjusted for DST (e.g., `-420` for Pacific Daylight Time) |
| `CallingWindow` | String / null | `null` when no window applies. Permitted calling hours in the destination's local time, `HH:MM-HH:MM`, three semicolon-separated windows: weekday;Saturday;Sunday |
| `CallingTimeRestrictions` | Integer | Bit field: `1` = currently outside the calling window, `2` = an EBR exemption to the calling window is available, `4` = the state does not specify its own window (or you are exempt), so the federal 8 AM–9 PM window applies |
| `DoNotCallToday` | Boolean | `true` if should not be called today (state holiday or state of emergency) |
| `PostalCode` | String / null | Normalized postal code used for the time zone calculation (`10001`, `M5V`). `null` if none was supplied. API only, requires `version=8+` |
| `TZSource` | String | `postalCode` if the fields above were derived from a supplied postal code, otherwise `areaCode`. API only, requires `version=8+` |
| `IsCallAllowedNonATDS` | Boolean | `true` if a manually dialed, live-agent marketing call may be placed right now. See [Is the call allowed?](#is-the-call-allowed). API only, requires `version=8+` |
| `IsCallAllowedATDS` | Boolean | Same, for autodialed calls. Wireless and VoIP return `false` unless a Permission EBR is on file. API only, requires `version=8+` |
| `IsCallAllowedAI` | Boolean | Same, for AI / artificial / prerecorded voice. `true` only with a valid Permission EBR (`EBRType` `P`). See [AI Voice Agents](/api-reference/scrub/ai-voice-agents). API only, requires `version=8+` |
#### How the time zone and calling window are determined
1. By default the destination is located from the phone number's area code and
prefix (NPA-NXX). That gives the time zone (`TZCode`, `UTCOffset`) and the
state whose calling hours, holidays and state-of-emergency blocks are applied
(`CallingWindow`, `CallingTimeRestrictions`, `DoNotCallToday`).
2. API callers may supply the contact's postal code per number, as
`PHONE|ID|POSTALCODE` in `phoneList`. When the
postal code is recognized (5-digit US ZIP or Canadian postal code / FSA), the
destination time zone and state come from the postal code instead, and
`TZSource` is `postalCode`. Mobile numbers keep their area code when their
owner moves, so this is the more reliable choice when you know where the
contact lives.
3. If the postal code is missing or not recognized, step 1 applies and
`TZSource` is `areaCode`.
The postal code never changes `ResultCode`, `Reason`, `RegionAbbrev`,
`Country`, `Locale`, DNC list matching or EBR handling — those always follow the
phone number. Batch scrubs (portal upload and SFTP) do not accept a postal code.
### EBR Information
| Field | Type | Description |
| -------------- | ------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `EBRType` | String / null | Type of EBR applied: `S` (Sale), `I` (Inquiry), `P` (Permission). `null` if none (v5–7: empty string) |
| `EBRExpiresOn` | Date / null | Date the EBR expires, `YYYY-MM-DD`, inclusive. The earlier of the federal and state expiration dates. `null` if no EBR. Requires `version=6+` (v6–7: `YYYY-MM-DD 23:59:00` string) |
### Line Type Dates
| Field | Type | Description |
| ------------------ | ----------- | ---------------------------------------------------------------------------------------------------------- |
| `WirelessPortDate` | Date / null | Date the number was ported to wireless. `null` if no port record (v7: `0` or empty). Requires `version=7+` |
| `VoIPDate` | Date / null | Date the number was identified as VoIP, `YYYY-MM-DD`. `null` if not VoIP. Requires `version=7+` |
### Other Fields
| Field | Type | Description |
| ----------------------- | ------------- | ---------------------------------------------------------------------- |
| `NewReassignedAreaCode` | String / null | New area code if the area code was split or overlaid, otherwise `null` |
`EBRExpiresOn` is returned only with `version=6` or higher;
`WirelessPortDate` and `VoIPDate` only with `version=7` or higher;
`PostalCode`, `TZSource`, `IsCallAllowedNonATDS`, `IsCallAllowedATDS` and
`IsCallAllowedAI` only with `version=8` or higher. Use `version=8` to receive
all fields.
In versions 6–7, `EBRExpiresOn` is not an ISO 8601 timestamp: the time
portion is always `23:59:00` (end of day) and no timezone is included. Treat
it as a date — compare `YYYY-MM-DD` against your local calendar date rather
than parsing it as a UTC timestamp. Version 8 returns the date only.
## Is the call allowed?
`ResultCode` has many values because the right action depends on how you place
the call. With `version=8` the response includes three flags that collapse
`ResultCode`, `EBRType`, `DoNotCallToday` and the calling window into one
yes/no answer for **a marketing call placed right now**. They differ in how
wireless numbers and consent are treated, because that is where the law forks.
| Flag | Use it when | DNC-status condition for `1` |
| ---------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------- |
| `IsCallAllowedNonATDS` | A live agent dials, and the equipment is not an autodialer under the law that applies to you (see below) | `ResultCode` in `C`, `X`, `E`, `O`, `W`, `G`, `H`, `Y` — wireless treated like landlines |
| `IsCallAllowedATDS` | An autodialer places the call (federal or state definition) — TCPA §227(b) requires prior express written consent to call **wireless** numbers | `ResultCode` in `C`, `X`, `E`, `O`; or `G`, `H` when `EBRType` is `P` (consent on file). Wireless without consent is `false` |
| `IsCallAllowedAI` | The call uses an **artificial, prerecorded or AI-generated voice** (including ringless voicemail) — §227(b) requires prior express written consent for **wireless and residential landlines**, with no EBR exemption | `EBRType` is `P` **and** `ResultCode` in `E`, `O`, `G`, `H`. A clean number with no consent (`C`) is `false` |
All three also require every check below:
| Check | Condition |
| -------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Wireless-prohibited states | `ResultCode` is not `L`, `F` or `V` |
| Holidays / emergencies | `DoNotCallToday` is `false` |
| Calling window | The destination's current local time is inside `CallingWindow` (`CallingTimeRestrictions` bit `1` is clear), or an after-hours EBR exemption applies under your campaign's settings |
Everything else — `D`, `P`, `B`, `I`, `M` — returns `false` on all three. The
flags are nested: `IsCallAllowedAI` implies `IsCallAllowedATDS` implies
`IsCallAllowedNonATDS`.
Consent is a Permission (`P`) EBR stored through the [EBR and Consent
API](/api-reference/scrub/ebr-list). Sale and Inquiry EBRs are DNC exemptions,
not consent, and do not satisfy the ATDS or AI flags.
### Which flag applies to you
Under the federal TCPA, an autodialer (ATDS) is equipment that stores or
produces telephone numbers **using a random or sequential number generator**
(*Facebook v. Duguid*, U.S. Supreme Court, 2021). Since that decision, courts
have consistently held that a dialer — including a predictive dialer — that
calls numbers from a list you loaded is not an ATDS, even if it uses a
sequential counter to work through the list (e.g. *Soliman v. Subway*, 2d Cir.
2024\). For a live-agent call from your own list, `IsCallAllowedNonATDS` is
therefore usually the right flag under federal law.
Three things move a call to a stricter flag regardless of the dialer:
1. **Voice.** An artificial, prerecorded or AI-generated voice, or a voicemail
drop, requires prior express written consent for marketing on its own — use
`IsCallAllowedAI`. The FCC confirmed in February 2024 that AI-generated
voices are artificial voices under the TCPA.
2. **State law.** Florida, Oklahoma, Washington, Maryland and a growing list of
states define "autodialer" more broadly than the federal test (typically any
*automated system for the selection or dialing* of numbers) and attach
their own consent and calling-hour rules. If the contact is in one of those
states — use `RegionAbbrev`, or `PostalCode` when you supplied one — use
`IsCallAllowedATDS`.
3. **Your equipment actually generates numbers**, or your counsel has not
confirmed otherwise — use `IsCallAllowedATDS`.
These flags encode DNC status, stored consent, line type and calling hours —
the data DNCScrub holds. They do not know how you obtained the number, whether
your consent language meets a given state's standard, or what your dialer
does. Which flag is correct for your operation is a determination for you and
your counsel; when in doubt, use the stricter flag. A `false` on any flag does not
mean the call is illegal for every use case (for example informational or
non-marketing calls); use `ResultCode`, `LineType` and `CallingWindow` for
those.
All flags are evaluated at scrub time. The calling-window check makes them
change during the day, so for lists you scrub in advance rely on
`CallingWindow` and `UTCOffset` at dial time rather than a stored flag.
## JSON response shape
With `output=json`, **version 8** returns an object:
```json theme={null}
{
"version": 8,
"results": [ { "Phone": "7075276405", "ResultCode": "D", ... } ]
}
```
`results` has one row per number, in the order submitted. Errors (HTTP 4xx/5xx)
are also objects (`{"message": "..."}`), so a client never has to test whether
the body is an array. Values are typed:
| JSON type | Fields |
| ---------------------------------- | ------------------------------------------------------------------------------------------------------------------- |
| string | `Phone`, `ResultCode`, `Reason`, `RegionAbbrev`, `Country`, `Locale`, `CarrierInfo`, `LineType`, `TZSource` |
| string or `null` | `Reserved`, `NewReassignedAreaCode`, `EBRType`, `PostalCode`, `CallingWindow` |
| integer | `TZCode`, `UTCOffset`, `CallingTimeRestrictions` (`null` only for non-NANP destinations with no time zone) |
| boolean | `DoNotCallToday`, `IsWirelessOrVoIP`, `IsCallAllowedNonATDS`, `IsCallAllowedATDS`, `IsCallAllowedAI` — never `null` |
| date string `YYYY-MM-DD` or `null` | `EBRExpiresOn`, `WirelessPortDate`, `VoIPDate` |
`Phone` stays a string: it is an identifier, not a quantity. Field names are
unchanged from earlier versions, so a v7 client moving to v8 changes only where
it reads the array and how it compares booleans.
**Versions 5–7** return a bare JSON array with every value quoted as a string
(`"UTCOffset": "-420"`, `"IsWirelessOrVoIP": "1"`, `"WirelessPortDate": "0"`
for none, `"EBRExpiresOn": "2027-02-09 23:59:00"`, and `"DoNotCallToday": ""`
when no calling window applies — treat empty as `0`). Those versions are
unchanged. CSV output is identical across versions apart from the added
columns.
## Reason Field Format
The `Reason` field provides detail about why a number was flagged. For a Do
Not Call result (`ResultCode` `D` or `O`), it is a **fixed set of
semicolon-separated positions**, one per database. Each position is always
present and always in the same order; a position is left **empty** when the
number is not on that database. Parse by position — for example, the state
entry is always the second position.
| Position | Database | When present | When absent |
| -------- | ------------ | ------------------------------------ | ----------- |
| 1 | National DNC | `National (Country) YYYY-MM-DD` | empty |
| 2 | State DNC | `State (StateList) YYYY-MM-DD` | empty |
| 3 | TPS | `DMA TPS` (US) or `CMA TPS` (Canada) | empty |
| 4 | Wireless | `W` | empty |
`Country` is `USA` or `CAN`. The date is the date the number was added to that
registry.
The `StateList` in `State (StateList)` is the **state DNC registry the number is
listed on** — not where the number is geographically from. Those differ more
often than you might expect: a number can be on one state's registry while its
area code belongs to another (a ported number, or a state that publishes
out-of-state area codes). For example, `2036295673` has a Connecticut area code
but is on Florida's registry, so it returns `State (FL)`.
Use the separate `RegionAbbrev` field for the number's geographic
state/province. A number listed on several state registries reports one of
them; the `Reason` field has a single State position by design, so parsing by
position stays reliable.
### Examples
National DNC only:
```
National (USA) 2003-06-01;;;
```
State DNC only (note the leading empty National position):
```
;State (CA) 2020-01-15;;
```
On National, State, and TPS:
```
National (USA) 2003-06-01;State (CA) 2020-01-15;DMA TPS;
```
Wireless number with no DNC-list match (position 4 set, others empty). The
`ResultCode` is `W`, or `L` when the number is wireless in a state that
prohibits solicitation to wireless numbers:
```
;;;W
```
Wireless number that is also on a state DNC list (positions 2 and 4 set). This
number has a New Jersey area code but is listed on Florida's registry, so the
State position reports `FL` while `RegionAbbrev` returns `NJ`:
```
;State (FL) 2022-01-21;;W
```
### Standalone reasons
Some results set the entire `Reason` to a single value instead of the
positional format above:
| `Reason` | `ResultCode` | Meaning |
| ------------- | ------------ | -------------------------------------------------- |
| `Litigator` | `D` | Number belongs to a known TCPA litigator |
| `VoIP` | `Y` | Flagged as VoIP (VoIP scrubbing must be purchased) |
| `RequiresEWC` | `D` | Requires express written consent |
For these standalone reasons, the single value replaces the positional
databases — the number may also be on other DNC databases that the `Reason`
field does not list in this case. Wireless is **not** a standalone reason; it
appears in position 4 as `W` (see the examples above).
## Carrier Information Format
The `CarrierInfo` field contains three parts separated by semicolons:
```
9740;RBOC;"AT&T California:AT&T California"
```
| Part | Description |
| ----------------------------------- | ----------------------------------------- |
| `9740` | Carrier ID |
| `RBOC` | Carrier Type (RBOC, WIRELESS, CLEC, etc.) |
| `"AT&T California:AT&T California"` | Carrier name(s) |
### Carrier Types
| Type | Description |
| ---------- | --------------------------------------------------------- |
| `RBOC` | Regional Bell Operating Company (major landline carriers) |
| `WIRELESS` | Wireless/cellular carrier |
| `CLEC` | Competitive Local Exchange Carrier |
| `VOIP` | Voice over IP provider |
| `CABLE` | Cable company providing phone service |
## Line Types
| Value | Description |
| ---------- | ------------------------------ |
| `Wireless` | Mobile/cellular phone |
| `VoIP` | Voice over IP line |
| `AllOther` | Landline or other non-wireless |
## Timezone Codes
`TZCode` values for US and Canadian destinations. `UTCOffset` is returned
separately and already accounts for DST, so most integrations only need
`UTCOffset` and `CallingWindow`.
| Code | Timezone | Observes DST |
| ----- | -------------------------------------- | ------------ |
| `1` | Samoa | No |
| `2` | Hawaii | No |
| `3` | Alaska | Yes |
| `4` | Pacific | Yes |
| `6` | Alaska, Aleutians West | Yes |
| `7` | Pacific Standard (no DST) | No |
| `10` | Mountain | Yes |
| `15` | Arizona | No |
| `17` | Mountain Standard (no DST) | No |
| `20` | Central | Yes |
| `25` | Saskatchewan | No |
| `27` | Central Standard (no DST) | No |
| `35` | Eastern | Yes |
| `37` | Eastern Standard (no DST) | No |
| `40` | Indiana Eastern | Yes |
| `47` | Atlantic Standard (no DST) | No |
| `50` | Atlantic | Yes |
| `60` | Newfoundland | Yes |
| `275` | West Pacific (Guam, Northern Marianas) | No |
## Example Response Analysis
```json theme={null}
{
"version": 8,
"results": [
{
"Phone": "7075276405",
"ResultCode": "D",
"Reserved": null,
"Reason": "National (USA) 2003-06-01;;;",
"RegionAbbrev": "CA",
"Country": "US",
"Locale": "Santa Rosa",
"CarrierInfo": "9740;RBOC;\"AT&T California:AT&T California\"",
"NewReassignedAreaCode": null,
"TZCode": 4,
"CallingWindow": null,
"UTCOffset": -420,
"DoNotCallToday": false,
"CallingTimeRestrictions": 4,
"EBRType": null,
"IsWirelessOrVoIP": false,
"LineType": "AllOther",
"EBRExpiresOn": null,
"WirelessPortDate": null,
"VoIPDate": null,
"PostalCode": null,
"TZSource": "areaCode",
"IsCallAllowedNonATDS": false,
"IsCallAllowedATDS": false,
"IsCallAllowedAI": false
}
]
}
```
**Analysis:**
* **Result**: `D` = Do Not Call
* **Reason**: On National DNC since June 1, 2003
* **Location**: Santa Rosa, CA, USA
* **Carrier**: AT\&T California (landline)
* **Line Type**: Landline (`AllOther`, `IsWirelessOrVoIP` = `false`)
* **Timezone**: Pacific (code `4`, UTC-420 minutes, derived from the area code)
* **Callable now?**: No on all three flags — the number is on the National DNC
# Full Scrub API Overview
Source: https://docs.dncscrub.com/api-reference/scrub/overview
Scrub phone numbers against multiple DNC lists and compliance databases
The Full Scrub API allows you to check phone numbers against multiple compliance databases including:
* **National DNC Registry** (USA and Canada)
* **State DNC Lists**
* **Your Internal DNC (IDNC) Database**
* **Litigator Lists**
* **Consent and EBR (Existing Business Relationship) Records**
* **Wireless Number Identification**
* **VoIP Identification**
* **Calling Time Restrictions**
* **Holiday Restrictions**
* **Consent (express written consent) for autodialed and AI-voice calls**
The Full Scrub API is only checking for DNC status and Calling TIme\Holiday
restrictions. For full TCPA compliance, you also need to scrub for Reassigned
Numbers. A second API call is needed to scrub for Reassigned Scrubbing such as
[Reassigned Authority Plus](/api-reference/reassigned/authority-plus).
## Base URL
```
https://www.dncscrub.com/app/main/rpc/scrub
```
## Quick Start
```bash cURL theme={null}
curl --location --request GET \
'https://www.dncscrub.com/app/main/rpc/scrub?phoneList=7075276405&version=8&output=json' \
--header 'loginId: YOUR_API_KEY'
```
```javascript JavaScript theme={null}
const response = await fetch(
"https://www.dncscrub.com/app/main/rpc/scrub?phoneList=7075276405&version=8&output=json",
{
method: "GET",
headers: { loginId: "YOUR_API_KEY" },
}
);
const data = await response.json();
```
```csharp C# theme={null}
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Add("loginId", "YOUR_API_KEY");
var response = await client.GetStringAsync(
"https://www.dncscrub.com/app/main/rpc/scrub?phoneList=7075276405&version=8&output=json"
);
}
```
## Parameters
| Parameter | Required | Description |
| ------------ | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `phoneList` | Yes | Phone number(s) to scrub. Comma-separated for multiple. Each may carry `\|ID` or `\|ID\|POSTALCODE` suffixes; the postal code makes time zone and calling window follow the contact's location (see [Postal Code Time Zones](/api-reference/scrub/scrub-single#postal-code-time-zones)) |
| `version` | Yes | API output version. Use `8` for current version. |
| `output` | No | Response format: `json` or `csv` (default) |
| `projId` | No | Project ID for specific project |
| `campaignId` | No | Campaign ID for specific campaign |
## Response Example
```json theme={null}
[
{
"Phone": "7075276405",
"ResultCode": "D",
"Reserved": "",
"Reason": "National (USA) 2003-06-01;;;",
"RegionAbbrev": "CA",
"Country": "US",
"Locale": "Santa Rosa",
"CarrierInfo": "9740;RBOC;\"AT&T California:AT&T California\"",
"NewReassignedAreaCode": "",
"TZCode": "4",
"CallingWindow": "",
"UTCOffset": "-420",
"DoNotCallToday": "",
"CallingTimeRestrictions": "4",
"EBRType": "",
"IsWirelessOrVoIP": "0",
"LineType": "AllOther",
"EBRExpiresOn": "",
"WirelessPortDate": "0",
"VoIPDate": "",
"PostalCode": "",
"TZSource": "areaCode",
"IsCallAllowedNonATDS": "0",
"IsCallAllowedATDS": "0",
"IsCallAllowedAI": "0"
}
]
```
## Result Codes
The `ResultCode` field indicates the scrub result:
| Code | Meaning | Action |
| ---- | ----------------------- | -------------------------------------------------- |
| `C` | Clean | Phone number is safe to call |
| `D` | Do Not Call | Phone number is on a DNC list |
| `W` | Wireless | Wireless number, not in DNC, not blocked |
| `L` | Wireless Prohibited | Wireless in a state prohibiting solicitation |
| `G` | EBR + Wireless | Valid EBR and wireless, not on any DNC |
| `H` | EBR Override + Wireless | Wireless with valid EBR overriding DNC |
| `F` | Wireless Restricted | Wireless in state not allowing even manual dialing |
For a complete list of result codes and field descriptions, see the [Output
Guide](/api-reference/scrub/output-guide).
## Available Endpoints
Scrub a single phone number
Scrub multiple phone numbers in one request
Pass a unique ID with each phone number
Add or remove numbers from your Internal DNC
Manage Existing Business Relationship records
One flag that tells an AI dialer whether it may place the call
Complete field reference
# Scrub + Add EBR
Source: https://docs.dncscrub.com/api-reference/scrub/scrub-ebr
POST https://www.dncscrub.com/app/main/rpc/scrub
Scrub phone numbers and add or refresh their EBR records in a single API call
Scrub one or more phone numbers **and** add or refresh their Existing Business Relationship (EBR) records in a single request. This is the combined version of the [Scrub](/api-reference/scrub/scrub-multiple) and [EBR and Consent](/api-reference/scrub/ebr-list) endpoints: each number is checked against the DNC lists, and any EBR records you include in the same request are written before the result is returned, so the scrub result reflects the EBR you just submitted.
Use this when your system establishes (or re-establishes) a business relationship at the same moment it needs a compliance decision — for example, logging an inquiry and immediately deciding whether the number is callable.
Each EBR you submit sets that number's date of last contact to the date you
provide and recalculates its expiration from that date. If you submit an EBR
for the same number on every contact, its expiration window will roll forward
each time and will not expire. Only submit an EBR when a genuine new business
relationship event occurs, or use `keepBetterEBR` (see below) to avoid
shortening or unintentionally extending an existing EBR. See
[EBR Expiration](/api-reference/scrub/ebr-list#ebr-expiration).
## Request
### Headers
Your API Key
Must be `application/json`
### Request Body
Comma-separated list of 10-digit phone numbers (e.g.,
`5039367187,7075276405`). To include a system identifier with each result,
append `|{id}` to the phone number (e.g.,
`5039367187|abc-10232,7075276405|abc-10233`). A third field carries an
optional postal code, `|{id}|{postalCode}`, used for the time zone and
calling-window calculation (see [Postal Code Time
Zones](/api-reference/scrub/scrub-single#postal-code-time-zones)).
API version. Use `8` (latest). Version `6` adds `EBRExpiresOn` — useful here
to see the expiration of the EBR you just submitted; version `7` adds
`WirelessPortDate` and `VoIPDate`; version `8` adds `PostalCode`, `TZSource`,
`IsCallAllowedNonATDS`, `IsCallAllowedATDS` and `IsCallAllowedAI`.
Response format: `json` or `csv`
Optional. Project ID
Optional. Campaign ID
When set to `1`, if an EBR record already exists for a number being submitted
and the existing EBR is "better" than the one being added, the existing EBR is
not overwritten. Federal EBR expiration dates determine which is better
(longer remaining validity = better). Defaults to `0`, which overwrites the
existing EBR and resets its expiration window.
Optional. EBR records to add or refresh as part of this scrub. Each record
applies to the `phoneNumber` it names, which should also appear in
`phoneList`.
10-digit phone number(s). For multiple numbers, comma-separate them (e.g., `"5039367187,7075276405"`).
EBR type. See [EBR Types](/api-reference/scrub/ebr-list#ebr-types) for the
full list (e.g., `S` - Sale/Purchase, `I` - Inquiry, `P` - Permission).
Date of last contact in `MM/DD/YYYY` format (e.g., `"11/11/2020"`).
Date when written obligation ends (New Jersey only).
Your internal tracking string.
Company/product/brand name used to establish the EBR.
Email address (100 characters max).
## Example Request
```bash cURL theme={null}
curl --location --request POST \
'https://www.dncscrub.com/app/main/rpc/scrub' \
--header 'loginId: YOUR_API_KEY' \
--header 'Content-Type: application/json' \
--data '{
"phoneList": "5039367187,7075276405",
"version": "8",
"output": "json",
"keepBetterEBR": 0,
"ebrList": [
{
"phoneNumber": "5039367187",
"type": "I",
"dateOfLastContact": "11/11/2020",
"referenceNum": "OrderID-12345"
}
]
}'
```
```javascript JavaScript theme={null}
const response = await fetch("https://www.dncscrub.com/app/main/rpc/scrub", {
method: "POST",
headers: {
loginId: "YOUR_API_KEY",
"Content-Type": "application/json",
},
body: JSON.stringify({
phoneList: "5039367187,7075276405",
version: "8",
output: "json",
keepBetterEBR: 0,
ebrList: [
{
phoneNumber: "5039367187",
type: "I",
dateOfLastContact: "11/11/2020",
referenceNum: "OrderID-12345",
},
],
}),
});
const results = await response.json();
results.forEach((result) => {
console.log(`${result.Phone}: ${result.ResultCode} (EBR: ${result.EBRType})`);
});
```
```csharp C# theme={null}
System.Net.ServicePointManager.SecurityProtocol = System.Net.SecurityProtocolType.Tls12;
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Add("loginId", "YOUR_API_KEY");
var requestBody = new
{
phoneList = "5039367187,7075276405",
version = "8",
output = "json",
keepBetterEBR = 0,
ebrList = new[]
{
new
{
phoneNumber = "5039367187",
type = "I",
dateOfLastContact = "11/11/2020",
referenceNum = "OrderID-12345"
}
}
};
var json = System.Text.Json.JsonSerializer.Serialize(requestBody);
var content = new StringContent(json, System.Text.Encoding.UTF8, "application/json");
var response = await client.PostAsync(
"https://www.dncscrub.com/app/main/rpc/scrub",
content
);
var responseString = await response.Content.ReadAsStringAsync();
}
```
```json Response theme={null}
[
{
"Phone": "5039367187",
"ResultCode": "E",
"Reserved": "",
"Reason": "EBR",
"RegionAbbrev": "OR",
"Country": "US",
"Locale": "Portland",
"CarrierInfo": "9740;RBOC;\"CenturyLink:CenturyLink\"",
"NewReassignedAreaCode": "",
"TZCode": "4",
"CallingWindow": "",
"UTCOffset": "-420",
"DoNotCallToday": "",
"CallingTimeRestrictions": "4",
"EBRType": "I",
"IsWirelessOrVoIP": "0",
"LineType": "AllOther",
"EBRExpiresOn": "2021-02-09 23:59:00",
"WirelessPortDate": "0",
"VoIPDate": ""
}
]
```
## Response Fields
The response is identical to the standard [Scrub](/api-reference/scrub/scrub-multiple#response-fields) response, one row per number in `phoneList`. Because the EBR is written before the scrub result is computed, the result reflects the EBR you submitted.
The scrub result code. Numbers with a valid EBR return an EBR-related code such
as `E`, `F`, `G`, `H`, or `O` (see
[Output Guide](/api-reference/scrub/output-guide)).
The type of EBR currently on the record (e.g., `I` for Inquiry), or blank if
the record has no EBR.
When the EBR expires, format `YYYY-MM-DD HH:MM:SS`. The earlier of the
federal and state expiration dates — reflects the EBR you just submitted.
Empty if no EBR. Requires `version=6` or higher. The time portion is always
`23:59:00` (end of day) and no timezone is included — treat the value as a
date and compare against your local calendar date rather than parsing it as a
UTC timestamp
## How It Works
1. Any records in `ebrList` are added or refreshed, honoring `keepBetterEBR`.
2. Every number in `phoneList` is scrubbed against the DNC lists.
3. The scrub result — including any EBR exemption applied in step 1 — is returned.
A number can appear in `phoneList` without a matching `ebrList` entry (scrub only), and you can submit multiple EBR records in one request.
## Best Practices
Submit an EBR when an actual business relationship event occurs (an inquiry,
sale, or grant of permission) — not on every scrub. Re-submitting an EBR for
the same number repeatedly resets its date of last contact and rolls the
expiration window forward, which can keep an exemption alive longer than the
relationship justifies.
Set `keepBetterEBR: 1` to preserve an existing EBR that has longer remaining
validity instead of overwriting it with a shorter one.
The `dateOfLastContact` should be the actual date of the business
relationship event, not the current date.
Use `output=csv` for large batches. CSV parsing is more efficient for
high-volume processing.
# Scrub Multiple Numbers
Source: https://docs.dncscrub.com/api-reference/scrub/scrub-multiple
POST https://www.dncscrub.com/app/main/rpc/scrub
Scrub multiple phone numbers in a single API call
Submit multiple phone numbers in a single request for efficient batch processing.
To add or refresh EBR records in the same call as a scrub, use
[Scrub + Add EBR](/api-reference/scrub/scrub-ebr).
If you scrub more than 10 phone numbers, use HTTP POST instead of HTTP GET. If
you do not know your batch size, safest option is always use HTTP POST. The
maximum number of records that can be scrubbed per requests is 10,000. If you
have larger batches, consider using SFTP.
## Request
### Headers
Your API Key
### Request Body
Comma-separated list of 10-digit phone numbers (e.g.,
`5039367187,7075276405,7072842774`). To include a system identifier with each
result, append `|{id}` to the phone number (e.g.,
`5039367187|abc-10232,7075276405|abc-10233,7072842774|abc-10234`). To have
the time zone and calling window calculated from the contact's postal code
instead of the area code, append it as a third field, `|{id}|{postalCode}`
(e.g., `5039367187|abc-10232|10001,7075276405||97205`). See [Postal Code
Time Zones](/api-reference/scrub/scrub-single#postal-code-time-zones).
API version. Use `8` (latest). Version `6` adds `EBRExpiresOn`; version `7`
adds `WirelessPortDate` and `VoIPDate`; version `8` adds `PostalCode`, `TZSource`,
`IsCallAllowedNonATDS`, `IsCallAllowedATDS` and `IsCallAllowedAI`.
Response format: `json` or `csv`
Optional. Project ID
Optional. Campaign ID
## Example Request
```bash cURL (POST - for 10+ numbers) theme={null}
curl --location --request POST \
'https://www.dncscrub.com/app/main/rpc/scrub' \
--header 'loginId: YOUR_API_KEY' \
--header 'Content-Type: application/json' \
--data '{
"phoneList": "5039367187,7075276405,7072842774",
"version": "8",
"output": "json"
}'
```
```javascript JavaScript theme={null}
const phoneNumbers = ["5039367187", "7075276405", "7072842774"];
const phoneList = phoneNumbers.join(",");
const response = await fetch("https://www.dncscrub.com/app/main/rpc/scrub", {
method: "POST",
headers: {
loginId: "YOUR_API_KEY",
"Content-Type": "application/json",
},
body: JSON.stringify({
phoneList: phoneList,
version: "8",
output: "json",
}),
});
const results = await response.json();
results.forEach((result) => {
console.log(`${result.Phone}: ${result.ResultCode}`);
});
```
```csharp C# theme={null}
System.Net.ServicePointManager.SecurityProtocol = System.Net.SecurityProtocolType.Tls12;
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Add("loginId", "YOUR_API_KEY");
var requestBody = new
{
phoneList = "5039367187,7075276405,7072842774",
version = "8",
output = "json"
};
var json = System.Text.Json.JsonSerializer.Serialize(requestBody);
var content = new StringContent(json, System.Text.Encoding.UTF8, "application/json");
var response = await client.PostAsync(
"https://www.dncscrub.com/app/main/rpc/scrub",
content
);
var responseString = await response.Content.ReadAsStringAsync();
}
```
```json Response theme={null}
[
{
"Phone": "5039367187",
"ResultCode": "D",
"Reserved": "",
"Reason": "Litigator",
"RegionAbbrev": "OR",
"Country": "US",
"Locale": "Portland",
"CarrierInfo": "5820;WIRELESS;\"Verizon Wireless:Verizon Wireless\"",
"NewReassignedAreaCode": "",
"TZCode": "4",
"CallingWindow": "",
"UTCOffset": "-420",
"DoNotCallToday": "",
"CallingTimeRestrictions": "4",
"EBRType": "",
"IsWirelessOrVoIP": "1",
"LineType": "Wireless",
"EBRExpiresOn": "",
"WirelessPortDate": "2019-03-14",
"VoIPDate": "",
"PostalCode": "",
"TZSource": "areaCode",
"IsCallAllowedNonATDS": "0",
"IsCallAllowedATDS": "0",
"IsCallAllowedAI": "0"
},
{
"Phone": "7075276405",
"ResultCode": "D",
"Reserved": "",
"Reason": "National (USA) 2003-06-01;;;",
"RegionAbbrev": "CA",
"Country": "US",
"Locale": "Santa Rosa",
"CarrierInfo": "9740;RBOC;\"AT&T California:AT&T California\"",
"NewReassignedAreaCode": "",
"TZCode": "4",
"CallingWindow": "",
"UTCOffset": "-420",
"DoNotCallToday": "",
"CallingTimeRestrictions": "4",
"EBRType": "",
"IsWirelessOrVoIP": "0",
"LineType": "AllOther",
"EBRExpiresOn": "",
"WirelessPortDate": "0",
"VoIPDate": "",
"PostalCode": "",
"TZSource": "areaCode",
"IsCallAllowedNonATDS": "0",
"IsCallAllowedATDS": "0",
"IsCallAllowedAI": "0"
}
]
```
## Response Fields
The phone number that was scrubbed
The scrub result code (see [Result
Codes](/api-reference/scrub/overview#result-codes))
Reserved field (used for unique identifiers)
Explanation of why the number is flagged
State/region abbreviation (e.g., "CA")
Country code (e.g., "US")
City or locality
Carrier information in format: `ID;TYPE;"Name"`
Timezone code
UTC offset in minutes
Type of EBR applied: `S` (Sale), `I` (Inquiry), or `P` (Permission). Empty if
no EBR
`1` if wireless/VoIP, `0` otherwise
Line type: `Wireless`, `VoIP`, or `AllOther`
When the EBR expires, format `YYYY-MM-DD HH:MM:SS` (e.g. `2027-02-09
23:59:00`). The earlier of the federal and state expiration dates. Empty if no
EBR. Requires `version=6` or higher. The time portion is always `23:59:00`
(end of day) and no timezone is included — treat the value as a date and
compare against your local calendar date rather than parsing it as a UTC
timestamp
Date the number was ported to wireless. `0` or empty when there is no port
record. Requires `version=7` or higher
Date the number was identified as VoIP. Empty if not VoIP. Requires
`version=7` or higher
Normalized postal code used for the time zone calculation (`10001`, `M5V`).
Empty if none was supplied. Requires `version=8` or higher
`postalCode` when the time zone and calling window were derived from the
supplied postal code, otherwise `areaCode`. See [Postal Code Time
Zones](/api-reference/scrub/scrub-single#postal-code-time-zones). Requires
`version=8` or higher
`1` if a **manually dialed, live-agent** marketing call may be placed to this
number right now; `0` otherwise. Combines `ResultCode`, `DoNotCallToday` and
the calling window. See [Is the call
allowed?](/api-reference/scrub/output-guide#is-the-call-allowed) for the rules
and for when this flag applies to you. Requires `version=8` or higher
Same checks, for calls placed by an **autodialer** (federal or state
definition). Wireless and VoIP numbers return `0` unless a Permission (`P`)
EBR — express written consent — is on file. Requires `version=8` or higher
Same checks, for calls using an **artificial, prerecorded or AI-generated
voice**. `1` only when a Permission (`P`) EBR is on file and still valid
(`EBRType` is `P` and `ResultCode` is `E`, `O`, `G` or `H`) — any line type.
Clean numbers without consent return `0`. See [Compliance for AI Voice
Agents](/api-reference/scrub/ai-voice-agents). Requires `version=8` or higher
## Processing Multiple Results
```javascript theme={null}
const results = await response.json();
const clean = results.filter((r) => r.ResultCode === "C");
const doNotCall = results.filter((r) => r.ResultCode === "D");
const wireless = results.filter((r) => r.IsWirelessOrVoIP === "1");
console.log(`Clean numbers: ${clean.length}`);
console.log(`Do Not Call: ${doNotCall.length}`);
console.log(`Wireless: ${wireless.length}`);
```
## Using HTTP POST for Large Batches
For more than 10 phone numbers, use HTTP POST with a JSON body:
```csharp theme={null}
using (var client = new HttpClient())
{
System.Net.ServicePointManager.SecurityProtocol = System.Net.SecurityProtocolType.Tls12;
client.DefaultRequestHeaders.Add("loginId", "YOUR_API_KEY");
var requestBody = new
{
phoneList = "5039367187,7075276405,...",
version = "8",
output = "csv" // Recommended for large batches
};
var json = System.Text.Json.JsonSerializer.Serialize(requestBody);
var content = new StringContent(json, System.Text.Encoding.UTF8, "application/json");
var response = await client.PostAsync(
"https://www.dncscrub.com/app/main/rpc/scrub",
content
);
var responseString = await response.Content.ReadAsStringAsync();
}
```
## Best Practices
While the API can handle large batches, consider breaking very large lists
into batches of 1,000-5,000 numbers for optimal performance.
Use `output=csv` for large batches. CSV parsing is more efficient for
high-volume processing.
Operations are atomic. If one phone number is invalid, the entire batch
fails. Validate phone numbers before sending.
# Scrub Single Number
Source: https://docs.dncscrub.com/api-reference/scrub/scrub-single
GET https://www.dncscrub.com/app/main/rpc/scrub
Scrub a single phone number via the API
Scrub a single phone number against all configured DNC lists and compliance databases.
## Request
### Headers
Your API Key
### Query Parameters
The 10-digit phone number to scrub. Optionally append a pipe-delimited
identifier (`5039367181|ACCT-1`) and/or postal code (`5039367181|ACCT-1|10001`;
leave the identifier empty to pass only a postal code: `5039367181||10001`) —
see [Postal Code Time Zones](#postal-code-time-zones)
API version. Use `8` (latest). Version `6` adds `EBRExpiresOn`; version `7`
adds `WirelessPortDate` and `VoIPDate`; version `8` adds `PostalCode`, `TZSource`,
`IsCallAllowedNonATDS`, `IsCallAllowedATDS` and `IsCallAllowedAI`, and returns
JSON as a typed object (`{"version": 8, "results": [...]}`) instead of an array
of strings — see [JSON response
shape](/api-reference/scrub/output-guide#json-response-shape).
Response format: `json` or `csv`
Optional. Project ID
Optional. Campaign ID
## Postal Code Time Zones
By default `TZCode`, `UTCOffset`, `CallingWindow`, `CallingTimeRestrictions`
and `DoNotCallToday` are derived from the phone number's area code and prefix.
Mobile numbers keep their area code when their owner moves, so the area code is
not always where the person is. If you know the contact's postal code, pass it
and those fields are calculated from the postal code's time zone and state
instead — state calling hours, state holidays and state-of-emergency blocks all
follow the postal code's state.
The postal code is always passed per number, as the third pipe-delimited field
of `phoneList`: `PHONE|ID|POSTALCODE`. Leave the ID empty if you don't use one:
```
phoneList=5039367181||10001
```
There is deliberately no request-level parameter — one postal code applied to a
whole list would silently mis-time every other number. See [Unique
Identifiers](/api-reference/scrub/unique-identifier) for the pipe syntax.
Accepted formats: 5-digit US ZIP (ZIP+4 is accepted, e.g. `10001-1234`; only
the first five digits are used) and Canadian postal codes (`M5V3L9`, or just
the `M5V` forward sortation area). Case and hyphens are ignored. **Do not put
spaces inside a `phoneList` entry** — whitespace separates phone numbers, so
`M5V 3L9` must be sent as `M5V3L9` (or `M5V-3L9`).
If the postal code is not recognized, the number is processed exactly as if no
postal code had been passed. Use `version=8` to receive `TZSource`, which tells
you which method was used.
The postal code only affects the time zone and calling-window fields.
`ResultCode`, `Reason`, `RegionAbbrev`, `Country`, `Locale`, DNC list matching
and EBR logic are always based on the phone number.
## One-Field Answer
With `version=8` the response also includes three yes/no flags so you don't
have to interpret `ResultCode`, `EBRType`, `DoNotCallToday` and the calling
window yourself. Pick the one that matches how you place calls:
| Flag | You are placing… |
| ---------------------- | -------------------------------------------------- |
| `IsCallAllowedNonATDS` | a manually dialed, live-agent call |
| `IsCallAllowedATDS` | an autodialed call (live agent on connect) |
| `IsCallAllowedAI` | a call with an AI, artificial or prerecorded voice |
See [Is the call allowed?](/api-reference/scrub/output-guide#is-the-call-allowed)
for the rules and [Compliance for AI Voice
Agents](/api-reference/scrub/ai-voice-agents) for the AI workflow end to end.
## Example Request
```bash cURL theme={null}
curl --location --request GET \
'https://www.dncscrub.com/app/main/rpc/scrub?phoneList=7075276405&version=8&output=json' \
--header 'loginId: YOUR_API_KEY'
```
```javascript JavaScript theme={null}
const phoneNumber = "7075276405";
const apiUrl = `https://www.dncscrub.com/app/main/rpc/scrub?phoneList=${phoneNumber}&version=8&output=json`;
fetch(apiUrl, {
method: "GET",
headers: {
loginId: "YOUR_API_KEY",
},
})
.then((response) => response.json())
.then((data) => {
const result = data.results[0];
console.log("Phone:", result.Phone);
console.log("Result Code:", result.ResultCode);
console.log("Reason:", result.Reason);
});
```
```csharp C# theme={null}
// Ensure TLS 1.2
System.Net.ServicePointManager.SecurityProtocol = System.Net.SecurityProtocolType.Tls12;
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Add("loginId", "YOUR_API_KEY");
var phoneNumber = "7075276405";
var url = $"https://www.dncscrub.com/app/main/rpc/scrub?phoneList={phoneNumber}&version=8&output=json";
var response = await client.GetStringAsync(url);
Console.WriteLine(response);
}
```
```json Response theme={null}
{
"version": 8,
"results": [
{
"Phone": "7075276405",
"ResultCode": "D",
"Reserved": null,
"Reason": "National (USA) 2003-06-01;;;",
"RegionAbbrev": "CA",
"Country": "US",
"Locale": "Santa Rosa",
"CarrierInfo": "9740;RBOC;\"AT&T California:AT&T California\"",
"NewReassignedAreaCode": null,
"TZCode": 4,
"CallingWindow": null,
"UTCOffset": -420,
"DoNotCallToday": false,
"CallingTimeRestrictions": 4,
"EBRType": null,
"IsWirelessOrVoIP": false,
"LineType": "AllOther",
"EBRExpiresOn": null,
"WirelessPortDate": null,
"VoIPDate": null,
"PostalCode": null,
"TZSource": "areaCode",
"IsCallAllowedNonATDS": false,
"IsCallAllowedATDS": false,
"IsCallAllowedAI": false
}
]
}
```
```json phoneList=5039367181||10001 theme={null}
{
"version": 8,
"results": [
{
"Phone": "5039367181",
"ResultCode": "W",
"Reserved": null,
"Reason": ";;;W",
"RegionAbbrev": "OR",
"Country": "US",
"Locale": "Portland",
"CarrierInfo": "5820;WIRELESS;\"Verizon Wireless:Verizon Wireless\"",
"NewReassignedAreaCode": null,
"TZCode": 35,
"CallingWindow": "8:00-21:00;8:00-21:00;8:00-21:00",
"UTCOffset": -240,
"DoNotCallToday": false,
"CallingTimeRestrictions": 4,
"EBRType": null,
"IsWirelessOrVoIP": true,
"LineType": "Wireless",
"EBRExpiresOn": null,
"WirelessPortDate": null,
"VoIPDate": null,
"PostalCode": "10001",
"TZSource": "postalCode",
"IsCallAllowedNonATDS": true,
"IsCallAllowedATDS": false,
"IsCallAllowedAI": false
}
]
}
```
## Response Fields
The phone number that was scrubbed
The scrub result code (see [Result
Codes](/api-reference/scrub/overview#result-codes))
Your unique identifier if you passed one (`PHONE|ID`), otherwise `null`
Explanation of why the number is flagged
State/region abbreviation (e.g., "CA")
Two-digit country code (e.g., "US")
City or locality
Carrier information in format: `ID;TYPE;"Name"`
New area code if the number's area code has been split or overlaid, otherwise `null`
Time zone code (see [Timezone
Codes](/api-reference/scrub/output-guide#timezone-codes)). Derived from the
postal code when one is supplied, otherwise from the area code
Permitted calling hours in the destination's local time, `HH:MM-HH:MM`, as
three semicolon-separated windows: weekday;Saturday;Sunday (e.g.
`8:00-21:00;8:00-21:00;8:00-21:00`). `null` when no window applies
UTC offset in minutes for the destination, adjusted for DST (e.g. `-240`)
`true` if the number should not be called today (state holiday or state of emergency)
Bit field: `1` = it is currently outside the calling window, `2` = an EBR
exemption to the calling window is available, `4` = the destination state
does not specify its own calling window (or you are exempt from it), so the
federal 8 AM–9 PM window applies
Type of EBR applied: `S` (Sale), `I` (Inquiry), or `P` (Permission). `null` if no EBR
`true` if wireless or VoIP
Line type: `Wireless`, `VoIP`, or `AllOther`
Date the EBR expires, `YYYY-MM-DD` (e.g. `2027-02-09`), inclusive — the number may be called through the end of that day in the destination's local time. The earlier of the federal and state expiration dates. `null` if no EBR. Requires `version=6` or higher (versions 6–7 return `YYYY-MM-DD 23:59:00` as a string)
Date the number was ported to wireless, `YYYY-MM-DD`. `null` when there is no port record (versions 7 returns `0` or empty). Requires `version=7` or higher
Date the number was identified as VoIP, `YYYY-MM-DD`. `null` if not VoIP. Requires
`version=7` or higher
Normalized postal code used for the time zone calculation (`10001`, `M5V`).
`null` if none was supplied. Requires `version=8` or higher
`postalCode` when the time zone and calling window were derived from the
supplied postal code, otherwise `areaCode`. Requires `version=8` or higher
`true` if a **manually dialed, live-agent** marketing call may be placed to this number right now. Combines `ResultCode`, `DoNotCallToday` and
the calling window. See [Is the call
allowed?](/api-reference/scrub/output-guide#is-the-call-allowed) for the rules
and for when this flag applies to you. Requires `version=8` or higher
Same checks, for calls placed by an **autodialer** (federal or state
definition). Wireless and VoIP numbers return `false` unless a Permission (`P`)
EBR — express written consent — is on file. Requires `version=8` or higher
Same checks, for calls using an **artificial, prerecorded or AI-generated
voice**. `true` only when a Permission (`P`) EBR is on file and still valid
(`EBRType` is `P` and `ResultCode` is `E`, `O`, `G` or `H`) — any line type.
Clean numbers without consent return `false`. See [Compliance for AI Voice
Agents](/api-reference/scrub/ai-voice-agents). Requires `version=8` or higher
## Handling the Response. Make sure to handle all response codes. The sample below handles just a few
```javascript theme={null}
const { results } = await response.json();
const result = results[0];
switch (result.ResultCode) {
case "C":
// Clean - safe to call
console.log("Phone number is clean");
break;
case "D":
// Do Not Call
console.log("Do not call:", result.Reason);
break;
case "W":
// Wireless number detected
console.log("Wireless number detected");
break;
default:
console.log("Result:", result.ResultCode);
}
```
# Scrub with Unique Identifiers
Source: https://docs.dncscrub.com/api-reference/scrub/unique-identifier
GET https://www.dncscrub.com/app/main/rpc/scrub
Pass a unique identifier with each phone number
Pass a unique identifier (such as Account ID, Record ID, or Member ID) with each phone number and have it returned in the response. This allows you to easily match scrub results back to your records.
## How It Works
Append a pipe character (`|`) followed by your unique identifier to each phone number:
```
phoneList=5039367181|UniqueID
```
The unique identifier will be returned in the `Reserved` field of the response.
An optional third field carries the contact's postal code, which switches the
time zone and calling-window calculation from the number's area code to the
postal code (see [Postal Code Time
Zones](/api-reference/scrub/scrub-single#postal-code-time-zones)):
```
phoneList=5039367181|UniqueID|10001
phoneList=5039367181||10001 (no identifier)
```
## Request
### Headers
Your API Key
### Query Parameters
Phone number with identifier in format: `PHONE|ID` (e.g.,
`5039367181|ACCT-12345`), optionally followed by a postal code:
`PHONE|ID|POSTALCODE` (e.g., `5039367181|ACCT-12345|10001`). For multiple
numbers, comma-separate them: `5039367181|ACCT-001,7075276405|ACCT-002`
API version. Use `8` (latest). Version `6` adds `EBRExpiresOn`; version `7`
adds `WirelessPortDate` and `VoIPDate`; version `8` adds `PostalCode`, `TZSource`,
`IsCallAllowedNonATDS`, `IsCallAllowedATDS` and `IsCallAllowedAI`.
Response format: `json` or `csv`
Project ID
Campaign ID
## Example Request
```bash cURL theme={null}
curl --location --request GET \
'https://www.dncscrub.com/app/main/rpc/scrub?phoneList=5039367181|ACCT-12345&version=8&output=json' \
--header 'loginId: YOUR_API_KEY'
```
```javascript JavaScript theme={null}
const phoneNumber = "5039367181";
const accountId = "ACCT-12345";
const response = await fetch(
`https://www.dncscrub.com/app/main/rpc/scrub?phoneList=${phoneNumber}|${accountId}&version=8&output=json`,
{
method: "GET",
headers: { loginId: "YOUR_API_KEY" },
}
);
const data = await response.json();
console.log("Account ID:", data[0].Reserved); // "ACCT-12345"
```
```csharp C# theme={null}
System.Net.ServicePointManager.SecurityProtocol = System.Net.SecurityProtocolType.Tls12;
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Add("loginId", "YOUR_API_KEY");
var phoneNumber = "5039367181";
var accountId = "ACCT-12345";
var url = $"https://www.dncscrub.com/app/main/rpc/scrub?phoneList={phoneNumber}|{accountId}&version=8&output=json";
var response = await client.GetStringAsync(url);
Console.WriteLine(response);
}
```
```json Response theme={null}
[
{
"Phone": "5039367181",
"ResultCode": "W",
"Reserved": "ACCT-12345",
"Reason": ";;;W",
"RegionAbbrev": "OR",
"Country": "US",
"Locale": "Portland",
"CarrierInfo": "5820;WIRELESS;\"Verizon Wireless:Verizon Wireless\"",
"NewReassignedAreaCode": "",
"TZCode": "4",
"CallingWindow": "8:00-21:00;8:00-21:00;8:00-21:00",
"UTCOffset": "-420",
"DoNotCallToday": "0",
"CallingTimeRestrictions": "4",
"EBRType": "",
"IsWirelessOrVoIP": "1",
"LineType": "Wireless",
"EBRExpiresOn": "",
"WirelessPortDate": "0",
"VoIPDate": "",
"PostalCode": "",
"TZSource": "areaCode",
"IsCallAllowedNonATDS": "1",
"IsCallAllowedATDS": "0",
"IsCallAllowedAI": "0"
}
]
```
The `Reserved` field contains your unique identifier `"ACCT-12345"`.
## Response Fields
The phone number that was scrubbed
The scrub result code (see [Result
Codes](/api-reference/scrub/overview#result-codes))
Your unique identifier passed with the phone number
Explanation of why the number is flagged
State/region abbreviation (e.g., "CA")
Country code (e.g., "US")
City or locality
Carrier information in format: `ID;TYPE;"Name"`
Timezone code
UTC offset in minutes
`1` if wireless/VoIP, `0` otherwise
Line type: `Wireless`, `VoIP`, or `AllOther`
Normalized postal code used for the time zone calculation (`10001`, `M5V`).
Empty if none was supplied. Requires `version=8` or higher
`postalCode` when the time zone and calling window were derived from the
supplied postal code, otherwise `areaCode`. See [Postal Code Time
Zones](/api-reference/scrub/scrub-single#postal-code-time-zones). Requires
`version=8` or higher
`1` if a **manually dialed, live-agent** marketing call may be placed to this
number right now; `0` otherwise. Combines `ResultCode`, `DoNotCallToday` and
the calling window. See [Is the call
allowed?](/api-reference/scrub/output-guide#is-the-call-allowed) for the rules
and for when this flag applies to you. Requires `version=8` or higher
Same checks, for calls placed by an **autodialer** (federal or state
definition). Wireless and VoIP numbers return `0` unless a Permission (`P`)
EBR — express written consent — is on file. Requires `version=8` or higher
Same checks, for calls using an **artificial, prerecorded or AI-generated
voice**. `1` only when a Permission (`P`) EBR is on file and still valid
(`EBRType` is `P` and `ResultCode` is `E`, `O`, `G` or `H`) — any line type.
Clean numbers without consent return `0`. See [Compliance for AI Voice
Agents](/api-reference/scrub/ai-voice-agents). Requires `version=8` or higher
For the full field list see the [Output Guide](/api-reference/scrub/output-guide).
## Multiple Numbers with Identifiers
Comma-separate multiple phone numbers with their identifiers:
```
phoneList=5039367181|ACCT-001,7075276405|ACCT-002,7072842774|ACCT-003
```
### Example
```javascript theme={null}
const records = [
{ phone: "5039367181", accountId: "ACCT-001" },
{ phone: "7075276405", accountId: "ACCT-002" },
{ phone: "7072842774", accountId: "ACCT-003" },
];
const phoneList = records.map((r) => `${r.phone}|${r.accountId}`).join(",");
// phoneList = "5039367181|ACCT-001,7075276405|ACCT-002,7072842774|ACCT-003"
const response = await fetch(
`https://www.dncscrub.com/app/main/rpc/scrub?phoneList=${encodeURIComponent(
phoneList
)}&version=8&output=json`,
{
method: "GET",
headers: { loginId: "YOUR_API_KEY" },
}
);
const results = await response.json();
// Match results back to original records
results.forEach((result) => {
console.log(`Account ${result.Reserved}: ${result.ResultCode}`);
});
```
## Use Cases
Pass your CRM Record ID to update records directly after scrubbing
Track which phone number belongs to which customer in large batches
Include transaction IDs for compliance logging
Pass primary keys to enable efficient database updates
## Best Practices
The unique identifier should not contain commas (`,`) or pipe characters (`|`)
as these are used as delimiters. The pipe fields are positional: the second
is always the identifier and the third is always the postal code, so use
`PHONE||POSTALCODE` to pass a postal code without an identifier.
* Keep identifiers reasonably short
* Use URL-safe characters
* Consider encoding special characters if needed
# Add Phone Numbers
Source: https://docs.dncscrub.com/api-reference/trustcall/add
POST https://dataapi.dncscrub.com/v1.5/TrustCall/Add
Add phone numbers to TrustCall monitoring for automatic spam score checks
Add phone numbers to TrustCall monitoring. Numbers will be automatically checked for carrier spam scores.
When first added, scores may show as `Processing` until checked with each carrier (typically within 24 hours).
## Request
### Headers
Your API Key (LoginId from your DNCScrub account)
Must be `application/json`
### Request Body
The request body is a JSON array of phone number objects:
10-digit North American phone number (without leading 1 or +)
Optional description or label for the phone number (max 50 characters)
Service type for the phone number. If omitted, defaults to `Remediation` for accounts with remediation service enabled, or `Scanning` for all other accounts.
**Valid values:**
| Value | Description |
| ------------------------- | --------------------------------------------------------- |
| `Scanning` | Standard monitoring service |
| `Remediation` | Remediation service |
| `Remediation Daily Scans` | Remediation with daily scanning |
| `One Time Scan` | A single scan; the number is never re-scanned |
| `OTS Remediation` | A one-time remediation scan; the number is not re-scanned |
Each value requires the corresponding service to be enabled on your account. If the service is
not enabled, the item's `Response` field returns ` service type is not allowed for this account`.
If an unrecognized value is provided, the item's `Response` field returns `Invalid Service type` (HTTP status remains 200).
Optional legal entity identifier
## Example Request
```bash cURL theme={null}
curl --location --request POST \
'https://dataapi.dncscrub.com/v1.5/TrustCall/Add' \
--header 'loginId: YOUR_API_KEY' \
--header 'Content-Type: application/json' \
--data-raw '[
{ "Phone": "5039367187", "Label": "Customer Service", "LegalEntityId": 123 },
{ "Phone": "8084565302", "Label": "Marketing", "LegalEntityId": 456 }
]'
```
```javascript JavaScript theme={null}
const response = await fetch(
'https://dataapi.dncscrub.com/v1.5/TrustCall/Add',
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
'loginId': 'YOUR_API_KEY'
},
body: JSON.stringify([
{ Phone: '5039367187', Label: 'Customer Service', LegalEntityId: 123 },
{ Phone: '8084565302', Label: 'Marketing', LegalEntityId: 456 }
])
}
);
const data = await response.json();
console.log(data);
```
```csharp C# theme={null}
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Add("loginId", "YOUR_API_KEY");
var requestData = new[]
{
new { Phone = "5039367187", Label = "Customer Service", LegalEntityId = 123 },
new { Phone = "8084565302", Label = "Marketing", LegalEntityId = 456 }
};
var content = new StringContent(
JsonSerializer.Serialize(requestData),
Encoding.UTF8,
"application/json"
);
var response = await client.PostAsync(
"https://dataapi.dncscrub.com/v1.5/TrustCall/Add",
content
);
var result = await response.Content.ReadAsStringAsync();
Console.WriteLine(result);
}
```
```json Response theme={null}
[
{
"Response": "Phone number added to monitor",
"Phone": "5039367187",
"LegalEntityId": 123,
"CurrScore": "Processing",
"MaxScore": "Processing",
"HistoricalScore": "0",
"VerizonScore": "Processing",
"ATTScore": "Processing",
"TMobileScore": "Processing",
"RoboKillerStatus": "Processing",
"NomoroboStatus": "Processing",
"FTCComplaints": null
},
{
"Response": "Phone number added to monitor",
"Phone": "8084565302",
"LegalEntityId": 456,
"CurrScore": "Processing",
"MaxScore": "Processing",
"HistoricalScore": "0",
"VerizonScore": "Processing",
"ATTScore": "Processing",
"TMobileScore": "Processing",
"RoboKillerStatus": "Processing",
"NomoroboStatus": "Processing",
"FTCComplaints": null
}
]
```
## Response Fields
Status message indicating the result of the add operation
The phone number that was added
The legal entity identifier associated with the phone number
Current average carrier spam score: `Clean`, `Medium`, `High`, or `Processing`
Maximum score recorded in the last 15 days
Historical score from 0-5 (0-1 = no issues, 5 = 50%+ high spam history)
Verizon carrier status: `Clean`, `Flagged`, or `Processing`
AT\&T carrier status: `Clean`, `Flagged`, or `Processing`
T-Mobile carrier status: `Clean`, `Flagged`, or `Processing`
RoboKiller app status: `Clean`, `Flagged`, or `Processing`
Nomorobo app status: `Clean`, `Flagged`, or `Processing`
Array of FTC complaints associated with the number, or `null` if none
## Error Responses
| Status | Description |
| ---------------- | ------------------------------------------- |
| 400 Bad Request | Invalid request body or phone number format |
| 401 Unauthorized | Invalid or missing API key |
## Limits
* Maximum **50 phone numbers** per add request
# Flags Removed Summary
Source: https://docs.dncscrub.com/api-reference/trustcall/flags-removed-summary
GET https://dataapi.dncscrub.com/v1.5/TrustCall/FlagsRemovedSummary
Retrieve a summary of spam flags removed across carriers within a specified time period
Retrieve a summary of spam flags that have been removed across carriers within a specified time period. This endpoint provides counts of flags removed for AT\&T, Rogers/Bell, T-Mobile, Verizon, and Total flags removed.
## Request
### Headers
Your API Key (LoginId from your DNCScrub account)
### Query Parameters
Number of days to look back. Minimum is 1, maximum is 90. Defaults to 7.
## Example Request
```bash cURL theme={null}
curl --location --request GET \
'https://dataapi.dncscrub.com/v1.5/TrustCall/FlagsRemovedSummary?days=30' \
--header 'loginId: YOUR_API_KEY'
```
```javascript JavaScript theme={null}
const response = await fetch(
'https://dataapi.dncscrub.com/v1.5/TrustCall/FlagsRemovedSummary?days=30',
{
method: 'GET',
headers: { 'loginId': 'YOUR_API_KEY' }
}
);
const data = await response.json();
console.log(data);
```
```csharp C# theme={null}
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Add("loginId", "YOUR_API_KEY");
var response = await client.GetAsync(
"https://dataapi.dncscrub.com/v1.5/TrustCall/FlagsRemovedSummary?days=30"
);
var result = await response.Content.ReadAsStringAsync();
Console.WriteLine(result);
}
```
```json Response theme={null}
{
"Att": 5,
"Tmobile": 12,
"Verizon": 8,
"RogersBell": 0,
"Total": 25
}
```
## Response Fields
Number of AT\&T flags removed in the specified period. For Canadian accounts, this will be `0`.
Number of T-Mobile flags removed in the specified period
Number of Verizon flags removed in the specified period
Number of Rogers/Bell flags removed in the specified period. For US accounts, this will be `0`.
Total number of flags removed across all supported carriers in the specified period
## Error Responses
| Status | Description |
| ---------------- | --------------------------------------------------- |
| 400 Bad Request | Invalid `days` parameter (must be between 1 and 90) |
| 401 Unauthorized | Invalid or missing API key |
# Get Spam Scores
Source: https://docs.dncscrub.com/api-reference/trustcall/get
GET https://dataapi.dncscrub.com/v1.5/TrustCall/Get
Retrieve current carrier spam scores for monitored phone numbers
Retrieve current carrier spam scores for specific phone numbers being monitored.
For checking scores of all monitored numbers at once, use the [Get All](/api-reference/trustcall/get-all) endpoint instead.
## Request
### Headers
Your API Key (LoginId from your DNCScrub account)
### Query Parameters
Comma-separated list of 10-digit phone numbers (maximum 200 numbers)
## Example Request
```bash cURL theme={null}
curl --location --request GET \
'https://dataapi.dncscrub.com/v1.5/TrustCall/Get?phoneList=7867056421,3862847537' \
--header 'loginId: YOUR_API_KEY'
```
```javascript JavaScript theme={null}
const response = await fetch(
'https://dataapi.dncscrub.com/v1.5/TrustCall/Get?phoneList=7867056421,3862847537',
{
method: 'GET',
headers: { 'loginId': 'YOUR_API_KEY' }
}
);
const data = await response.json();
console.log(data);
```
```csharp C# theme={null}
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Add("loginId", "YOUR_API_KEY");
var url = "https://dataapi.dncscrub.com/v1.5/TrustCall/Get?phoneList=7867056421,3862847537";
var response = await client.GetStringAsync(url);
Console.WriteLine(response);
}
```
```json Response theme={null}
[
{
"Response": "Phone number current score",
"Phone": "7867056421",
"LegalEntityId": 123,
"CurrScore": "High",
"MaxScore": "High",
"HistoricalScore": "5",
"VerizonScore": "Flagged",
"ATTScore": "Flagged",
"TMobileScore": "Clean",
"RoboKillerStatus": "Clean",
"NomoroboStatus": "Flagged",
"FTCComplaints": [
{
"FTCComplaintId": "79923e06b1c74d47e6ad5826b7554046",
"Phone": "7867056421",
"CreatedDate": "08/15/2022 22:22:39",
"ViolationDate": "07/29/2022 12:04:00",
"City": "Jackson",
"State": "New Jersey",
"AreaCode": "732",
"Subject": "Dropped call or no message",
"RecordedMessageOrRobocall": "Y"
}
]
},
{
"Response": "Phone number current score",
"Phone": "3862847537",
"LegalEntityId": 456,
"CurrScore": "Clean",
"MaxScore": "Clean",
"HistoricalScore": "0",
"VerizonScore": "Clean",
"ATTScore": "Clean",
"TMobileScore": "Clean",
"RoboKillerStatus": "Clean",
"NomoroboStatus": "Clean",
"FTCComplaints": null
}
]
```
## Response Fields
Status message
The phone number that was checked
The legal entity identifier associated with the phone number
Current average carrier spam score:
* `Clean` - No spam flags
* `Medium` - Some carriers flagged
* `High` - Multiple carriers flagged
* `Processing` - Score check in progress
Maximum score recorded in the last 15 days
Historical score from 0-5:
* `0-1` - No significant issues
* `5` - 50%+ high spam history
Verizon carrier status: `Clean`, `Flagged`, or `Processing`
AT\&T carrier status: `Clean`, `Flagged`, or `Processing`
T-Mobile carrier status: `Clean`, `Flagged`, or `Processing`
RoboKiller app status: `Clean` or `Flagged`
Nomorobo app status: `Clean` or `Flagged`
Array of FTC complaints, or `null` if none. See FTC Complaint Fields below.
## FTC Complaint Fields
Unique complaint identifier
Phone number the complaint was filed against
When the complaint was filed
When the alleged violation occurred
Complainant's city
Complainant's state
Complainant's area code
Complaint category/subject
`Y` if this was a robocall complaint
## Error Responses
| Status | Description |
| ---------------- | ------------------------------------------------- |
| 400 Bad Request | Invalid phone number format or missing parameters |
| 401 Unauthorized | Invalid or missing API key |
## Limits
* Maximum **200 phone numbers** per GET request
* For larger batches, use POST to `/v1.5/TrustCall/Get` with a JSON array body
# Get All Spam Scores
Source: https://docs.dncscrub.com/api-reference/trustcall/get-all
GET https://dataapi.dncscrub.com/v1.5/TrustCall/GetAll
Retrieve carrier spam scores for all monitored phone numbers
Retrieve carrier spam scores for all phone numbers being monitored by your account.
The `X-Total-Count` response header contains the total number of phone numbers in your account.
## Request
### Headers
Your API Key (LoginId from your DNCScrub account)
### Query Parameters
Maximum number of records to return. Defaults to 15,000.
## Example Request
```bash cURL theme={null}
curl --location --request GET \
'https://dataapi.dncscrub.com/v1.5/TrustCall/GetAll' \
--header 'loginId: YOUR_API_KEY'
```
```javascript JavaScript theme={null}
const response = await fetch(
'https://dataapi.dncscrub.com/v1.5/TrustCall/GetAll',
{
method: 'GET',
headers: { 'loginId': 'YOUR_API_KEY' }
}
);
// Get total count from header
const totalCount = response.headers.get('X-Total-Count');
console.log(`Total numbers monitored: ${totalCount}`);
const data = await response.json();
console.log(data);
```
```csharp C# theme={null}
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Add("loginId", "YOUR_API_KEY");
var response = await client.GetAsync(
"https://dataapi.dncscrub.com/v1.5/TrustCall/GetAll"
);
// Get total count from header
if (response.Headers.TryGetValues("X-Total-Count", out var values))
{
Console.WriteLine($"Total numbers: {values.First()}");
}
var result = await response.Content.ReadAsStringAsync();
Console.WriteLine(result);
}
```
```json Response theme={null}
[
{
"Response": "Phone number current score",
"Phone": "7867056421",
"LegalEntityId": 123,
"CurrScore": "High",
"MaxScore": "High",
"HistoricalScore": "5",
"VerizonScore": "Flagged",
"ATTScore": "Flagged",
"TMobileScore": "Clean",
"RoboKillerStatus": "Clean",
"NomoroboStatus": "Flagged",
"FTCComplaints": [
{
"FTCComplaintId": "79923e06b1c74d47e6ad5826b7554046",
"Phone": "7867056421",
"CreatedDate": "08/15/2022 22:22:39",
"ViolationDate": "07/29/2022 12:04:00",
"City": "Jackson",
"State": "New Jersey",
"AreaCode": "732",
"Subject": "Dropped call or no message",
"RecordedMessageOrRobocall": "Y"
}
]
},
{
"Response": "Phone number current score",
"Phone": "5039367187",
"LegalEntityId": 456,
"CurrScore": "Clean",
"MaxScore": "Clean",
"HistoricalScore": "0",
"VerizonScore": "Clean",
"ATTScore": "Clean",
"TMobileScore": "Clean",
"RoboKillerStatus": "Clean",
"NomoroboStatus": "Clean",
"FTCComplaints": null
}
]
```
## Response Headers
| Header | Description |
| --------------- | --------------------------------------------- |
| `X-Total-Count` | Total number of phone numbers in your account |
## Response Fields
Status message
The phone number
The legal entity identifier associated with the phone number
Current average carrier spam score: `Clean`, `Medium`, `High`, or `Processing`
Maximum score recorded in the last 15 days
Historical score from 0-5 (0-1 = no issues, 5 = 50%+ high spam)
Verizon carrier status: `Clean`, `Flagged`, or `Processing`
AT\&T carrier status: `Clean`, `Flagged`, or `Processing`
T-Mobile carrier status: `Clean`, `Flagged`, or `Processing`
RoboKiller app status: `Clean` or `Flagged`
Nomorobo app status: `Clean` or `Flagged`
Array of FTC complaints, or `null` if none
## Error Responses
| Status | Description |
| --------------------- | -------------------------- |
| 400 Bad Request | Invalid request parameters |
| 401 Unauthorized | Invalid or missing API key |
| 413 Payload Too Large | Too many records requested |
## Pagination Example
```javascript theme={null}
async function getAllMonitoredNumbers(apiKey) {
const response = await fetch(
'https://dataapi.dncscrub.com/v1.5/TrustCall/GetAll?maxRecords=15000',
{
headers: { 'loginId': apiKey }
}
);
const totalCount = parseInt(response.headers.get('X-Total-Count'));
const results = await response.json();
console.log(`Retrieved ${results.length} of ${totalCount} total numbers`);
// Categorize by score
const flagged = results.filter(r => r.CurrScore === 'High');
const medium = results.filter(r => r.CurrScore === 'Medium');
const clean = results.filter(r => r.CurrScore === 'Clean');
return {
total: totalCount,
flagged: flagged.length,
medium: medium.length,
clean: clean.length,
results
};
}
```
# Get All Legal Entities
Source: https://docs.dncscrub.com/api-reference/trustcall/get-all-legal-entities
GET https://dataapi.dncscrub.com/v1.5/TrustCall/GetAllLegalEntities
Retrieve all legal entities associated with an account
Retrieve all legal entities associated with your account. Legal entities represent the business identities under which your phone numbers are registered.
## Request
### Headers
Your API Key (LoginId from your DNCScrub account)
## Example Request
```bash cURL theme={null}
curl --location --request GET \
'https://dataapi.dncscrub.com/v1.5/TrustCall/GetAllLegalEntities' \
--header 'loginId: YOUR_API_KEY'
```
```javascript JavaScript theme={null}
const response = await fetch(
'https://dataapi.dncscrub.com/v1.5/TrustCall/GetAllLegalEntities',
{
method: 'GET',
headers: { 'loginId': 'YOUR_API_KEY' }
}
);
const data = await response.json();
console.log(data);
```
```csharp C# theme={null}
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Add("loginId", "YOUR_API_KEY");
var response = await client.GetAsync(
"https://dataapi.dncscrub.com/v1.5/TrustCall/GetAllLegalEntities"
);
var result = await response.Content.ReadAsStringAsync();
Console.WriteLine(result);
}
```
```json Response theme={null}
[
{
"LegalEntityId": 123,
"AcctId": "YOUR_ACCOUNT_ID",
"IsDefault": true,
"LegalName": "Acme Corporation",
"Ein": "***6789",
"PrimaryPhoneNumber": "5551234567",
"StreetAddress": "123 Main Street",
"City": "New York",
"State": "NY",
"Zip": "10001",
"CountryCode": "US"
},
{
"LegalEntityId": 456,
"AcctId": "YOUR_ACCOUNT_ID",
"IsDefault": false,
"LegalName": "Acme Subsidiary LLC",
"Ein": "***4321",
"PrimaryPhoneNumber": "5559876543",
"StreetAddress": "456 Oak Avenue",
"City": "Los Angeles",
"State": "CA",
"Zip": "90001",
"CountryCode": "US"
}
]
```
## Response Fields
Unique identifier for the legal entity
The account ID the legal entity belongs to
Whether this is the default legal entity for the account
The registered legal name of the business entity
Masked Employer Identification Number (EIN) showing only the last 4 digits (e.g., `***6789`)
Primary contact phone number for the legal entity
Street address of the legal entity
City of the legal entity's address
State or province code
ZIP or postal code
Two-letter country code (e.g., "US")
## Error Responses
| Status | Description |
| ---------------- | -------------------------- |
| 401 Unauthorized | Invalid or missing API key |
# Create Legal Entity
Source: https://docs.dncscrub.com/api-reference/trustcall/legal-entity-create
POST https://dataapi.dncscrub.com/v1.5/legalentity/Create
Create a new legal entity for your account
Create a new legal entity for your account. Legal entities represent the business identities under which your phone numbers are registered and are used for carrier registration and compliance purposes.
## Request
### Headers
Your API Key (LoginId from your DNCScrub account)
Must be `application/json`
### Request Body
The registered legal name of the business entity
Set to `true` to make this the default legal entity for the account
Employer Identification Number (EIN), digits without a dash (e.g., "987654321")
Street address of the legal entity
City of the legal entity's address
State or province code (e.g., "NY", "CA")
ZIP or postal code
Two-letter country code (e.g., "US")
Industry identifier code. See the table below for valid values.
| ID | Industry |
| -- | ------------------------- |
| 1 | Education |
| 2 | Transportation |
| 3 | Retail |
| 4 | Delivery/Shipping |
| 5 | Government |
| 6 | Health Care |
| 7 | Financial |
| 8 | Public Service |
| 9 | Real Estate |
| 10 | Legal |
| 11 | Restaurant/Food Services |
| 12 | Automotive |
| 13 | Religious |
| 14 | Veterinary Services |
| 15 | Trade Contractors |
| 16 | Personal Services |
| 17 | Business Services |
| 18 | Hospitality/Entertainment |
| 19 | Insurance |
| 20 | Manufacturing |
| 21 | Other Business |
| 22 | Telecommunications |
| 23 | Technology |
| 24 | Non-Profit |
| 25 | Travel |
| 26 | Utilities |
| 27 | Prison |
Primary contact phone number for the legal entity
Name of the primary contact person
Email address of the primary contact
Phone number of the primary contact person
Number of employees at the company
Estimated number of outbound calls per month
Dun & Bradstreet DUNS number
Company website URL
"Doing Business As" name, if different from legal name
Business license number
Description of the purpose of outbound calls
Description of potential negative reaction
## Example Request
```bash cURL theme={null}
curl --location --request POST \
'https://dataapi.dncscrub.com/v1.5/legalentity/Create' \
--header 'loginId: YOUR_API_KEY' \
--header 'Content-Type: application/json' \
--data-raw '{
"IsDefault": false,
"LegalName": "Test New Company LLC",
"EIN": "123456789",
"StreetAddress": "123 Main Street",
"City": "Austin",
"State": "TX",
"Zip": "78701",
"CountryCode": "US",
"IndustryId": "7",
"PrimaryContactName": "John Doe",
"PrimaryContactEmail": "john.doe@testcompany.com",
"PrimaryContactPhoneNumber": "5125551234",
"PrimaryPhoneNumber": "5125550000",
"CallsPerMonth": 10000,
"EmployeeCount": 50,
"DunsNumber": "123456789",
"Url": "https://www.testcompany.com",
"Dba": "Test Co",
"LicenceNumber": "LIC-12345",
"CallPurposeDescription": "Customer service follow-up calls",
"PotentialNegativeReaction": "Low"
}'
```
```javascript JavaScript theme={null}
const response = await fetch(
'https://dataapi.dncscrub.com/v1.5/legalentity/Create',
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
'loginId': 'YOUR_API_KEY'
},
body: JSON.stringify({
LegalName: 'Test New Company LLC',
IsDefault: false,
EIN: '123456789',
StreetAddress: '123 Main Street',
City: 'Austin',
State: 'TX',
Zip: '78701',
CountryCode: 'US',
IndustryId: '7',
PrimaryPhoneNumber: '5125550000',
PrimaryContactName: 'John Doe',
PrimaryContactEmail: 'john.doe@testcompany.com',
PrimaryContactPhoneNumber: '5125551234',
EmployeeCount: 50,
CallsPerMonth: 10000,
DunsNumber: '123456789',
Url: 'https://www.testcompany.com',
Dba: 'Test Co',
LicenceNumber: 'LIC-12345',
CallPurposeDescription: 'Customer service follow-up calls',
PotentialNegativeReaction: 'Low'
})
}
);
const data = await response.json();
console.log(data);
```
```csharp C# theme={null}
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Add("loginId", "YOUR_API_KEY");
var requestData = new
{
LegalName = "Test New Company LLC",
IsDefault = false,
EIN = "123456789",
StreetAddress = "123 Main Street",
City = "Austin",
State = "TX",
Zip = "78701",
CountryCode = "US",
IndustryId = "7",
PrimaryPhoneNumber = "5125550000",
PrimaryContactName = "John Doe",
PrimaryContactEmail = "john.doe@testcompany.com",
PrimaryContactPhoneNumber = "5125551234",
EmployeeCount = 50,
CallsPerMonth = 10000,
DunsNumber = "123456789",
Url = "https://www.testcompany.com",
Dba = "Test Co",
LicenceNumber = "LIC-12345",
CallPurposeDescription = "Customer service follow-up calls",
PotentialNegativeReaction = "Low"
};
var content = new StringContent(
JsonSerializer.Serialize(requestData),
Encoding.UTF8,
"application/json"
);
var response = await client.PostAsync(
"https://dataapi.dncscrub.com/v1.5/legalentity/Create",
content
);
var result = await response.Content.ReadAsStringAsync();
Console.WriteLine(result);
}
```
```json Response theme={null}
{
"LegalEntityId": 68257,
"AcctId": "YOUR_ACCOUNT_ID"
}
```
## Response Fields
The unique identifier assigned to the newly created legal entity
The account ID the legal entity belongs to
## Error Responses
| Status | Description |
| ------------------------- | -------------------------------------------------------------------- |
| 400 Bad Request | Missing required fields (e.g., `LegalName`) or request body is empty |
| 401 Unauthorized | Invalid or missing API key |
| 409 Conflict | A legal entity with the same `LegalName` already exists |
| 500 Internal Server Error | Server error during processing |
# Update Legal Entity
Source: https://docs.dncscrub.com/api-reference/trustcall/legal-entity-update
PUT https://dataapi.dncscrub.com/v1.5/legalentity/Update
Update an existing legal entity for your account
Update an existing legal entity for your account. Use this endpoint to modify legal entity information such as address, contact details, or business information.
## Request
### Headers
Your API Key (LoginId from your DNCScrub account)
Must be `application/json`
### Request Body
The unique identifier of the legal entity to update
The registered legal name of the business entity
Set to `true` to make this the default legal entity for the account
Employer Identification Number (EIN), digits without a dash (e.g., "987654321")
Street address of the legal entity
City of the legal entity's address
State or province code (e.g., "NY", "CA")
ZIP or postal code
Two-letter country code (e.g., "US")
Industry identifier code. See the table below for valid values.
| ID | Industry |
| -- | ------------------------- |
| 1 | Education |
| 2 | Transportation |
| 3 | Retail |
| 4 | Delivery/Shipping |
| 5 | Government |
| 6 | Health Care |
| 7 | Financial |
| 8 | Public Service |
| 9 | Real Estate |
| 10 | Legal |
| 11 | Restaurant/Food Services |
| 12 | Automotive |
| 13 | Religious |
| 14 | Veterinary Services |
| 15 | Trade Contractors |
| 16 | Personal Services |
| 17 | Business Services |
| 18 | Hospitality/Entertainment |
| 19 | Insurance |
| 20 | Manufacturing |
| 21 | Other Business |
| 22 | Telecommunications |
| 23 | Technology |
| 24 | Non-Profit |
| 25 | Travel |
| 26 | Utilities |
| 27 | Prison |
Primary contact phone number for the legal entity
Name of the primary contact person
Email address of the primary contact
Phone number of the primary contact person
Number of employees at the company
Estimated number of outbound calls per month
Dun & Bradstreet DUNS number
Company website URL
"Doing Business As" name, if different from legal name
Business license number
Description of the purpose of outbound calls
Description of potential negative reaction
## Example Request
```bash cURL theme={null}
curl --location --request PUT \
'https://dataapi.dncscrub.com/v1.5/legalentity/Update' \
--header 'loginId: YOUR_API_KEY' \
--header 'Content-Type: application/json' \
--data-raw '{
"LegalEntityId": 68257,
"LegalName": "Updated Company LLC",
"IsDefault": true,
"EIN": "987654321",
"StreetAddress": "456 Updated Avenue",
"City": "Dallas",
"State": "TX",
"Zip": "75201",
"CountryCode": "US",
"IndustryId": "22",
"PrimaryContactName": "Jane Smith",
"PrimaryContactEmail": "jane.smith@updatedcompany.com",
"PrimaryContactPhoneNumber": "2145551234",
"PrimaryPhoneNumber": "2145550000",
"CallsPerMonth": 25000,
"EmployeeCount": 1000,
"DunsNumber": "987654321",
"Url": "https://www.updatedcompany.com",
"Dba": "Updated Co",
"LicenceNumber": "LIC-98765",
"CallPurposeDescription": "Sales and marketing outreach",
"PotentialNegativeReaction": "Medium"
}'
```
```javascript JavaScript theme={null}
const response = await fetch(
'https://dataapi.dncscrub.com/v1.5/legalentity/Update',
{
method: 'PUT',
headers: {
'Content-Type': 'application/json',
'loginId': 'YOUR_API_KEY'
},
body: JSON.stringify({
LegalEntityId: 68257,
LegalName: 'Updated Company LLC',
IsDefault: true,
EIN: '987654321',
StreetAddress: '456 Updated Avenue',
City: 'Dallas',
State: 'TX',
Zip: '75201',
CountryCode: 'US',
IndustryId: '22',
PrimaryContactName: 'Jane Smith',
PrimaryContactEmail: 'jane.smith@updatedcompany.com',
PrimaryContactPhoneNumber: '2145551234',
PrimaryPhoneNumber: '2145550000',
CallsPerMonth: 25000,
EmployeeCount: 1000,
DunsNumber: '987654321',
Url: 'https://www.updatedcompany.com',
Dba: 'Updated Co',
LicenceNumber: 'LIC-98765',
CallPurposeDescription: 'Sales and marketing outreach',
PotentialNegativeReaction: 'Medium'
})
}
);
const data = await response.json();
console.log(data);
```
```csharp C# theme={null}
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Add("loginId", "YOUR_API_KEY");
var requestData = new
{
LegalEntityId = 68257,
LegalName = "Updated Company LLC",
IsDefault = true,
EIN = "987654321",
StreetAddress = "456 Updated Avenue",
City = "Dallas",
State = "TX",
Zip = "75201",
CountryCode = "US",
IndustryId = "22",
PrimaryContactName = "Jane Smith",
PrimaryContactEmail = "jane.smith@updatedcompany.com",
PrimaryContactPhoneNumber = "2145551234",
PrimaryPhoneNumber = "2145550000",
CallsPerMonth = 25000,
EmployeeCount = 1000,
DunsNumber = "987654321",
Url = "https://www.updatedcompany.com",
Dba = "Updated Co",
LicenceNumber = "LIC-98765",
CallPurposeDescription = "Sales and marketing outreach",
PotentialNegativeReaction = "Medium"
};
var content = new StringContent(
JsonSerializer.Serialize(requestData),
Encoding.UTF8,
"application/json"
);
var response = await client.PutAsync(
"https://dataapi.dncscrub.com/v1.5/legalentity/Update",
content
);
var result = await response.Content.ReadAsStringAsync();
Console.WriteLine(result);
}
```
```json Response theme={null}
{
"LegalEntityId": 68257,
"AcctId": "YOUR_ACCOUNT_ID"
}
```
## Response Fields
The unique identifier of the updated legal entity
The account ID the legal entity belongs to
## Error Responses
| Status | Description |
| ------------------------- | ------------------------------------------------------------------------------- |
| 400 Bad Request | Missing required field (`LegalEntityId`) or request body is empty |
| 401 Unauthorized | Invalid or missing API key |
| 404 Not Found | Legal entity with the specified `LegalEntityId` does not exist for your account |
| 500 Internal Server Error | Server error during processing |
Use the [Get All Legal Entities](/api-reference/trustcall/get-all-legal-entities) endpoint to retrieve the `LegalEntityId` values for your account's legal entities.
# One-Time Scan API
Source: https://docs.dncscrub.com/api-reference/trustcall/one-time-scan
Check phone number reputation without ongoing monitoring. API only available to telco carriers
# TrustCall One-Time Scan API
The One-Time Scan API allows you to check phone number reputation without adding the number to ongoing monitoring.
This API is only available for telco carriers. For end-users the TrustCall
Premier (Monitor) API should be used
## When to Use One-Time Scan
* Checking numbers before acquisition
* One-off reputation checks
* Numbers you don't need to continuously monitor
## vs. TrustCall Premier
| Feature | One-Time Scan | Premier |
| ------------------- | ------------- | ------- |
| Ongoing monitoring | No | Yes |
| Carrier scores | Yes | Yes |
| Historical tracking | No | Yes |
| FTC complaints | No | Yes |
## Getting Started
Contact [support@dnc.com](mailto:support@dnc.com) to:
* Get API access
* Understand pricing
## Related
Full-featured monitoring API with historical tracking
# One-Time Scan Status
Source: https://docs.dncscrub.com/api-reference/trustcall/one-time-scan-status
GET https://dataapi.dncscrub.com/v1.5/TrustCall/OneTimeScan
Check the status of a one-time scan job
Check the status of a one-time scan job submitted via the [Submit One-Time Scan](/api-reference/trustcall/one-time-scan-submit) endpoint.
## Request
### Headers
Your API Key (LoginId from your DNCScrub account)
### Query Parameters
The job ID (UUID) returned from the POST OneTimeScan endpoint
## Example Request
```bash cURL theme={null}
curl --location --request GET \
'https://dataapi.dncscrub.com/v1.5/TrustCall/OneTimeScan?jobId=a1b2c3d4-e5f6-7890-abcd-ef1234567890' \
--header 'loginId: YOUR_API_KEY'
```
```javascript JavaScript theme={null}
const response = await fetch(
'https://dataapi.dncscrub.com/v1.5/TrustCall/OneTimeScan?jobId=a1b2c3d4-e5f6-7890-abcd-ef1234567890',
{
method: 'GET',
headers: { 'loginId': 'YOUR_API_KEY' }
}
);
const data = await response.json();
console.log(data);
```
```csharp C# theme={null}
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Add("loginId", "YOUR_API_KEY");
var url = "https://dataapi.dncscrub.com/v1.5/TrustCall/OneTimeScan?jobId=a1b2c3d4-e5f6-7890-abcd-ef1234567890";
var response = await client.GetStringAsync(url);
Console.WriteLine(response);
}
```
```json Response (Processing) theme={null}
{
"JobId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"Status": "Processing",
"PhoneCount": 3,
"ProcessedCount": 1
}
```
```json Response (Complete) theme={null}
{
"JobId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"Status": "Complete",
"PhoneCount": 3,
"ProcessedCount": 3,
"Results": [
{
"Phone": "5039367187",
"CurrScore": "Clean",
"VerizonScore": "Clean",
"ATTScore": "Clean",
"TMobileScore": "Clean",
"RoboKillerStatus": "Clean",
"NomoroboStatus": "Clean",
"FTCComplaints": null
},
{
"Phone": "8084565302",
"CurrScore": "Medium",
"VerizonScore": "Clean",
"ATTScore": "Flagged",
"TMobileScore": "Clean",
"RoboKillerStatus": "Clean",
"NomoroboStatus": "Clean",
"FTCComplaints": null
},
{
"Phone": "7867056421",
"CurrScore": "High",
"VerizonScore": "Flagged",
"ATTScore": "Flagged",
"TMobileScore": "Clean",
"RoboKillerStatus": "Clean",
"NomoroboStatus": "Flagged",
"FTCComplaints": [
{
"FTCComplaintId": "79923e06b1c74d47e6ad5826b7554046",
"Phone": "7867056421",
"CreatedDate": "08/15/2022 22:22:39",
"ViolationDate": "07/29/2022 12:04:00",
"Subject": "Dropped call or no message"
}
]
}
]
}
```
## Response Fields
The scan job identifier
Current job status:
* `Submitted` - Job received, not yet started
* `Processing` - Scan in progress
* `Complete` - Scan finished, results available
* `Failed` - Scan encountered an error
Total number of phone numbers in the job
Number of phone numbers processed so far
Array of scan results (only present when `Status` is `Complete`). See result fields below.
## Result Fields
The phone number that was scanned
Current average carrier spam score: `Clean`, `Medium`, or `High`
Verizon carrier status: `Clean` or `Flagged`
AT\&T carrier status: `Clean` or `Flagged`
T-Mobile carrier status: `Clean` or `Flagged`
RoboKiller app status (if `carrierandapps` scan type)
Nomorobo app status (if `carrierandapps` scan type)
Array of FTC complaints (if `carrierandapps` scan type)
## Error Responses
| Status | Description |
| ---------------- | ---------------------------------- |
| 400 Bad Request | Invalid or missing job ID |
| 401 Unauthorized | Invalid or missing API key |
| 403 Forbidden | Job belongs to a different account |
| 500 Server Error | Internal server error |
## Polling Example
```javascript theme={null}
async function waitForScanResults(jobId, apiKey, maxWaitMs = 300000) {
const startTime = Date.now();
const pollInterval = 5000; // 5 seconds
while (Date.now() - startTime < maxWaitMs) {
const response = await fetch(
`https://dataapi.dncscrub.com/v1.5/TrustCall/OneTimeScan?jobId=${jobId}`,
{ headers: { 'loginId': apiKey } }
);
const data = await response.json();
if (data.Status === 'Complete') {
return data.Results;
}
if (data.Status === 'Failed') {
throw new Error('Scan job failed');
}
console.log(`Processing: ${data.ProcessedCount}/${data.PhoneCount}`);
await new Promise(resolve => setTimeout(resolve, pollInterval));
}
throw new Error('Scan timed out');
}
```
# Submit One-Time Scan
Source: https://docs.dncscrub.com/api-reference/trustcall/one-time-scan-submit
POST https://dataapi.dncscrub.com/v1.5/TrustCall/OneTimeScan
Submit a batch of phone numbers for one-time carrier spam score scanning
Submit a batch of phone numbers for one-time carrier spam score scanning. Results are delivered asynchronously via webhook notification.
Unlike TrustCall monitoring, one-time scans do not add numbers to ongoing
monitoring. Results are delivered to your webhook URL when the scan completes.
## Request
### Headers
Your API Key (LoginId from your DNCScrub account)
Must be `application/json`
### Request Body
Array of 10-digit phone number strings to scan
Webhook URL where scan results will be POSTed when complete. Maximum 1500 characters.
Consider using [webhook.site](https://webhook.site) to generate a temporary
URL for testing. It lets you inspect the exact payload and headers sent by the
callback, making it easy to understand the webhook structure before
implementing your production endpoint.
Optional API key to include in the webhook notification header. Maximum 1500 characters.
Type of scan to perform: - `carrier` - Carrier scores only (Verizon, AT\&T,
T-Mobile) - `carrierandapps` - Carrier scores plus app scores (RoboKiller,
Nomorobo, FTC complaints)
Set to `true` to test your webhook URL without performing an actual scan. The system will send a test payload to verify your endpoint is reachable.
## Example Request
```bash cURL theme={null}
curl --location --request POST \
'https://dataapi.dncscrub.com/v1.5/TrustCall/OneTimeScan' \
--header 'loginId: YOUR_API_KEY' \
--header 'Content-Type: application/json' \
--data-raw '{
"PhoneNumbers": ["5039367187", "8084565302", "7867056421"],
"NotificationURL": "https://your-server.com/webhook/trustcall",
"NotificationAPIKey": "your-webhook-api-key",
"ScanType": "carrierandapps"
}'
```
```javascript JavaScript theme={null}
const response = await fetch(
"https://dataapi.dncscrub.com/v1.5/TrustCall/OneTimeScan",
{
method: "POST",
headers: {
"Content-Type": "application/json",
loginId: "YOUR_API_KEY",
},
body: JSON.stringify({
PhoneNumbers: ["5039367187", "8084565302", "7867056421"],
NotificationURL: "https://your-server.com/webhook/trustcall",
NotificationAPIKey: "your-webhook-api-key",
ScanType: "carrierandapps",
}),
}
);
const data = await response.json();
console.log(data);
```
```csharp C# theme={null}
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Add("loginId", "YOUR_API_KEY");
var requestData = new
{
PhoneNumbers = new[] { "5039367187", "8084565302", "7867056421" },
NotificationURL = "https://your-server.com/webhook/trustcall",
NotificationAPIKey = "your-webhook-api-key",
ScanType = "carrierandapps"
};
var content = new StringContent(
JsonSerializer.Serialize(requestData),
Encoding.UTF8,
"application/json"
);
var response = await client.PostAsync(
"https://dataapi.dncscrub.com/v1.5/TrustCall/OneTimeScan",
content
);
var result = await response.Content.ReadAsStringAsync();
Console.WriteLine(result);
}
```
```json Response theme={null}
{
"JobId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"Status": "Submitted",
"PhoneCount": 3
}
```
## Response Fields
Unique identifier for the scan job. Use this to check scan status.
Initial status of the scan: `Submitted`
Number of phone numbers submitted for scanning
## Webhook Notification
When the scan completes, results are POSTed to your `NotificationURL`:
```json theme={null}
{
"JobId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"Status": "Complete",
"Results": [
{
"Phone": "5039367187",
"CurrScore": "Clean",
"VerizonScore": "Clean",
"ATTScore": "Clean",
"TMobileScore": "Clean",
"RoboKillerStatus": "Clean",
"NomoroboStatus": "Clean",
"FTCComplaints": null
}
]
}
```
## Error Responses
| Status | Description |
| ---------------- | ---------------------------------------------------------------- |
| 400 Bad Request | Invalid request body or phone number format |
| 401 Unauthorized | Invalid or missing API key |
| 403 Forbidden | Account not authorized for one-time scan or insufficient credits |
| 500 Server Error | Internal server error |
## Scan Types
| Scan Type | Included Data |
| ---------------- | ----------------------------------------------------- |
| `carrier` | Verizon, AT\&T, T-Mobile scores |
| `carrierandapps` | Carrier scores + RoboKiller, Nomorobo, FTC complaints |
# TrustCall Overview
Source: https://docs.dncscrub.com/api-reference/trustcall/overview
Monitor phone number reputation and spam scores
# TrustCall API
TrustCall provides real-time phone number reputation monitoring, including spam scores from major carriers, app scores, and FTC complaints.
## What is TrustCall?
TrustCall monitors your outbound phone numbers to detect:
* **Carrier spam flags** - When carriers label your number as spam/scam
* **App blocking** - When apps like RoboKiller or Nomorobo flag your number
* **FTC complaints** - Consumer complaints filed against your number
## Why Monitor Your Numbers?
If your outbound numbers are flagged as spam, your calls won't connect - leading to lost business and wasted dialing costs.
Proactive monitoring helps you:
* Identify flagged numbers before they impact your business
* Take corrective action quickly
* Maintain high connection rates
## Available APIs
Full-featured API with carrier-specific scores, historical data, and FTC complaints.
Check phone number reputation without ongoing monitoring.
## TrustCall Premier Features
| Feature | Description |
| -------------------- | --------------------------------------------------- |
| **Carrier Scores** | Individual scores from Verizon, AT\&T, and T-Mobile |
| **Average Score** | Combined score across all carriers |
| **Historical Score** | 15-day historical spam score trend |
| **App Scores** | RoboKiller and Nomorobo status |
| **FTC Complaints** | Consumer complaints with details |
## Score Values
### Carrier Scores (Verizon, AT\&T, T-Mobile)
| Score | Meaning |
| ------------ | ----------------------------------- |
| `Clean` | Not flagged by this carrier |
| `Flagged` | Marked as spam/scam by this carrier |
| `Processing` | Recently added, not yet checked |
### Combined Scores (CurrScore, MaxScore)
| Score | Meaning |
| ------------ | ------------------------------- |
| `Clean` | No spam issues detected |
| `Medium` | Some flags detected |
| `High` | Significant spam flags |
| `Processing` | Recently added, not yet checked |
### Historical Score
| Score | Meaning |
| ----- | --------------------------------------------------- |
| `0-1` | No issues in last 15 days |
| `2-3` | Occasional flags |
| `4-5` | Frequent flags (50%+ of checks had high spam score) |
## Workflow
Add your outbound phone numbers to TrustCall monitoring.
TrustCall continuously checks your numbers with carriers.
Query scores before using a number for outbound calls.
Remove numbers you no longer use from monitoring.
# TrustCall Premier (Monitor) API
Source: https://docs.dncscrub.com/api-reference/trustcall/premier
Full-featured phone number reputation monitoring API
# TrustCall Premier API
TrustCall Premier (also called TrustCall Monitor) provides comprehensive phone number reputation monitoring with carrier-specific scores, historical data, app scores, and FTC complaints.
## Base URL
```
https://trustcallapi.dncscrub.com/v1.4/trustcall
```
## Authentication
All API calls require two headers:
| Header | Value |
| -------------- | ------------------ |
| `loginId` | Your API Key |
| `Content-Type` | `application/json` |
***
## Add Phone Numbers
Add phone numbers to TrustCall monitoring.
### Endpoint
```
POST https://trustcallapi.dncscrub.com/v1.4/trustcall/add
```
### Request Body
```json theme={null}
[
{
"Phone": "5039367187",
"Label": "Customer Service",
"LegalEntityId": 123
},
{
"Phone": "8084565302",
"Label": "Marketing",
"LegalEntityId": 456
}
]
```
| Field | Required | Description |
| --------------- | -------- | --------------------------------- |
| `Phone` | Yes | 10-digit phone number |
| `Label` | No | Description (max 50 characters) |
| `LegalEntityId` | No | Legal entity identifier (integer) |
### Example Request
```bash theme={null}
curl --location --request POST \
'https://trustcallapi.dncscrub.com/v1.4/trustcall/add' \
--header 'Content-Type: application/json' \
--header 'loginId: YOUR_API_KEY' \
--data-raw '[
{"Phone": "5039367187", "Label": "Customer Service", "LegalEntityId": 123},
{"Phone": "8084565302", "Label": "Marketing", "LegalEntityId": 456}
]'
```
### Response
```json theme={null}
[
{
"Response": "Phone number added to monitor",
"Phone": "5039367187",
"LegalEntityId": 123,
"CurrScore": "Clean",
"MaxScore": "Clean",
"HistoricalScore": "0",
"VerizonScore": "Clean",
"ATTScore": "Clean",
"TMobileScore": "Clean",
"RoboKillerStatus": "Clean",
"NomoroboStatus": "Clean",
"FTCComplaints": null
}
]
```
When first added, scores may show as `Processing` until checked with each
carrier (within 24 hours).
***
## Check Scores
Get current scores for monitored phone numbers.
### Endpoint
```
GET/POST https://trustcallapi.dncscrub.com/v1.4/trustcall/get
```
### Using GET (up to 200 numbers)
```bash theme={null}
curl --location --request GET \
'https://trustcallapi.dncscrub.com/v1.4/trustcall/get?phoneList=7867056421,3862847537' \
--header 'Content-Type: application/json' \
--header 'loginId: YOUR_API_KEY'
```
### Using POST (for larger batches)
```bash theme={null}
curl --location --request POST \
'https://trustcallapi.dncscrub.com/v1.4/trustcall/get' \
--header 'Content-Type: application/json' \
--header 'loginId: YOUR_API_KEY' \
--data-raw '["5039367187", "8084565302"]'
```
### Response
```json theme={null}
[
{
"Response": "Phone number current score",
"Phone": "7867056421",
"LegalEntityId": 123,
"CurrScore": "High",
"MaxScore": "High",
"HistoricalScore": "5",
"VerizonScore": "Flagged",
"ATTScore": "Flagged",
"TMobileScore": "Clean",
"RoboKillerStatus": "Clean",
"NomoroboStatus": "Flagged",
"FTCComplaints": [
{
"FTCComplaintId": "79923e06b1c74d47e6ad5826b7554046",
"Phone": "7867056421",
"CreatedDate": "08/15/2022 22:22:39",
"ViolationDate": "07/29/2022 12:04:00",
"City": "Jackson",
"State": "New Jersey",
"AreaCode": "732",
"Subject": "Dropped call or no message",
"RecordedMessageOrRobocall": "Y"
}
]
}
]
```
***
## Get All Scores
Get scores for all phone numbers in your account.
### Endpoint
```
GET https://trustcallapi.dncscrub.com/v1.4/trustcall/getAll
```
### Example
```bash theme={null}
curl --location --request GET \
'https://trustcallapi.dncscrub.com/v1.4/trustcall/getAll' \
--header 'Content-Type: application/json' \
--header 'loginId: YOUR_API_KEY'
```
***
## Remove Phone Numbers
Remove phone numbers from monitoring.
### Endpoint
```
POST https://trustcallapi.dncscrub.com/v1.4/trustcall/remove
```
### Example
```bash theme={null}
curl --location --request POST \
'https://trustcallapi.dncscrub.com/v1.4/trustcall/remove' \
--header 'Content-Type: application/json' \
--header 'loginId: YOUR_API_KEY' \
--data-raw '["5039367187"]'
```
### Response
```json theme={null}
[
{
"Phone": "5039367187",
"Response": "Phone number removed from monitor"
}
]
```
***
## Response Fields
| Field | Description |
| ------------------ | ----------------------------------------------------------------- |
| `Response` | Status message |
| `Phone` | The phone number |
| `LegalEntityId` | Legal entity identifier (integer) |
| `CurrScore` | Current average score: `Clean`, `Medium`, `High`, or `Processing` |
| `MaxScore` | Maximum score in last 15 days |
| `HistoricalScore` | Score from 0-5 (0-1 = no issues, 5 = 50%+ high spam) |
| `VerizonScore` | Verizon status: `Clean`, `Flagged`, or `Processing` |
| `ATTScore` | AT\&T status: `Clean`, `Flagged`, or `Processing` |
| `TMobileScore` | T-Mobile status: `Clean`, `Flagged`, or `Processing` |
| `RoboKillerStatus` | RoboKiller app status: `Clean` or `Flagged` |
| `NomoroboStatus` | Nomorobo app status: `Clean` or `Flagged` |
| `FTCComplaints` | Array of FTC complaints (if any) |
## FTC Complaint Fields
| Field | Description |
| --------------------------- | ----------------------------- |
| `FTCComplaintId` | Unique complaint identifier |
| `Phone` | Phone number complained about |
| `CreatedDate` | When complaint was filed |
| `ViolationDate` | When violation occurred |
| `City` | Complainant's city |
| `State` | Complainant's state |
| `AreaCode` | Complainant's area code |
| `Subject` | Complaint category |
| `RecordedMessageOrRobocall` | `Y` if robocall complaint |
## Limits
| Limit | Value |
| ------------------------------ | --------- |
| Numbers per Add request | 50 |
| Numbers per Get request (POST) | Unlimited |
| Numbers per Get request (GET) | 200 |
## C# Class Definitions
```csharp theme={null}
public class PhoneResponseRecord
{
public string Response { get; set; }
public string Phone { get; set; }
public int? LegalEntityId { get; set; }
public string CurrScore { get; set; }
public string MaxScore { get; set; }
public string HistoricalScore { get; set; }
public string VerizonScore { get; set; }
public string ATTScore { get; set; }
public string TMobileScore { get; set; }
public string RoboKillerStatus { get; set; }
public string NomoroboStatus { get; set; }
public List FTCComplaints { get; set; }
}
public class FTCComplaintDTO
{
public string FTCComplaintId { get; set; }
public string Phone { get; set; }
public string CreatedDate { get; set; }
public string ViolationDate { get; set; }
public string City { get; set; }
public string State { get; set; }
public string AreaCode { get; set; }
public string Subject { get; set; }
public string RecordedMessageOrRobocall { get; set; }
}
```
# Remove Phone Numbers
Source: https://docs.dncscrub.com/api-reference/trustcall/remove
POST https://dataapi.dncscrub.com/v1.5/TrustCall/Remove
Remove phone numbers from TrustCall monitoring
Remove phone numbers from TrustCall monitoring. Removed numbers will no longer be tracked for carrier spam scores.
## Request
### Headers
Your API Key (LoginId from your DNCScrub account)
Must be `application/json`
### Request Body
The request body is a JSON array of 10-digit phone number strings:
```json theme={null}
["5039367187", "8084565302"]
```
## Example Request
```bash cURL theme={null}
curl --location --request POST \
'https://dataapi.dncscrub.com/v1.5/TrustCall/Remove' \
--header 'loginId: YOUR_API_KEY' \
--header 'Content-Type: application/json' \
--data-raw '["5039367187", "8084565302"]'
```
```javascript JavaScript theme={null}
const response = await fetch(
'https://dataapi.dncscrub.com/v1.5/TrustCall/Remove',
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
'loginId': 'YOUR_API_KEY'
},
body: JSON.stringify(['5039367187', '8084565302'])
}
);
const data = await response.json();
console.log(data);
```
```csharp C# theme={null}
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Add("loginId", "YOUR_API_KEY");
var phoneNumbers = new[] { "5039367187", "8084565302" };
var content = new StringContent(
JsonSerializer.Serialize(phoneNumbers),
Encoding.UTF8,
"application/json"
);
var response = await client.PostAsync(
"https://dataapi.dncscrub.com/v1.5/TrustCall/Remove",
content
);
var result = await response.Content.ReadAsStringAsync();
Console.WriteLine(result);
}
```
```json Response theme={null}
[
{
"Phone": "5039367187",
"Response": "Phone number removed from monitor"
},
{
"Phone": "8084565302",
"Response": "Phone number removed from monitor"
}
]
```
## Response Fields
The phone number that was removed
Status message indicating the result of the remove operation
## Error Responses
| Status | Description |
| ---------------- | ------------------------------------------- |
| 400 Bad Request | Invalid request body or phone number format |
| 401 Unauthorized | Invalid or missing API key |
# C# Examples
Source: https://docs.dncscrub.com/examples/csharp
Production-ready C# examples for integrating with DNCScrub APIs
# 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.Json` and `System.Net.Http.Json`
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.
## 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 results = await client.GetFromJsonAsync(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](/api-reference/scrub/output-guide) for a full reference of result codes and response fields.
## 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
{
["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();
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.
```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(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(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 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() ?? [];
}
public async Task CheckReassignedAsync(string phoneNumber, string consentDate)
{
var url = $"https://dataapi.dncscrub.com/v1.5/Data/TCPAAuthority?phoneNumber={phoneNumber}&date={consentDate}";
return await _http.GetFromJsonAsync(url);
}
public async Task 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(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);
```
**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}");
```
# JavaScript Examples
Source: https://docs.dncscrub.com/examples/javascript
JavaScript code examples for CCC APIs
# JavaScript Code Examples
Complete JavaScript examples for integrating with CCC APIs. These examples work in both Node.js and browser environments.
In browser environments, API calls may be blocked by CORS. These APIs are designed for server-side use. For client-side applications, make calls through your backend.
## Scrub API - Basic Example
```javascript theme={null}
async function scrubPhoneNumber(phoneNumber, apiKey) {
const url = `https://www.dncscrub.com/app/main/rpc/scrub?phoneList=${phoneNumber}&version=8&output=json`;
const response = await fetch(url, {
method: 'GET',
headers: {
'loginId': apiKey
}
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
return data[0];
}
// Usage
const result = await scrubPhoneNumber('7075276405', 'YOUR_API_KEY');
console.log(`Result Code: ${result.ResultCode}`);
console.log(`Reason: ${result.Reason}`);
```
## Scrub Multiple Phone Numbers
```javascript theme={null}
async function scrubMultipleNumbers(phoneNumbers, apiKey) {
const phoneList = phoneNumbers.join(',');
const url = `https://www.dncscrub.com/app/main/rpc/scrub?phoneList=${phoneList}&version=8&output=json`;
const response = await fetch(url, {
method: 'GET',
headers: {
'loginId': apiKey
}
});
const results = await response.json();
// Categorize results
const clean = results.filter(r => r.ResultCode === 'C');
const doNotCall = results.filter(r => r.ResultCode === 'D');
const wireless = results.filter(r => r.IsWirelessOrVoIP === '1');
return {
all: results,
clean,
doNotCall,
wireless,
summary: {
total: results.length,
cleanCount: clean.length,
dncCount: doNotCall.length,
wirelessCount: wireless.length
}
};
}
// Usage
const numbers = ['5039367187', '7075276405', '7072842774'];
const results = await scrubMultipleNumbers(numbers, 'YOUR_API_KEY');
console.log(`Clean: ${results.summary.cleanCount}`);
console.log(`DNC: ${results.summary.dncCount}`);
```
## Scrub with Unique Identifiers
```javascript theme={null}
async function scrubWithIds(records, apiKey) {
// records = [{ phone: '5039367187', id: 'ACCT-001' }, ...]
const phoneList = records
.map(r => `${r.phone}|${r.id}`)
.join(',');
const url = `https://www.dncscrub.com/app/main/rpc/scrub?phoneList=${encodeURIComponent(phoneList)}&version=8&output=json`;
const response = await fetch(url, {
headers: { 'loginId': apiKey }
});
const results = await response.json();
// Results have your ID in the Reserved field
return results.map(r => ({
phone: r.Phone,
accountId: r.Reserved, // Your unique ID
resultCode: r.ResultCode,
reason: r.Reason
}));
}
// Usage
const records = [
{ phone: '5039367187', id: 'ACCT-001' },
{ phone: '7075276405', id: 'ACCT-002' }
];
const results = await scrubWithIds(records, 'YOUR_API_KEY');
```
## HTTP POST for Large Batches
```javascript theme={null}
async function scrubLargeBatch(phoneNumbers, apiKey) {
const response = await fetch('https://www.dncscrub.com/app/main/rpc/scrub', {
method: 'POST',
headers: {
'loginId': apiKey,
'Content-Type': 'application/x-www-form-urlencoded'
},
body: new URLSearchParams({
phoneList: phoneNumbers.join(','),
version: '5',
output: 'json'
})
});
return await response.json();
}
```
## TCPA Authority API
```javascript theme={null}
async function checkReassigned(phoneNumber, consentDate, apiKey) {
const url = `https://dataapi.dncscrub.com/v1.4/Data/TCPAAuthority?phoneNumber=${phoneNumber}&date=${consentDate}`;
const response = await fetch(url, {
headers: { 'loginId': apiKey }
});
const result = await response.json();
return {
phoneNumber: result.PhoneNumber,
isReassigned: result.IsReassigned,
isValid: result.IsValid,
lineType: result.LineType,
carrier: result.Carrier,
location: `${result.Locale}, ${result.Region}`,
timezone: result.TZ
};
}
// Usage
const result = await checkReassigned('7075276405', '20210209', 'YOUR_API_KEY');
if (result.isReassigned === true) {
console.log('DO NOT CALL - Number reassigned');
} else if (result.isReassigned === false) {
console.log('Safe to call');
} else {
console.log('Unable to determine - proceed with caution');
}
```
## Litigator API
```javascript theme={null}
async function checkLitigators(phoneNumbers, apiKey) {
const phoneList = phoneNumbers.join(',');
const url = `https://dataapi.dncscrub.com/v1.4/scrub/litigator?phoneList=${phoneList}`;
const response = await fetch(url, {
headers: { 'loginId': apiKey }
});
const results = await response.json();
const litigators = results.filter(r => r.IsLitigator);
const safe = results.filter(r => !r.IsLitigator);
return { litigators, safe };
}
// Usage
const { litigators, safe } = await checkLitigators(['5039367187', '7075276405'], 'YOUR_API_KEY');
console.log(`Litigators found: ${litigators.length}`);
```
## Internal DNC Management
```javascript theme={null}
// Add to Internal DNC
async function addToInternalDNC(phoneNumber, apiKey) {
const url = `https://www.dncscrub.com/app/main/rpc/pdnc?phoneList=${phoneNumber}&actionType=add`;
const response = await fetch(url, {
headers: { 'loginId': apiKey }
});
return response.ok;
}
// Remove from Internal DNC
async function removeFromInternalDNC(phoneNumber, apiKey) {
const url = `https://www.dncscrub.com/app/main/rpc/pdnc?phoneList=${phoneNumber}&actionType=remove`;
const response = await fetch(url, {
headers: { 'loginId': apiKey }
});
return response.ok;
}
```
## TrustCall Premier API
```javascript theme={null}
// Add numbers to monitoring
async function addToTrustCall(numbers, apiKey) {
const response = await fetch('https://trustcallapi.dncscrub.com/v1.4/trustcall/add', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'loginId': apiKey
},
body: JSON.stringify(numbers.map(phone => ({ Phone: phone })))
});
return await response.json();
}
// Check scores
async function getTrustCallScores(phoneNumbers, apiKey) {
const phoneList = phoneNumbers.join(',');
const url = `https://trustcallapi.dncscrub.com/v1.4/trustcall/get?phoneList=${phoneList}`;
const response = await fetch(url, {
headers: {
'Content-Type': 'application/json',
'loginId': apiKey
}
});
return await response.json();
}
```
## Error Handling Wrapper
```javascript theme={null}
class CCCApiClient {
constructor(apiKey) {
this.apiKey = apiKey;
this.baseUrl = 'https://www.dncscrub.com/app/main/rpc';
}
async request(endpoint, options = {}) {
const url = `${this.baseUrl}${endpoint}`;
try {
const response = await fetch(url, {
...options,
headers: {
'loginId': this.apiKey,
...options.headers
}
});
if (response.status === 401) {
throw new Error('Invalid API Key');
}
if (response.status === 429) {
throw new Error('Rate limit exceeded');
}
if (!response.ok) {
const error = await response.text();
throw new Error(`API Error: ${error}`);
}
const contentType = response.headers.get('content-type');
if (contentType?.includes('application/json')) {
return await response.json();
}
return await response.text();
} catch (error) {
if (error.name === 'TypeError') {
throw new Error('Network error - check your connection');
}
throw error;
}
}
async scrub(phoneNumbers) {
const phoneList = Array.isArray(phoneNumbers) ? phoneNumbers.join(',') : phoneNumbers;
return this.request(`/scrub?phoneList=${phoneList}&version=8&output=json`);
}
}
// Usage
const client = new CCCApiClient('YOUR_API_KEY');
try {
const results = await client.scrub(['5039367187', '7075276405']);
console.log(results);
} catch (error) {
console.error('API Error:', error.message);
}
```
## HTML Form Example
A complete HTML example for browser-based scrubbing (through your backend):
```html theme={null}
Phone Scrubber
Phone Number Scrubber
```
# GoHighLevel
Source: https://docs.dncscrub.com/integrations/gohighlevel
Add DNCScrub compliance scrubbing to your GoHighLevel agency and sub-accounts
[GoHighLevel](https://www.gohighlevel.com) is an all-in-one sales and marketing platform for agencies. The DNCScrub app brings TCPA and Do Not Call compliance scrubbing directly into your GoHighLevel agency and sub-accounts, so you can screen contact phone numbers before you dial, text, or start a campaign.
## Prerequisites
* A GoHighLevel agency account with permission to install marketplace apps
* A DNCScrub account with API access (your **Login ID** / API key and a **Campaign ID**)
## Install the App
DNCScrub installs once at the **agency level** and then works across the sub-accounts you choose. You install it from the GoHighLevel Marketplace.
In your GoHighLevel **agency** account, open the **App Marketplace**.
- In the search box (top right), type DNC.
- Select the CCC DNCScrub app by Contact Center Compliance.
On the app page, make sure the view is set to **Agency View**, then select **Install**. DNCScrub can only be installed from the agency — not from a sub-account — and you install it once no matter how many sub-accounts you have.
In the **Select Sub-Account** window, check the sub-accounts (locations) where you want to use DNCScrub, then select **Continue**. You can enable more sub-accounts later, so it is fine to start with just the ones you need.
On the **Install confirmation** page, review the selected location and the permissions the app requests, then select **Allow & Install** to finish installing DNCScrub.
Once installation is complete, a new tab opens confirming **Connected Successfully** — your GoHighLevel account is now connected to DNC Scrub. Select **Close This Tab** and return to GoHighLevel.
After installing, GoHighLevel may drop you into a sub-account. To finish setup, switch to **Agency View** — the **DNCScrub Settings** page lives there.
## Set Up Your Agency
Your GoHighLevel connection is created automatically when you install the app. Next, add your DNCScrub API credentials at the **agency level** so scrubbing works across all of your sub-accounts.
Enter these settings from **Agency View**. The **DNCScrub Settings** page only appears at the agency level — not inside a sub-account. Use the account switcher (top-left in GoHighLevel) to select your agency first.
In your GoHighLevel **agency**, select **DNCScrub Settings** in the left sidebar.
On the **Agency** tab, under **DNC Scrub API Credentials**, enter your **DNC Scrub Login ID (API Key)**. You can also add a **DNC Scrub Campaign ID** — if you leave it blank, your default campaign is used.
These agency credentials apply to every sub-account by default.
Select **Save Agency Settings**, then **Test DNC Connection**. A green **DNC Scrub API: Connected** message confirms your credentials work.
In the **Connection** panel at the bottom-right of the screen, you should see two green indicators — **GoHighLevel** and **DNC Scrub API**. Two green lights mean you are fully connected and ready to scrub.
Agency credentials are shared by all sub-accounts. You can override them for an individual sub-account in the next step.
## Configure a Sub-Account
Switch to the **Sub-Accounts** tab and choose a sub-account (location) from the dropdown to configure it on its own. Repeat these steps for each sub-account you want to protect.
If the panel shows a message instead of the sub-account's settings:
* **App Not Installed** — the DNC Scrub app has not been added to that sub-account yet. Open the **App Marketplace** inside that sub-account, install the DNC Scrub app, then return here and select it again.
* **Sub-Account Not Active** — GoHighLevel reports the sub-account as paused or removed, so DNC Scrub cannot reach it. Reactivate it under **Sub-Accounts** in GoHighLevel, then reload this page. Installing the app again will not help: an agency-level install shows as installed in every sub-account, so the App Marketplace can say the app is installed while the sub-account itself is inactive.
### Credential override
Use **DNC Credentials Override** to point a single sub-account at a different DNCScrub Login ID or Campaign ID. Leave these fields blank to inherit the agency defaults.
### Scrub behavior
The **Scrub Behavior** section controls when and how contacts are scrubbed for the selected sub-account:
| Setting | What it does |
| ------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| **Create DNC note on new contacts** | Add a *DNC Scrub* note with a scrub link when a contact is created |
| **Auto-scrub new contacts** | Scrub a contact automatically when it is created — on top of the note |
| **Pin scrub note** | Pin the *DNC Scrub* note to the top of the contact's notes panel |
| **Auto-scrub when the note link is opened** | Automatically scrub the contact when its DNC Scrub link is opened from the notes — no button click needed |
| **Re-scrub interval** | How long a scrub result stays reusable, as a number plus Hours, Days or Months (default `1 Month`). A number scrubbed within this period is reused instead of being scrubbed again, so it is not charged again. Applies to every scrub, not only bulk. Capped at 31 days |
### Note appearance
Under **Note Appearance**, set the colors DNC Scrub uses for the notes it adds to contacts:
* **Scrub Link Note Color** — the pinned note that holds the scrub link
* **Result: Clean Color** — the result note when a number is safe to call
* **Result: Blocked Color** — the result note when a number is blocked
### Contact tags
Turn on **Manage DNC tags** to have DNC Scrub tag each contact with its scrub result. The tag is kept in sync on every re-scrub, so a contact always carries the tag that matches its latest result — handy for building smart lists and triggering workflows.
Choose which tags to apply under **Apply these status tags**. Each scrub result maps to a single status tag:
| Status tag | Applied when the number is |
| ---------------- | ----------------------------------------------------- |
| **DNC-Blocked** | Blocked — Do Not Call |
| **DNC-Clean** | Clean and safe to call (includes exemptions and EBRs) |
| **DNC-Wireless** | A wireless number |
| **DNC-Invalid** | Invalid or unusable |
A contact only ever carries one of these status tags at a time. When a re-scrub changes the result, DNC Scrub removes the old status tag and adds the new one.
DNC Scrub only ever changes the DNC status tags you enable here. Any other tags on the contact — yours or from other apps — are never touched.
### Bulk scrub schedule
Turn on **Enable scheduled bulk scrub** to automatically re-scrub all contacts on a recurring schedule, then set:
* **Frequency** — Daily, Weekly, Monthly, or **Every…** for a set number of days or months between runs (new sub-accounts default to Monthly)
* **At time** — the time of day the scrub runs
* **On these days** (Weekly), **On day of month** (Monthly), or **Run every** *N* days/months (Every…)
* **Timezone** — the schedule runs in the timezone you choose
A plain-English summary — for example, *"Runs every day at 2:00 AM (America/Los Angeles)."* — confirms exactly when the scrub will run.
Select **Save Sub-Account Settings** at the bottom of the page to apply the credential, scrub-behavior, note-appearance, and schedule settings above.
## Onboard the Sub-Account
Run the **Onboarding** actions once when you first set up DNC Scrub for a sub-account. These run as soon as you click them — they are separate from the **Save Sub-Account Settings** button above.
* **Create Custom Fields** — creates the DNC custom fields used to store scrub results on contacts.
* **Create Onboarding Notes** — adds a pinned *DNC Scrub* note with a scrub link to every existing contact.
The **Offboarding** actions shown in the same area remove DNC Scrub from the sub-account — see [Offboarding](#offboarding).
## Scrubbing a Contact
Once a sub-account is onboarded, each contact gets a pinned **DNC Scrub** note containing a link to the scrub page.
On the contact, open the pinned **DNC Scrub** note and select the scrub link.
The scrub page lists every phone number on the contact. Select **Scrub All Numbers** to screen them against DNCScrub.
Each number returns a result card — **Clean** (green) or **Do Not Call** (red) — along with the result details. A summary banner reports how many numbers were scrubbed and how many were blocked.
The result is written back to the contact as a color-coded **DNC Scrub** note, and — when [contact tags](#contact-tags) are enabled — the contact is tagged with its result (for example, `DNC-Blocked`) so you can filter it in smart lists and workflows.
### Reading a result
Each phone result card includes:
| Field | Description |
| --------------- | ------------------------------------------------------------------------------- |
| **Result Code** | The DNCScrub status code (for example, `Y` = clean, `D` = Do Not Call) |
| **Callable** | Whether the number is safe to call (*Yes — Safe to call* or *NO — Do Not Call*) |
| **Line Type** | The line type, such as VoIP, Wireless, or Landline |
| **Carrier** | The carrier name when available |
| **Reason** | Why the number was flagged, such as a National DNC registration date |
## Taking Action on a Result
From the scrub results you can act on a number directly:
* **Re-Scrub** — run the scrub again to refresh the result.
* **Add to IDNC** — add the number to your Internal Do Not Call list. The contact is also tagged `DNC-Internal`.
* **Add EBR** — record an Existing Business Relationship so the number remains callable under that exemption.
When you select **Add EBR**, fill in the relationship details:
* **EBR Type** — the relationship and its duration, such as *Sale (18 months)*.
* **Date of Last Contact** — when you last did business with the contact.
* **Reference** — an optional reference number.
## Automated and Bulk Scrubbing
Beyond scrubbing contacts one at a time, you can automate the process:
* Enable **Auto-scrub new contacts** (see [Configure a Sub-Account](#configure-a-sub-account)) to scrub contacts as workflows create them.
* Enable **Auto-scrub when the note link is opened** (see [Configure a Sub-Account](#configure-a-sub-account)) to scrub automatically when a rep opens the DNC Scrub link from a contact's notes.
* Enable the **Bulk Scrub Schedule** (see [Configure a Sub-Account](#configure-a-sub-account)) to re-scrub all contacts on a recurring schedule, skipping any contact scrubbed within the **Re-scrub interval**.
### How results are reused
A scrub result is stored against the phone number itself, not the contact, and reused until the **Re-scrub interval** expires.
That means:
* The same number on more than one contact is scrubbed — and charged — once.
* The same number in more than one sub-account is scrubbed once, because results are shared across every sub-account using the same DNC Scrub credentials.
* A scheduled bulk scrub that runs more often than the interval reuses the stored results rather than scrubbing again.
To get a fresh result before the interval expires, open the contact's DNC Scrub link and choose **Re-scrub**. Adding a number to your Internal DNC list, removing it, or recording an EBR clears the stored result automatically, so the next scrub reflects the change.
The scrub page shows **Last scrubbed** with the date and time the result was obtained, so you can always see how current it is.
## Note Link Security
Every **DNC Scrub** note link is signed with a private key unique to your agency, so only scrub links your account generates are accepted. You can view and rotate this key under **DNC Settings → Note Link Security**, where it is shown masked (for example, `••••••••abcd`).
Rotate the key if you believe a scrub link has been shared outside your team.
Select **↻ Rotate** next to the signing key, then confirm. The key is replaced immediately.
Rotating **invalidates every existing scrub link**. For each sub-account, run **Delete All DNC Notes** and then **Create Onboarding Notes** so contacts receive fresh, valid links.
Until you recreate the notes, opening an old scrub link shows *"This DNC Scrub link is invalid or has been revoked."* Recreate the notes to restore access.
## Offboarding
To remove DNC Scrub data from a sub-account, use the **Offboarding** actions in DNC Settings:
* **Delete All DNC Notes**
* **Delete Custom Fields**
Offboarding actions cannot be undone. They permanently remove the DNC Scrub notes and custom fields from the sub-account.
## Support
* [DNCScrub API Documentation](/api-reference/overview)
* [GoHighLevel Documentation](https://help.gohighlevel.com/)
* [Contact Support](mailto:support@dnc.com)
# n8n
Source: https://docs.dncscrub.com/integrations/n8n
Automate compliance workflows with n8n and DNCScrub APIs
[n8n](https://n8n.io) is a workflow automation platform that connects applications and automates business processes. This guide shows how to integrate DNCScrub APIs into n8n workflows for automated compliance checking.
## Prerequisites
* n8n instance (cloud or self-hosted)
* DNCScrub account with API access
* Your DNCScrub API key (loginId)
## Setting Up Authentication
DNCScrub APIs authenticate via the `loginId` header.
### Create a Credential
1. In n8n, go to **Credentials** → **Add Credential**
2. Select **Header Auth**
3. Configure:
* **Name**: `DNCScrub API`
* **Header Name**: `loginId`
* **Header Value**: Your DNCScrub API key
## Common Workflow Patterns
### Pre-Dial Compliance Check
Scrub phone numbers before dialing to ensure compliance using Salesforce trigger. n8x can work with multiple tools but this example uses Salesforce.
Use a **Salesforce Trigger** for new leads, a **Webhook** for real-time requests, or a **Schedule Trigger** for batch processing.
Configure the DNCScrub Scrub API call:
* **Method**: `GET`
* **URL**: `https://www.dncscrub.com/app/main/rpc/scrub`
* **Authentication**: Select your `DNCScrub API` credential
* **Query Parameters**:
* `phoneList`: `{{ $json.phone }}`
* `projId`: YOUR\_PROJECT\_ID (optional)
Check the scrub result:
* **Condition**: `{{ $json.results[0].Status }}` equals `Ok`
* **True branch**: Proceed to dial
* **False branch**: Skip or update CRM
Use the **Salesforce Node** to update the lead status based on scrub results.
### Add Contact to Internal DNC
Add to Internal DNC list. when requested by the contact.
```
HTTP Request Configuration:
━━━━━━━━━━━━━━━━━━━━━━━━━━
Method: GET
URL: https://www.dncscrub.com/app/main/rpc/pdnc
Query Parameters:
phoneList: {{ $json.phone }}
action: add
projId: YOUR_PROJECT_ID
```
### Workflow JSON
You can import this workflow directly into n8n:
```json theme={null}
{
"nodes": [
{
"name": "Salesforce Trigger",
"type": "n8n-nodes-base.salesforceTrigger",
"position": [250, 300]
},
{
"name": "DNCScrub",
"type": "n8n-nodes-base.httpRequest",
"position": [450, 300],
"parameters": {
"method": "GET",
"url": "https://www.dncscrub.com/app/main/rpc/scrub",
"authentication": "genericCredentialType",
"genericAuthType": "httpHeaderAuth",
"queryParameters": {
"parameters": [
{
"name": "phoneList",
"value": "={{ $json.Phone }}"
},
{
"name": "projId",
"value": "YOUR_PROJECT_ID"
}
]
}
}
},
{
"name": "Check Result",
"type": "n8n-nodes-base.if",
"position": [650, 300],
"parameters": {
"conditions": {
"string": [
{
"value1": "={{ $json.results[0].Status }}",
"value2": "Ok"
}
]
}
}
}
]
}
```
## Error Handling
Add error handling to your workflows:
1. **Set "Continue On Fail"** on HTTP Request nodes to handle API errors gracefully
2. **Add an IF node** after each API call to check for success
3. **Log failures** to a Google Sheet, database, or notification system
## Batch Processing Tips
When processing large lists:
1. **Use the Loop Over Items node** to process records individually
2. **Add a Wait node** (100-200ms) between requests to avoid rate limits
3. **Use POST endpoints** for batches over 10 numbers
## Support
* [DNCScrub API Documentation](/api-reference/introduction)
* [n8n Documentation](https://docs.n8n.io/)
* [Contact Support](mailto:support@dnc.com)
# Integrations
Source: https://docs.dncscrub.com/integrations/overview
Platform integrations and implementation guides
##
Genesys Cloud
Configure CCC DNC scrubbing integration with Genesys Cloud. Genesys supports DNC.com (Contact Center Compliance Corporation) as a web service provider for just-in-time DNC scrubbing to ensure compliance with legislative requirements. Requires a Login ID from Contact Center Compliance to authorize service access.
The Genesys Cloud integration will suppress calls outside legal call
solicitation windows determined by DNCScrub as well as calls during state of
emergencies and holidays were soliciations are restricted. This is usually
desired but not always. Please contact [support@dnc.com](mailto:support@dnc.com) if you are unclear on
this impact. You can set custom calling times and holidays in DNCScrub to
manage this.
***
##
Zoom Contact Center
Enable Do Not Call integrations with Contact Center Compliance Corporation (DNC.com) in Zoom Contact Center. This integration allows Zoom Contact Center users to leverage CCC's DNC scrubbing services to ensure compliance with federal and state Do Not Call regulations during outbound calling campaigns.
***
##
Zapier Automation Platform
Automate Do Not Call scrubbing workflows with CCC's Zapier integration. This app enables automated TCPA compliance by scrubbing contact lists against known serial plaintiffs and litigators as part of your workflow automation. Perfect for call centers and marketing teams who need to integrate litigator scrubbing into their existing automation processes across 8,000+ connected apps.
***
##
DialedIn by ChaseData
Configure DNC Compliance workflows in ChaseData's Integration Portal. The platform supports DNC scrubbing integration through workflow steps that can be combined with field mapping, CRM integrations, and automated compliance processes. Workflows are executed via API requests to the ChaseData integration endpoint with authentication tokens.
***
## Lofty CRM
Connect DNC.com scrubbing directly to the Lofty real estate CRM. Lofty's built-in integration checks phone numbers against the National DNC, state DNCs, and known litigator lists before calls and texts, warns agents on unsafe numbers, converts automated texts to unsafe numbers into manual review tasks, and syncs your Lofty internal DNC list to your DNC.com project. Requires a DNC.com subscription and your account name, API key, and optional Project ID.
***
## CallShaper - DNCScrub Integration
Integration guide for CallShaper dialer with DNC Scrubbing services. Covers configuration and setup for automated compliance workflows.
***
***
## n8n Workflow Automation
Automate TCPA compliance workflows with n8n and DNCScrub APIs. Build pre-dial scrubbing, real-time legal calling hour checks, litigator screening, and opt-out management—all integrated with your CRM and other business tools.
Step-by-step setup with workflow examples
***
## GoHighLevel
Add DNCScrub compliance scrubbing to your GoHighLevel agency and sub-accounts. Install the marketplace app to bring TCPA and Do Not Call screening directly into your contact and outbound calling workflows.
Marketplace install and setup steps
***
##
Salesforce (Lightning App)
Add DNCScrub TCPA and Do Not Call compliance scrubbing natively to your Salesforce Leads, Contacts, Accounts, and Campaign Members. The Lightning app stores results in custom fields, so they work with standard reports, list views, and automation.
Install, setup, and scrubbing workflows
***
## VICIdial
Add DNCScrub TCPA and Do Not Call compliance scrubbing to your VICIdial system. Filter outbound lists in batch and screen inbound calls on your DIDs against federal, state, internal DNC, wireless, and litigator lists.
Settings container, outbound list filtering, and inbound DID setup
***
Need help with a custom integration? [Contact our support
team](mailto:support@dnc.com) for assistance.
# Salesforce
Source: https://docs.dncscrub.com/integrations/salesforce
Add DNCScrub TCPA and Do Not Call compliance scrubbing directly to your Salesforce Leads, Contacts, Accounts, and Campaign Members
The **CCC DNCScrub** app for Salesforce brings TCPA and Do Not Call compliance checking natively into your CRM. It checks phone numbers against federal and state DNC registries, wireless lists, litigator databases, and your own Internal Do Not Call list — directly on Lead, Contact, Account, and Campaign Member records, before your team dials.
The app is a native [Lightning](https://www.salesforce.com/products/platform/lightning/) application built with Lightning Web Components. Scrub results are stored in custom fields on your records, so they work with standard Salesforce reports, list views, flows, and validation rules.
## Prerequisites
* A Salesforce org on **Lightning Experience** (Developer, Professional with API access, Enterprise, or Unlimited edition)
* Permission to install apps and edit Lightning record pages (System Administrator or equivalent)
* A DNCScrub account with API access — your **Login ID** (API key) and, optionally, a **Campaign ID**
## Step 1: Install the App
Install the CCC DNCScrub managed package using the link that matches your org. You must be logged in to the target org before opening the link.
**Production:**
`https://login.salesforce.com/packaging/installPackage.apexp?p0=04thm000002JWSrAAO`
**Sandbox:**
`https://test.salesforce.com/packaging/installPackage.apexp?p0=04thm000002JWSrAAO`
**Specific Org:** replace `` with your org's My Domain.
`https://.sandbox.my.salesforce.com/packaging/installPackage.apexp?p0=04thm000002JWSrAAO`
Copy the install URL for your org type above and open it in your browser. Salesforce will confirm the components being added.
Select **Install for All Users** (or the scope that fits your rollout).
During install, Salesforce shows a **"Yes, grant access to these third-party web sites"** checkbox listing the DNCScrub API endpoints. Check it to approve. You do **not** need to add these URLs manually — the package includes them as active Remote Site Settings and creates them for you on install.
**Each org is configured separately — including sandboxes.** Installing the package does not carry over configuration between environments. In every org you install into, repeat [Step 2](#step-2-connect-your-dncscrub-account) to enter your Login ID / Campaign ID and [Step 3](#step-3-assign-permission-sets) to assign the permission sets. If you're testing against a sandbox, confirm the Login ID you enter is valid for the environment you're pointing at.
## Step 2: Connect Your DNCScrub Account
After installing, open the **CCC DNCScrub** app from the App Launcher and go to the **Settings** tab to enter your DNCScrub credentials. These settings apply org-wide to every scrub operation.
Under **API credentials**, enter:
* **Login ID (API Key)** — your DNCScrub API key
* **Campaign ID** — the DNCScrub campaign used to scrub (optional)
Select **Test Connection** to verify your Login ID works against the DNCScrub API.
Configure the **Scrub Options**:
* **Scrub Against** — which lists to screen numbers against
* **Rescrub Interval** and **Unit** — how long a scrub result stays valid before the number is sent to the API again. Enter a number and choose **Hours**, **Days**, or **Months**. Months and days use calendar arithmetic, so `1 Month` means one calendar month rather than 720 hours. `0` re-checks every time.
* **Auto-scrub new Leads and Contacts on create** — scrubs a record automatically as soon as it is created with a phone number.
Optionally enable **Notifications** to send an email after a bulk scrub completes.
Under **Audit Logs**, leave **Keep logs forever** selected unless you have a retention policy that says otherwise. These logs are your evidence that a number was checked before it was called, and may be needed to defend a claim years later. Clearing the checkbox reveals a **Retention (days)** field, which accepts a minimum of 1500 days — a little over the four-year window in which a TCPA claim can be brought.
Select **Save Settings**.
**Check the version first when something looks wrong.** The installed version is shown at the bottom right of the Settings page — for example **Version: 0.4.1**. After an upgrade, a browser may keep running the previous version's components until you hard-refresh (**Ctrl+Shift+R**, or **Cmd+Shift+R** on a Mac). If the version shown is the new one but the app still behaves like the old one, it is the browser cache; if the version shown is the old one, the upgrade did not reach that org.
### Daily cleanup job
Under **Scrub Options**, the Settings page reports whether the daily cleanup job is scheduled and when it next runs. The job removes expired entries from the scrub cache (and old audit logs, if you have set a retention period).
If it shows **Not scheduled**, select **Schedule now**. Orgs that received the app by package install normally have it already; orgs set up by a direct metadata deployment do not, because deployments do not run install scripts.
## Dashboard
Once connected, the **Dashboard** tab is your home base — an at-a-glance view of scrubbing activity (Do Not Call scrubs today and this week, Do Not Call numbers identified today, and reassigned checks today), along with an embedded Quick Scrub and a Recent Activity log.
## Step 3: Assign Permission Sets
The app ships with two permission sets. Assign them to your users from **Setup → Permission Sets**.
| Permission Set | For | Access |
| -------------- | -------------- | -------------------------------------------------------------------------------------------------------------------- |
| **CCC Admin** | Administrators | Full read/write on all CCC objects and fields, all tabs including Settings, and bulk schedule management |
| **CCC User** | Standard users | Read-only scrub fields on records, can trigger scrubs and view results; no access to Settings or schedule management |
**User seeing an "invalid access" error, or a Standard user can't scrub?** They're almost always missing a permission-set assignment. Standard users have no access to the scrub fields or actions until you assign them **CCC User** (or **CCC Admin**) — assigning the permission set resolves it. This must be done in each org, including sandboxes.
## Step 4: Add the Scrub Panel to Record Pages
The **CCC DNC Scrub Panel** is a Lightning component you place on Lead, Contact, Account, or Campaign Member record pages.
On a record, select the gear icon → **Edit Page** to open Lightning App Builder.
Drag the **CCC DNC Scrub Panel** component onto the page (the sidebar works well).
Set the **Phone Fields to Scrub** property to a comma-separated list of field API names — for example `Phone,MobilePhone,HomePhone`. Each field is scrubbed and displayed independently.
Save and **Activate** the page for the relevant app, record type, or profile.
### Scrub Panel properties
| Property | What it does |
| ------------------------------------- | ----------------------------------------------------------------------------------------------------------------- |
| **Phone Fields to Scrub** | Comma-separated phone field API names to display and scrub (e.g. `Phone,MobilePhone`) |
| **Disable Auto-Scrub on Record View** | Turns off automatic scrubbing when the panel loads, so numbers are only checked when the user clicks **Re-Scrub** |
You can place more than one panel on the same record page with different settings — for example, one panel that auto-scrubs the business `Phone` and a second panel for `MobilePhone` that only scrubs on demand.
## Scrubbing a Record
When the Scrub Panel loads, it automatically checks every configured phone field (unless auto-scrub is disabled). If a number was scrubbed within the rescrub interval, the cached result is shown without a new API call; otherwise a fresh check runs.
Each phone field renders as its own card with a status badge, line type, carrier, region, and a **Re-Scrub** button. Click **Re-Scrub** at any time to force a fresh check.
The record's summary fields always reflect the **worst** result across all phone fields. If `Phone` is *Clean* but `MobilePhone` is *Do Not Call*, the record shows **Do Not Call**.
### Reading the result codes
Each phone number receives a result code. Codes marked **Callable: Yes** are considered safe to call.
#### Scrub result codes
These codes are returned by the DNCScrub scrub API and apply to every full scrub.
| Code | Status | Callable | Description |
| -------- | ---------------------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------- |
| `C` | Clean | Yes | Not on any DNC list |
| `D` | Do Not Call | No | On the National Do Not Call Registry |
| `B` | Blocked | No | Number is blocked |
| `P` | Internal DNC | No | On your Internal Do Not Call list |
| `W` | Wireless | Yes | Wireless/mobile number (may require TCPA consent) |
| `L` | Restricted Wireless | No | Wireless in a state that does not allow solicitation to wireless numbers |
| `E` | EBR Valid | Yes | Currently valid EBR, not on a DNC list |
| `O` | EBR Override | Yes | EBR override applied to an otherwise DNC number |
| `G` | EBR + Wireless/VoIP | Yes | Valid EBR on a wireless/VoIP number, not on any DNC list. Cannot be predictive-dialed — an EBR is not an exemption to those rules |
| `H` | EBR Override + Wireless/VoIP | Yes | Wireless/VoIP number with a valid EBR overriding an otherwise DNC number. Cannot be predictive-dialed |
| `F` | EBR + Wireless Restricted | Yes | Valid EBR on a wireless number in a state that prohibits solicitation to wireless **even if manually dialed** (WY, NJ, TX, LA, AZ) |
| `V` | EBR Override + Wireless Restricted | Yes | EBR overriding an otherwise DNC number that is also wireless in a state prohibiting solicitation **even if manually dialed** (WY, NJ, TX, LA, AZ) |
| `Y` | VoIP | Yes | VoIP number not in any DNC database. Only returned when VoIP scrubbing is purchased — otherwise these return as `W` |
| `I`, `M` | Invalid | No | Not a valid or well-formed phone number |
| `X` | Exemption | Yes | A legal industry exemption applies |
For full definitions of every code, see the [scrub output guide](/api-reference/scrub/output-guide).
#### Litigator-only mode codes
When the org is configured for **litigator-only screening**, the app calls the DNCScrub Litigator API instead of the Full Scrub API. That API returns a simple true/false, which the Salesforce app maps to its own two codes so results render in the same UI.
| Code | Status | Callable | Description |
| ----- | ------------- | -------- | ------------------------------ |
| `LIT` | Litigator | No | Known TCPA litigator |
| `NL` | Not Litigator | Yes | Cleared by litigator screening |
## Quick Scrub
The **Quick Scrub** tab (also embedded in the Dashboard) is for ad-hoc checks. Paste one or more phone numbers — comma or newline separated — and get immediate results split into callable and non-callable groups. Quick Scrub does **not** require a Salesforce record and does **not** save results to any record.
## Internal DNC (IDNC) Management
Your **Internal DNC** list is your organization's private do-not-call list, separate from the national registry. Use it when a customer requests not to be called, you receive a written opt-out, or you need to block numbers beyond federal/state lists.
Manage it from the **IDNC Manager** tab — or the IDNC panel on a record page. Enter one or more numbers and use **Check Status**, **Add to IDNC**, or **Remove from IDNC**. Numbers on the IDNC return result code `P` (Internal DNC) and are marked non-callable in all future scrubs.
## EBR Management
An **Existing Business Relationship (EBR)** is a legal exemption that can let you call a DNC-listed number. From the **EBR Manager** tab, use **Add EBR** to record a relationship for a number (EBR type, date, optional reference and brand), and **Check EBR** to see which numbers already have one on file.
| EBR Type | Exemption window |
| ------------------- | ------------------------------------------ |
| **Sale** | 18 months from the last transaction |
| **Inquiry** | 3 months from the consumer's inquiry |
| **Permission** | Express written consent from the consumer |
| **Recent Sale** | Recent transaction (organization-specific) |
| **Newspaper Trial** | Newspaper subscription trial period |
When an EBR is active, the scrub returns codes `E`, `F`, `G`, `H`, or `O` instead of `D`, indicating the number is callable under the exemption.
## Reassignment Check (Authority+)
Under the TCPA, calling a number that was reassigned to a new subscriber after you obtained consent can create legal liability. The **Reassignment Check** tab (Authority+) verifies whether a number still belongs to the original subscriber.
Provide the **Phone Number** and the **Consent Date** — when the customer originally agreed to be contacted.
Select **Check Reassignment**. The system checks whether the number changed hands after the consent date.
If **Safe Harbor** is *Yes*, you have TCPA safe harbor protection — the reassignment database confirms the number had not been reassigned at the time of the call.
## Bulk Scrub and Scheduling
The **Bulk Scrub** tab scrubs records in batches and can run on a schedule.
Select **New Schedule** and choose the object — Lead, Contact, Account, or Campaign Member — and the phone fields to scrub.
Choose how often it runs:
* **One Time** — runs once on a specific date
* **Daily** — runs every day at a set time
* **Weekly** — runs on selected days of the week
* **Monthly** — runs on a specific day of the month
Add filters to target specific records (for example, only Leads with Status = *Hot*). The record-count preview shows how many records will be processed before you save.
**Save Result Code To** copies the raw result code (`C`, `D`, `P`, and so on) onto a field of your choice on each record, which is useful if you already report on an existing column.
Records are processed in batches of 1,000, with one API call per batch of distinct numbers. Records scrubbed within the rescrub interval are skipped — tick **Scrub all records (not just stale)** to override that and re-scrub everything in scope.
Saved schedules are listed with their object, fields, filters, frequency, and next run time. Use the buttons on each row to activate or pause a schedule, edit it, view the status of its most recent run, or delete it.
**A new schedule is saved inactive and will not run until you activate it.** Saving only stores the definition. Select the play button on the schedule's row to activate it; the Status column then changes from *Inactive* to *Active* and a next run time appears. Pausing a schedule stops the underlying job, and reactivating creates it again.
### How a bulk scrub runs
Start times are shown and entered in the time zone noted at the bottom of the schedule list — your Salesforce user's time zone.
When a schedule fires:
All records of the chosen object that have a value in at least one of the selected phone fields, narrowed by any filters you added.
By default, records scrubbed within your rescrub interval are skipped, so a daily schedule over a monthly interval only picks up what has become stale or is new. **Scrub all records (not just stale)** overrides this and re-scrubs everything in scope.
Phone numbers are gathered across all selected fields and reduced to distinct numbers, so the same number appearing on several records — or written in different formats — is sent once, not once per record.
Records are processed in batches of 1,000, with one API call per batch of distinct numbers. Bulk scrub always calls the API rather than reading the cache, and refreshes the cached result for every number it checks.
Each record's summary fields are updated with the **worst** result across its phone fields, and a **Scrub Detail** child record is written per phone field. If you set **Save Result Code To**, the raw code is copied to that field as well. Every operation is recorded in the Scrub Log.
### Checking that a run worked
The schedule row shows **Last Run** and a summary of what happened, for example `Processed: 1,240 (1,240 records)`. The status button on the row opens the progress of the most recent batch job, including any errors.
For more detail:
* **Setup → Apex Jobs** shows the batch job itself, its status, and any failures.
* The **Scrub Log** (`CCC_Scrub_Log__c`) records a `Bulk Scrub` entry per run, and `Bulk Scrub Error` if a run failed.
To be emailed when a run finishes, enable **Send email notification after bulk scrub** on the Settings tab and set the notification address. The email reports how many records were processed and updated.
To try a schedule's settings without waiting for it to fire, use the run button on the schedule row. It runs the same scrub immediately, once, without changing the schedule.
## Where Scrub Data Is Stored
Aggregate (worst-case) results are stored in custom fields on Lead, Contact, Account, and Campaign Member:
| Field Label | API Name | Description |
| ------------- | ---------------------- | ----------------------------------------------------- |
| Scrub Result | `CCC_Scrub_Result__c` | Result code from the most recent scrub |
| Scrub Status | `CCC_Scrub_Status__c` | Human-readable status (Clean, Do Not Call, EBR, etc.) |
| Last Scrubbed | `CCC_Last_Scrubbed__c` | Date and time of the most recent scrub |
| Scrub Reason | `CCC_Scrub_Reason__c` | DNC list match detail or reason |
| Is Reassigned | `CCC_Is_Reassigned__c` | Whether the phone was reassigned (Authority+) |
| EBR Type | `CCC_EBR_Type__c` | Type of EBR exemption, if any |
When multiple phone fields are configured, each gets its own **Scrub Detail** (`CCC_Scrub_Detail__c`) child record tracking that field's result code, status, line type, carrier, region, and last-scrubbed time. Every operation is also written to the **Scrub Log** (`CCC_Scrub_Log__c`) audit object.
### How results are reused between scrubs
Scrub results are cached per phone number in `CCC_Phone_Cache__c`, so the same number is not paid for twice within your rescrub interval — even when it appears on several records, or is stored in different formats. `(415) 323-0415`, `415-323-0415` and `1-415-323-0415` all resolve to the same cached entry.
Bulk Scrub always calls the API and refreshes the cache; Quick Scrub, record-page scrubs and auto-scrub read from it first and only call the API when there is no unexpired entry. Each entry stores its own expiry, stamped when it was written, so changing the rescrub interval affects numbers scrubbed from then on rather than rewriting entries you already have.
The cache holds one row per distinct number and is emptied of expired rows by the daily cleanup job. It is a billing optimisation only — `CCC_Scrub_Log__c` remains the audit record.
### Using scrub data in Salesforce
Because the CCC fields are standard custom fields, they work everywhere:
* **Reports & dashboards** — group or filter on `CCC_Scrub_Status__c` to report compliance across your database.
* **List views** — filter to see all *Do Not Call* or *Clean* records at a glance.
* **Flow / Process Builder** — trigger actions when `CCC_Scrub_Status__c` changes (e.g. notify a manager when a lead is flagged as a litigator).
* **Validation rules** — block lead conversion or activity creation when the status is *Do Not Call* or *Litigator*.
## Administration Notes
* **Rescrub interval** — set on the Settings tab as a value plus a unit of hours, days, or months; applies org-wide to panels, Quick Scrub, and bulk operations.
* **Daily cleanup job** — clears expired cache entries, and old audit logs if you have set a retention period. Its status is shown on the Settings tab, with a **Schedule now** button if it is missing.
* **Storage** — the scrub cache holds one row per distinct phone number, so it grows to roughly the number of unique numbers you scrub and then levels off. `CCC_Scrub_Log__c` grows with every scrub and is the only object without a natural ceiling; check **Setup → Storage Usage** periodically if you scrub at high volume.
* **Remote Site Settings** — three sites must be active for all features. They are included in the package; verify them under **Setup → Remote Site Settings**:
| Name | URL | Used For |
| ------------------ | ------------------------------ | -------------------------------- |
| `CCC_FullScrub` | `https://www.dncscrub.com` | DNC scrubbing, IDNC, and EBR |
| `CCC_DataAPI` | `https://dataapi.dncscrub.com` | Authority+ reassignment checking |
| `CCC_LitigatorAPI` | `https://api.dncscrub.com` | Litigator screening |
## Support
* [DNCScrub API Documentation](/api-reference/overview)
* [Salesforce Lightning Experience Help](https://help.salesforce.com/)
* [Contact Support](mailto:support@dnc.com)
# VICIdial
Source: https://docs.dncscrub.com/integrations/vicidial
Add DNCScrub TCPA and Do Not Call compliance scrubbing to your VICIdial lists and inbound DIDs
This integration filters your [VICIdial](https://www.vicidial.org) lists against state, federal (FTC), and internal DNC lists, as well as TCPA and Litigator scrub — directly through your DNC.com account. It works in two modes: **batch outbound list filtering** that updates lead statuses before you dial, and **inbound DID filtering** that screens calls coming in through DIDs on your system.
DNC.com offers VICIdial users a free 15-day trial of real-time integrated TCPA and DNC Safe Harbor lead scrubbing. [Contact VICIdial](https://www.vicidial.com/?page_id=7) for details on the free offer.
## Prerequisites
* A VICIdial system with command-line (CLI) access to one of your dialers
* A DNCScrub account with API access — your **Login ID** (API ID) and, optionally, a **Project ID** or **Campaign ID**
* Permission to create a Settings Container and edit DID entries in the VICIdial admin
## Step 1: Create the Settings Container
Both the outbound and inbound filters read their configuration from a single VICIdial **Settings Container** with the ID `DNCDOTCOM`. Create it once and customize it for your DNC.com account.
In the VICIdial admin, create a new Settings Container with the container ID `DNCDOTCOM`.
Add your DNC.com credentials and connection options (see the table below). At minimum, set your `LOGIN_ID` and the lists you want to scrub.
Set each `STATUS_*` option to the VICIdial status you want a number to receive when DNC.com returns that result code.
### Connection and account settings
| Setting | Description |
| ---------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `DNC_DOT_COM_URL` | The DNC.com API endpoint. You should not need to change `http://www.dncscrub.com/app/main/rpc/scrub` unless DNC.com changes their API. |
| `LOGIN_ID` | Your DNC.com API ID. |
| `PROJ_ID` | The project whose scrub settings to use. If both `PROJ_ID` and `CAMPAIGN_ID` are omitted, the Master Project is used. |
| `CAMPAIGN_ID` | The campaign to scrub in. If specified, you may omit `PROJ_ID`. If omitted, the Default Campaign of `PROJ_ID` (or of your Master Project) is used. |
| `VERSION` | A value of `2`+ enables Version 2.0 features; `3`+ enables Version 3.0 features, which add result code `Y` for VoIP. With versions below 3, VoIP numbers return as `W` (when VoIP scrubbing is enabled). |
| `VICI_LISTS` | The list IDs to scrub, separated by a hyphen — for example `105-106`. |
| `VICI_STATUS_SKIP` | Statuses within those lists to skip, separated by a hyphen — for example `SALE-DNC`. |
| `ADD_INFO_TO_COMMENTS` | `YES` or `NO`. When `YES`, the `vicidial_list` comments field is overwritten with extra DNC.com fields (DateField, Reason, RegionAbbrev, etc.), comma separated. |
### Example Settings Container
```ini DNCDOTCOM theme={null}
# Connection
DNC_DOT_COM_URL => http://www.dncscrub.com/app/main/rpc/scrub
LOGIN_ID => 1234567890QWERTYUIOP1234567890QWERTYUIOP
PROJ_ID =>
CAMPAIGN_ID =>
VERSION => 3
# Lists to scrub and statuses to skip
VICI_LISTS => 105-106
VICI_STATUS_SKIP => SALE-DNC
# Result-code to status mappings (see table below)
STATUS_X => XDNCCM
STATUS_C => CDNCCM
STATUS_O => ODNCCM
STATUS_E => EDNCCM
STATUS_R => RDNCCM
STATUS_W => WDNCCM
STATUS_G => GDNCCM
STATUS_H => HDNCCM
STATUS_L => LDNCCM
STATUS_F => FDNCCM
STATUS_V => VDNCCM
STATUS_I => IDNCCM
STATUS_M => MDNCCM
STATUS_B => BDNCCM
STATUS_P => PDNCCM
STATUS_D => DDNCCM
STATUS_S => SDNCCM
STATUS_T => TDNCCM
STATUS_Y => YDNCCM
# Overwrite the comments field with extra DNC.com detail (YES/NO)
ADD_INFO_TO_COMMENTS => NO
```
### Result codes
When DNC.com scrubs a number, it returns a result code. Each `STATUS_*` setting controls the VICIdial status the lead is updated to for that code. The defaults above (`*DNCCM`) are examples — set them to whatever fits your dial plan.
| Code | Setting | Meaning |
| ---- | ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `X` | `STATUS_X` | Industry eXemption applied to an otherwise Do Not Call number — number can be called |
| `C` | `STATUS_C` | Clean number — can be called |
| `O` | `STATUS_O` | EBR Override applied to an otherwise Do Not Call number (including an explicit EBR overriding a number in Project DNC) — number can be called |
| `E` | `STATUS_E` | Valid EBR, currently valid, not on a Do Not Call list — number can be called |
| `R` | `STATUS_R` | Expired EBR — formerly a valid EBR, not on a Do Not Call list; number can be called *(this result code will be available in the near future)* |
| `W` | `STATUS_W` | US Wireless number — not in any DNC database (or overridden by an industry exemption), but cannot be called from a predictive dialer |
| `G` | `STATUS_G` | Valid EBR and US Wireless or VoIP number, not on any DNC database (v2+) — still cannot be called from a predictive dialer, as EBRs are not an exemption to those rules |
| `H` | `STATUS_H` | US Wireless or VoIP number that is also a valid EBR overriding an otherwise DNC number (v2+) — still cannot be called from a predictive dialer |
| `L` | `STATUS_L` | Wireless number in a US state that does not allow telemarketing to wireless numbers even if manually dialed; not on any DNC list and not an EBR (v2+) |
| `F` | `STATUS_F` | Valid EBR and wireless number in a US state that does not allow telemarketing to wireless numbers even if manually dialed; not on any DNC list (v2+) |
| `V` | `STATUS_V` | Valid EBR overriding an otherwise DNC number that is also a wireless number in a US state that does not allow telemarketing to wireless even if manually dialed (WY, NJ, TX, LA, AZ) (v2+) |
| `I` | `STATUS_I` | Invalid — area code not active, or reserved/special-use phone number pattern (e.g. `555-5555`) |
| `M` | `STATUS_M` | Malformed — number is not 10 digits, etc. (this typically returns an error response instead of this code) |
| `B` | `STATUS_B` | Blocked — number is in an area code not covered by the project's National Subscription, a configured no-call area code, or no exemption was available in a pre-recorded call campaign |
| `P` | `STATUS_P` | Project DNC or DNF (Do Not Fax) database match (no further checks are performed) |
| `D` | `STATUS_D` | Do Not Call database match; the Reason field provides additional detail |
| `S` | `STATUS_S` | Disconnected — number matched a disconnected-numbers database *(future service)* |
| `T` | `STATUS_T` | Tier C phone company (call may be more expensive) *(future service)* |
| `Y` | `STATUS_Y` | VoIP number not in any DNC database (or overridden by an industry exemption). Returned only when `VERSION => 3` and the project has VoIP scrubbing enabled; otherwise such numbers return as `W` |
## Step 2: Run Outbound List Filtering
Outbound filtering runs in **batch mode** against lists that are already loaded on your system. It does **not** look up numbers as they are dialed.
Run the filter script from the Linux command line, passing the lists to scrub:
```bash theme={null}
AST_DNCcom_filter.pl --lists=LISTID1-LISTID2
```
Schedule it from the crontab of one of your dialers. Run it after-hours, or only during calling hours on inactive lists, to avoid scrubbing leads that are actively being dialed.
The `--lists` argument and the `VICI_LISTS` setting both identify lists with IDs separated by a hyphen (for example `105-106`).
## Step 3: Configure Inbound DID Filtering
A separate script, `DNCcom_inbound_filter.php`, screens calls coming in through your DIDs. It uses the same `DNCDOTCOM` Settings Container, plus two inbound-specific options.
### Inbound settings
| Setting | Description |
| ---------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `INBOUND_FILTER` | A comma-separated list of what to block: `USADNC` (federal DNC numbers), `PROJDNC` (internal project DNC numbers), `LITIGATOR` (the litigator list, if subscribed), and `INVALID` (invalid numbers). |
| `INBOUND_CACHE` | Number of days of recent DNC.com query results to search before making a new request, to reduce redundant lookups. Default is `0` (disabled). |
```ini DNCDOTCOM (inbound additions) theme={null}
INBOUND_FILTER => USADNC,PROJDNC,LITIGATOR,INVALID
INBOUND_CACHE => 0
```
### Point a DID at the filter
On the DID entry, set **Filter Inbound Number** to `URL`. For a system-wide filter, use the `did_system_filter` DID entry, reached from the link on the **Admin → System Settings** page.
Set the DID's **Filter URL** to point at the inbound filter script on your webserver. Replace the IP with the local address your dialers use to reach the webserver (the example below assumes `192.168.1.3`):
```text theme={null}
http://192.168.1.3/vicidial/DNCcom_inbound_filter.php?phone=--A--phone_number--B--
```
If you receive calls from North America, set the DID option **Clean CID Number** to `R10` so numbers are always looked up as proper 10-digit values.
## Related
For batch cellphone filtering specifically, see VICIdial's `CELLPHONE_USA_TCPA_FCC_COMPLIANCE.txt` document.
## Support
* [DNCScrub API Documentation](/api-reference/overview)
* [VICIdial DNC.com Integration Guide](https://vicidial.org/docs/DNC-dot-COM_integration.txt)
* [Contact Support](mailto:support@dnc.com)
# Interaction Methods
Source: https://docs.dncscrub.com/interaction-methods
Web, SFTP, API, or MCP Server
We support **three** primary ways to integrate or interact with our services. Choose the approach that fits your architecture and workflow:
| Method | Description |
| -------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Web Portal** | Use our browser-based portal to manually upload or manage your call lists, run scrubs, view results, and configure settings. |
| **SFTP** | Upload files via secure file transfer (SFTP) if you prefer batch processing or want to integrate with offline or legacy systems. This is an excellent integration option for large enterprises with existing batch processes. |
| **API** | Integrate programmatically using our REST API — ideal for real-time scrubbing, automation, and integration with your dialer, CRM, or other systems. |
> **Note:** You can mix and match these methods depending on your use case. For example, you might process large call batches via SFTP and then use the API for real-time checks before dialing.
For AI-assisted interactions, we also offer two MCP Servers. One is for AI-assisted applications and the other is for AI-assisted development.
***
## Next Steps
* If you prefer interactive, manual file uploads or one-off scrubs, start with the **[Web Portal](https://dncscrub.com)**.
* For bulk uploads and scheduled batch processing, see **SFTP**.
* If you want API automation — e.g. integrate DNCScrub directly into your dialing platform or CRM — see the **API Reference** section.
Happy calling — and stay compliant!
# Welcome to Contact Center Compliance
Source: https://docs.dncscrub.com/introduction
Powerful tools for TCPA Compliance, DNC Scrubbing, Call Deliverability, and Data Enhancement
Contact Center Compliance, [a Sonera company](https://sonera.co), provides a comprehensive and powerful compliance platform to help you reliably build, run, and scale your compliant calling operations. Scrub against Federal and State DNC lists, detect litigators, verify reassigned numbers, optimize call deliveraiblity, and ensure your outbound calling campaigns meet regulatory requirements—all through our powerful APIs and integrations.
## Need an account?
[Schedule a Meeting](https://www.dnc.com/schedule-meeting/) to get started.
Integrate DNC scrubbing, litigator detection, reassigned number
verification, and data enhancement directly into your applications with our
RESTful APIs.
Connect Contact Center Compliance with your existing platforms including
Genesys, Zoom, Salesforce, Zapier, and more.
Give AI agents real-time access to compliance APIs via the Model Context
Protocol. Perfect for voice AI, dialers, and LLM-powered applications.
Connect your AI coding assistant to our documentation for accurate code
generation and implementation guidance.
For billing, account settings, and user access, visit [dncscrub.com](https://www.dncscrub.com).
# add_ebr Tool
Source: https://docs.dncscrub.com/mcp/applications/ebr
Add Existing Business Relationship records to establish DNC exemptions
The `add_ebr` tool adds Existing Business Relationship records to your DNCScrub account. An EBR can provide an exemption to DNC rules, allowing you to contact numbers that would otherwise be restricted.
## Parameters
Array of EBR records to add.
10-digit phone number.
Date of the business relationship event. Formats: `MM/DD/YY`, `MM/DD/YYYY`, or `YYYY-MM-DD`.
EBR type:
* `S` - Sale/Purchase (18-month exemption)
* `I` - Inquiry (3-month exemption)
* `P` - Permission (express written consent / opt-in; the only type that can override an Internal DNC entry)
Company/product/brand name used to establish the EBR.
Your internal tracking ID for audit purposes.
API key. Only required if not provided via the `x-dncscrub-api-key` HTTP header.
If `true`, existing EBR records with longer exemption periods won't be overwritten.
## Response
Whether the API call succeeded.
Number of EBR records successfully added.
Machine-readable error code (when failed).
Human-readable error description (when failed).
## EBR Expiration Rules
| EBR Type | Federal Exemption Period |
| ------------------- | ------------------------------- |
| Sale/Purchase (`S`) | 18 months from last transaction |
| Inquiry (`I`) | 3 months from inquiry date |
State rules may have shorter exemption periods. The scrub API accounts for state-specific rules automatically.
## Examples
```json theme={null}
{
"records": [
{
"phoneNumber": "7075712071",
"dateOfLastContact": "2024-06-14",
"type": "S",
"brand": "Acme Corp"
}
]
}
```
```json theme={null}
{
"records": [
{
"phoneNumber": "7075712071",
"dateOfLastContact": "2024-06-14",
"type": "S"
},
{
"phoneNumber": "7072842774",
"dateOfLastContact": "2024-07-02",
"type": "I",
"referenceNum": "LEAD-12345"
}
]
}
```
```json theme={null}
{
"success": true,
"recordsAdded": 2
}
```
## Usage Notes
* Use accurate dates—the `dateOfLastContact` should be the actual business relationship date, not today's date
* Choose the correct EBR type: using the wrong type could create compliance issues
* The `referenceNum` field is useful for audit trails and tracing back to your CRM records
* Set `keepBetterEBR: true` to prevent accidentally downgrading a Sale EBR to an Inquiry EBR
# get_legal_call_times Tool
Source: https://docs.dncscrub.com/mcp/applications/get-legal-call-times
Get legal calling windows for phone numbers on a given date
The `get_legal_call_times` tool returns the legal calling windows (start and end times in UTC) for phone numbers on a given date. Use this to schedule calls in advance or display available calling times to agents.
## When to Use
* Planning call schedules for future dates
* Displaying legal calling windows to agents
* Building call queues with time-aware scheduling
## Parameters
Array of objects containing phone numbers and dates.
10-digit North American phone number (e.g., `"5039367187"`).
ISO 8601 date for which to get legal calling times (e.g., `"2024-01-15"`).
Optional DNCScrub project ID for custom calling hours.
Number of days to return (defaults to 1).
API key. Only required if not provided via the `x-dncscrub-api-key` HTTP header.
## Response
Whether the API call succeeded.
Array of results, one per phone number.
The phone number checked.
Array of legal calling time windows.
Start of legal calling window in UTC.
End of legal calling window in UTC.
`true` if there is at least one legal window to call.
Machine-readable error code (when failed).
Human-readable error description (when failed).
## Examples
```json theme={null}
{
"phoneNumbers": [
{
"phoneNumber": "5039367187",
"date": "2024-01-15"
}
]
}
```
```json theme={null}
{
"success": true,
"results": [
{
"phone": "5039367187",
"legalWindows": [
{
"startUTC": "2024-01-15T16:00:00Z",
"endUTC": "2024-01-16T05:00:00Z"
}
],
"hasLegalWindow": true
}
]
}
```
```json theme={null}
{
"success": true,
"results": [
{
"phone": "5039367187",
"legalWindows": [],
"hasLegalWindow": false
}
]
}
```
## Usage Notes
* Times are returned in UTC - convert to local time for display
* Some dates may have no legal windows (holidays, emergencies)
* Use `numberOfDays` to get windows for multiple consecutive days
* For real-time "can I call now?" checks, use `is_time_legal_to_call` instead
# get_phone_type Tool
Source: https://docs.dncscrub.com/mcp/applications/get-phone-type
Check if a phone number is residential or business
The `get_phone_type` tool returns whether a phone number is registered as residential or business. This is useful for B2B campaigns or compliance scenarios where different rules apply.
## When to Use
* B2B campaigns that should only target business numbers
* Compliance scenarios where residential vs business distinction matters
* Lead qualification and routing decisions
## Parameters
10-digit North American phone number to check (e.g., `"5039367187"`).
API key. Only required if not provided via the `x-dncscrub-api-key` HTTP header.
## Response
Whether the API call succeeded.
The phone number checked.
* `R` - Residential
* `B` - Business
* `U` - Unknown
Human-readable description of the type.
`true` if the number is residential.
`true` if the number is a business line.
Machine-readable error code (when failed).
Human-readable error description (when failed).
## Examples
```json theme={null}
{
"phone": "5039367187"
}
```
```json theme={null}
{
"success": true,
"phone": "5039367187",
"type": "R",
"typeDescription": "Residential phone number",
"isResidential": true,
"isBusiness": false
}
```
```json theme={null}
{
"success": true,
"phone": "5039367187",
"type": "B",
"typeDescription": "Business phone number",
"isResidential": false,
"isBusiness": true
}
```
## Usage Notes
* Some numbers may return `U` (Unknown) if classification data is not available
* Business numbers may have different DNC exemptions depending on your campaign type
* Consider combining with `scrub_phone_numbers` for complete compliance checking
# get_state_emergencies Tool
Source: https://docs.dncscrub.com/mcp/applications/get-state-emergencies
Get states with emergency declarations restricting telephone solicitations
The `get_state_emergencies` tool returns all states currently under emergency declarations that restrict telephone solicitation calls. Some states prohibit or restrict telephone solicitations during declared emergencies such as natural disasters.
## When to Use
* Checking for active emergencies before campaigns
* Real-time compliance monitoring
* Disaster response awareness for call centers
## Parameters
API key. Only required if not provided via the `x-dncscrub-api-key` HTTP header.
## Response
Whether the API call succeeded.
List of all states with their emergency status.
2-letter state code.
`true` if state has active emergency restrictions.
List of state codes currently under emergency restrictions.
`true` if any state has active emergency restrictions.
Machine-readable error code (when failed).
Human-readable error description (when failed).
## Examples
```json theme={null}
{}
```
```json theme={null}
{
"success": true,
"states": [
{ "state": "CA", "isInEmergency": false },
{ "state": "FL", "isInEmergency": false },
{ "state": "TX", "isInEmergency": false }
],
"emergencyStates": [],
"hasActiveEmergencies": false
}
```
```json theme={null}
{
"success": true,
"states": [
{ "state": "CA", "isInEmergency": false },
{ "state": "FL", "isInEmergency": true },
{ "state": "TX", "isInEmergency": false }
],
"emergencyStates": ["FL"],
"hasActiveEmergencies": true
}
```
## Usage Notes
* Check regularly during disaster seasons (hurricane, wildfire, etc.)
* Emergency restrictions can be declared and lifted quickly
* Use `emergencyStates` array for quick filtering
* The `hasActiveEmergencies` flag provides a quick check if any restrictions exist
* For real-time compliance, `is_time_legal_to_call` automatically accounts for emergencies
# get_state_holidays Tool
Source: https://docs.dncscrub.com/mcp/applications/get-state-holidays
Get state holidays where telephone solicitation calls are prohibited
The `get_state_holidays` tool returns all states and their restricted holidays where telephone solicitation calls are prohibited. Use this to plan campaigns and avoid calling on state holidays.
## When to Use
* Planning campaign schedules around state holidays
* Building holiday-aware calling calendars
* Compliance auditing and reporting
## Parameters
API key. Only required if not provided via the `x-dncscrub-api-key` HTTP header.
## Response
Whether the API call succeeded.
List of all state holidays with calling restrictions.
2-letter state code.
Date of the holiday.
Name of the holiday.
Number of unique states with restricted holidays.
Total number of restricted holidays.
Machine-readable error code (when failed).
Human-readable error description (when failed).
## Examples
```json theme={null}
{}
```
```json theme={null}
{
"success": true,
"holidays": [
{
"state": "CA",
"date": "2024-01-01",
"name": "New Year's Day"
},
{
"state": "CA",
"date": "2024-07-04",
"name": "Independence Day"
},
{
"state": "NY",
"date": "2024-01-01",
"name": "New Year's Day"
},
{
"state": "TX",
"date": "2024-03-02",
"name": "Texas Independence Day"
}
],
"stateCount": 3,
"holidayCount": 4
}
```
## Usage Notes
* Different states have different restricted holidays
* Some holidays are state-specific (e.g., Texas Independence Day)
* Federal holidays may not be restricted in all states
* Use this data to build state-aware calling calendars
* For real-time holiday checking, `is_time_legal_to_call` automatically accounts for holidays
# get_timezone_info Tool
Source: https://docs.dncscrub.com/mcp/applications/get-timezone-info
Get timezone and location information for phone numbers
The `get_timezone_info` tool returns timezone and location information for North American phone numbers. Use this to determine local time before calling.
## When to Use
* Determining the local time at a phone number's location
* Planning call schedules across multiple time zones
* Ensuring calls are made during appropriate hours
## Parameters
List of 10-digit North American phone numbers (e.g., `["5039367187", "2125551234"]`).
Optional ISO 8601 datetime to use instead of current time for DST calculations.
API key. Only required if not provided via the `x-dncscrub-api-key` HTTP header.
## Response
Whether the API call succeeded.
Array of results, one per phone number.
The phone number checked.
Timezone name (e.g., `America/Los_Angeles`).
2-letter state/province code.
UTC offset string (e.g., `-08:00`).
UTC offset in minutes.
Whether this timezone observes daylight saving time.
Next DST start date.
Next DST end date.
Local Access Transport Area code.
Rate center / LIR info.
Machine-readable error code (when failed).
Human-readable error description (when failed).
## Examples
```json theme={null}
{
"phoneNumbers": ["5039367187", "2125551234"]
}
```
```json theme={null}
{
"success": true,
"results": [
{
"phone": "5039367187",
"timezone": "America/Los_Angeles",
"state": "OR",
"utcOffset": "-08:00",
"utcOffsetMinutes": -480,
"hasDST": true,
"dstStartDate": "2024-03-10",
"dstEndDate": "2024-11-03",
"lata": "672",
"rateCenter": "PORTLAND"
},
{
"phone": "2125551234",
"timezone": "America/New_York",
"state": "NY",
"utcOffset": "-05:00",
"utcOffsetMinutes": -300,
"hasDST": true,
"dstStartDate": "2024-03-10",
"dstEndDate": "2024-11-03",
"lata": "132",
"rateCenter": "NEW YORK"
}
]
}
```
## Usage Notes
* Batch multiple numbers in a single request for efficiency
* Use `utcOffsetMinutes` for programmatic time calculations
* DST dates help plan for time changes
* For real-time "can I call now?" checks, use `is_time_legal_to_call` instead
# Getting Started
Source: https://docs.dncscrub.com/mcp/applications/getting-started
Connect your AI application to the DNCScrub MCP Server
## Connection Details
| Setting | Value |
| ------------------ | ------------------------------------------------ |
| **Server URL** | `https://mcp.dncscrub.com/mcp` |
| **Transport** | HTTP POST (Streamable HTTP) |
| **Authentication** | HTTP Header: `x-dncscrub-api-key: YOUR_LOGIN_ID` |
## Getting Your API Key
Your API key is your DNCScrub **Login ID**:
1. Log in to [dncscrub.com](https://dncscrub.com)
2. Navigate to **Users**
3. Under your API User, select **Get API Key**
## Client Configuration
Add to your `claude_desktop_config.json`:
```json theme={null}
{
"mcpServers": {
"dncscrub": {
"url": "https://mcp.dncscrub.com/mcp",
"headers": {
"x-dncscrub-api-key": "YOUR_LOGIN_ID"
}
}
}
}
```
On macOS, this file is at `~/Library/Application Support/Claude/claude_desktop_config.json`
Configure your MCP-compatible client with:
* **Transport Type**: HTTP (Streamable)
* **Endpoint**: `https://mcp.dncscrub.com/mcp`
* **Headers**: `x-dncscrub-api-key: YOUR_LOGIN_ID`
## Configuration Options
### Campaigns & Projects
Use `campaignId` or `projId` parameters to for Full Scrub tools:
* Track API usage by campaign
* Apply campaign-specific sensitivity settings
### Sensitivity Settings
Litigator scrub sensitivity and lookback periods are configured in the DNCScrub portal, not in MCP requests.
To adjust settings:
1. Log in to [dncscrub.com](https://dncscrub.com)
2. Navigate to your campaign settings
3. Configure sensitivity and lookback period
## Next Steps
Learn how to check phone numbers against the litigator database.
# global_phone_lookup Tool
Source: https://docs.dncscrub.com/mcp/applications/global-phone-lookup
Look up international phone numbers outside North America
The `global_phone_lookup` tool provides detailed information about international phone numbers outside North America. It returns country, region, carrier, timezone, and geographic coordinates.
## When to Use
* If you are only calling in North America, use other tools instead
* Determining timezone and location for international contacts
* Identifying carrier and line type for international numbers
## Parameters
Country calling code without the `+` sign (e.g., `"44"` for UK, `"49"` for
Germany, `"81"` for Japan).
Phone number without the country code (e.g., `"2079460123"` for a UK number).
API key. Only required if not provided via the `x-dncscrub-api-key` HTTP
header.
## Response
Whether the API call succeeded.
Full country name.
2-letter ISO country code.
Region/state/province code.
Full region/state/province name.
City name.
Timezone name.
UTC offset string.
DST indicator.
Latitude coordinate.
Longitude coordinate.
Type of number (mobile, landline, etc).
Carrier/operator name.
Primary language in the region.
Machine-readable error code (when failed).
Human-readable error description (when failed).
## Examples
```json theme={null}
{
"internationalCode": "44",
"phone": "2079460123"
}
```
```json theme={null}
{
"success": true,
"country": "United Kingdom",
"countryCode": "GB",
"regionCode": "ENG",
"regionName": "England",
"city": "London",
"timezone": "Europe/London",
"utcOffset": "+00:00",
"hasDST": "Y",
"latitude": "51.5074",
"longitude": "-0.1278",
"numberType": "Landline",
"carrier": "BT",
"language": "English"
}
```
## Common Country Codes
| Country | Code |
| -------------- | ---- |
| United Kingdom | 44 |
| Germany | 49 |
| France | 33 |
| Japan | 81 |
| Australia | 61 |
| India | 91 |
| Brazil | 55 |
| Mexico | 52 |
# add_internal_dnc Tool
Source: https://docs.dncscrub.com/mcp/applications/internal-dnc
Add or remove phone numbers from your Internal DNC list
The `add_internal_dnc` tool manages your organization's private Do Not Call list. Use it to add numbers when contacts request no further calls, or remove numbers when appropriate.
## Parameters
Phone numbers in 10-digit North American format (e.g., `"8663625478"`).
Action to perform:
* `add` - Add numbers to Internal DNC list
* `remove` - Remove numbers from Internal DNC list (requires an elevated role, see below)
**`remove` requires an elevated role.** The API key's user must be a
Supervisor or Administrator, unless removal has been enabled for the Agent
role on your account. `add` is available to every role. An Agent key
attempting `remove` fails with `API_ERROR`.
See [Internal DNC List](/api-reference/scrub/internal-dnc) for the underlying
API.
API key. Only required if not provided via the `x-dncscrub-api-key` HTTP header.
Project ID to scope the Internal DNC list. Useful for multi-client or multi-campaign setups.
## Response
Whether the API call succeeded.
The action that was performed: `add` or `remove`.
How many phone numbers were processed.
The phone numbers that were processed.
Array of results for each phone number, in the order they were submitted.
The phone number processed.
Result: `added`, `removed`, `already_exists`, or `not_found`.
Machine-readable error code (when failed).
Human-readable error description (when failed).
The underlying API confirms an `add` or `remove` without saying what each
number's prior state was, so the tool reads the list immediately before
changing it and reports the difference. Each `status` therefore reflects a
snapshot taken just before the change; a concurrent edit to the same list can
make it stale. `results` is omitted entirely if that read does not return
JSON — `success` still tells you whether the change itself went through.
## Error Codes
| Code | Description |
| ----------------- | ------------------------------------------ |
| `MISSING_API_KEY` | No API key provided in header or parameter |
| `INVALID_API_KEY` | The API key is invalid or unauthorized |
| `API_ERROR` | DNCScrub API returned an error |
| `MISSING_INPUT` | Required parameters are missing |
| `INVALID_PHONE` | One or more phone numbers are invalid |
## Examples
```json theme={null}
{
"phoneNumbers": ["5039367187", "7075276405"],
"action": "add"
}
```
```json theme={null}
{
"success": true,
"action": "add",
"phoneCount": 2,
"phoneNumbers": ["5039367187", "7075276405"],
"results": [
{ "phone": "5039367187", "status": "added" },
{ "phone": "7075276405", "status": "already_exists" }
]
}
```
```json theme={null}
{
"phoneNumbers": ["5039367187"],
"action": "remove"
}
```
```json theme={null}
{
"success": true,
"action": "remove",
"phoneCount": 1,
"phoneNumbers": ["5039367187"],
"results": [{ "phone": "5039367187", "status": "removed" }]
}
```
## Usage Notes
* Adding a number that already exists has no effect (idempotent); `results` reports it as `already_exists`
* Removing a number that isn't on the list has no effect; `results` reports it as `not_found`
* Use `projId` to maintain separate Internal DNC lists per project or client
* Phone numbers must be exactly 10 digits without formatting
# is_disconnected Tool
Source: https://docs.dncscrub.com/mcp/applications/is-disconnected
Real-time check if a phone number is disconnected
The `is_disconnected` tool checks in real-time if a phone number is disconnected or no longer in service. Use this to avoid wasting time calling invalid numbers.
## When to Use
* Before making calls to verify the number is still active
* Cleaning up contact lists by removing dead numbers
* Reducing wasted dial attempts and improving connect rates
## Parameters
10-digit North American phone number to check (e.g., `"5039367187"`).
API key. Only required if not provided via the `x-dncscrub-api-key` HTTP header.
## Response
Whether the API call succeeded.
The phone number checked.
* `C` - Connected (number is active)
* `D` - Disconnected (number is no longer in service)
* `U` - Unknown (unable to determine)
Human-readable explanation of the status.
`true` if the phone number is currently connected.
`true` if the phone number is disconnected.
Machine-readable error code (when failed).
Human-readable error description (when failed).
## Examples
```json theme={null}
{
"phoneNumber": "5039367187"
}
```
```json theme={null}
{
"success": true,
"phone": "5039367187",
"status": "C",
"statusDescription": "Connected - phone number is currently active and in service",
"isConnected": true,
"isDisconnected": false
}
```
```json theme={null}
{
"success": true,
"phone": "5039367187",
"status": "D",
"statusDescription": "Disconnected - phone number is no longer in service",
"isConnected": false,
"isDisconnected": true
}
```
## Usage Notes
* This is a real-time check, providing current status
* Disconnected numbers should be removed from your calling lists
* Consider checking periodically for numbers that haven't been reached
* Reduces wasted dial attempts and improves campaign efficiency
# is_litigator Tool
Source: https://docs.dncscrub.com/mcp/applications/is-litigator
Check if phone numbers belong to known TCPA litigators
The `is_litigator` tool checks if one or more phone numbers are associated with individuals who have filed TCPA (Telephone Consumer Protection Act) or related consumer-protection lawsuits.
## Parameters
Phone numbers in 10-digit North American format (e.g., `"8663625478"`).
API key. Only required if not provided via the `x-dncscrub-api-key` HTTP header.
Campaign ID in DNCScrub for usage tracking and sensitivity configuration.
Project ID in DNCScrub for usage tracking and sensitivity configuration.
## Response
Whether the API call succeeded.
Array of phone check results (when successful).
The phone number that was checked.
`true` if the number belongs to a known litigator.
Machine-readable error code (when failed).
Human-readable error description (when failed).
## Error Codes
| Code | Description |
| ----------------- | ------------------------------------------ |
| `MISSING_API_KEY` | No API key provided in header or parameter |
| `INVALID_API_KEY` | The API key is invalid or unauthorized |
| `API_ERROR` | DNCScrub API returned an error |
| `MISSING_INPUT` | Required parameters are missing |
## Examples
```json theme={null}
{
"phoneNumbers": ["8663625478", "5551234567"]
}
```
```json theme={null}
{
"success": true,
"results": [
{ "phone": "8663625478", "isLitigator": false },
{ "phone": "5551234567", "isLitigator": true }
]
}
```
```json theme={null}
{
"success": false,
"errorCode": "INVALID_API_KEY",
"errorMessage": "The provided API key is invalid or unauthorized"
}
```
## Usage Notes
* Check multiple numbers in a single request for better performance
* Results are returned in the same order as the input array
* Phone numbers should be 10 digits without formatting (no dashes, spaces, or country code)
# is_reassigned_number Tool
Source: https://docs.dncscrub.com/mcp/applications/is-reassigned-number
Check if a phone number has been reassigned using the FCC Reassigned Numbers Database
The `is_reassigned_number` tool checks if a phone number has been reassigned to a new owner since consent was given, using the FCC Reassigned Numbers Database (RND).
## When to Use
* Use this tool before calling to ensure consent is still valid. If a number has been reassigned, the original consent no longer applies to the new owner.
* Safe harbor is required
## Parameters
Array of objects containing phone numbers and consent dates.
10-digit North American phone number (e.g., `"5039367187"`).
Date consent was given in `YYYYMMDD`, `MM/DD/YYYY`, or `YYYY-MM-DD` format.
API key. Only required if not provided via the `x-dncscrub-api-key` HTTP
header.
## Response
Whether the API call succeeded.
Array of results, one per phone number.
The phone number checked.
* `true` - Number has been reassigned (do not call)
* `false` - Number has not been reassigned (safe to call)
* `null` - Insufficient data to determine
Whether FCC safe harbor exemption may be available.
Simple yes/no based on `isReassigned` being `false` or `null` with safe harbor.
Machine-readable error code (when failed).
Human-readable error description (when failed).
## Examples
```json theme={null}
{
"phoneNumbers": [
{
"phoneNumber": "5039367187",
"consentDate": "2023-06-15"
}
]
}
```
```json theme={null}
{
"success": true,
"results": [
{
"phone": "5039367187",
"isReassigned": false,
"hasSafeHarbor": true,
"isSafeToCall": true
}
]
}
```
```json theme={null}
{
"success": true,
"results": [
{
"phone": "5039367187",
"isReassigned": true,
"hasSafeHarbor": false,
"isSafeToCall": false
}
]
}
```
## Usage Notes
* Always provide the actual consent date, not the current date
* A `null` result with `hasSafeHarbor: true` may still be safe to call under FCC safe harbor provisions
# is_time_legal_to_call Tool
Source: https://docs.dncscrub.com/mcp/applications/is-time-legal-to-call
Real-time check if it's legal to call based on time restrictions
The `is_time_legal_to_call` tool checks if it is currently legal to call a phone number based on the recipient's local time and state regulations. Use this for real-time call decisions.
## When to Use
* Before initiating an outbound call
* Real-time compliance checking in dialers
* Voice AI pre-call screening
## Parameters
Array of objects containing phone numbers and proposed call times.
10-digit North American phone number (e.g., `"5039367187"`).
ISO 8601 datetime in UTC when you want to call (e.g., `"2024-01-15T14:30:00Z"`). **Optional - defaults to current UTC time if not provided.**
Optional DNCScrub project ID for custom calling hours.
API key. Only required if not provided via the `x-dncscrub-api-key` HTTP header.
## Response
Whether the API call succeeded.
Array of results, one per phone number.
The phone number checked.
`true` if calling is legal at the proposed time.
Seconds remaining in legal calling window (0 if not permitted).
Minutes remaining in legal calling window for convenience.
Machine-readable error code (when failed).
Human-readable error description (when failed).
## Examples
```json theme={null}
{
"phoneNumbers": [
{
"phoneNumber": "5039367187",
"callProposedDateTimeInUTC": "2024-01-15T18:30:00Z"
}
]
}
```
```json theme={null}
{
"success": true,
"results": [
{
"phone": "5039367187",
"isCallPermitted": true,
"secondsRemaining": 7200,
"minutesRemaining": 120
}
]
}
```
```json theme={null}
{
"success": true,
"results": [
{
"phone": "5039367187",
"isCallPermitted": false,
"secondsRemaining": 0,
"minutesRemaining": 0
}
]
}
```
## Usage Notes
* The `callProposedDateTimeInUTC` parameter is optional - if omitted, it defaults to the current UTC time
* `secondsRemaining` tells you how long you have before the calling window closes
* Different states have different calling hour restrictions
* Some states have additional restrictions on Sundays and holidays
* For planning future calls, use `get_legal_call_times` instead
# MCP Server for Applications
Source: https://docs.dncscrub.com/mcp/applications/overview
Give AI agents real-time access to powerful compliance tools
The DNCScrub MCP Server provides compliance tools to AI-assisted call center applications. It connects AI Agents, Voice AI platforms, Dialers, and more to Contact Center Compliance's powerful APIs. Provides the LLM 16 tools for Compliance, Call Deliverability, and Data Enhancement.
## Quickstart
```json theme={null}
{
"mcpServers": {
"dncscrub": {
"url": "https://mcp.dncscrub.com/mcp",
"headers": {
"x-dncscrub-api-key": "YOUR_LOGIN_ID"
}
}
}
}
```
Authenticate with the `x-dncscrub-api-key` header, as shown above. The API key
is your DNCScrub Login ID.
Your API key is your DNCScrub **Login ID**. Find it in the [DNCScrub
portal](https://dncscrub.com) under **Users** → **Get API Key**. Your API key
is your DNCScrub **Login ID**. Find it in the [DNCScrub
portal](https://dncscrub.com) under **Users** → **Get API Key**.
## Why Use This Server?
Modern LLMs are powerful—but they lack:
* Knowledge of Federal & State DNC rules
* Awareness of calling windows and holiday restrictions
* Litigator detection
* Reassigned number verification
* Real-time campaign-specific policies
The DNCScrub MCP Server fills this gap.
This MCP server **executes real API calls** for compliance operations. For
AI-assisted development and documentation search, see [MCP for
Developers](/mcp/developers/overview).
## Get Started
Get connected in minutes with configuration examples for Claude Desktop and
other MCP clients.
## Available Tools
### DNC & Litigator Scrubbing
Full compliance scrub against Federal DNC, State DNC, Internal DNC,
litigators, wireless status, and calling time restrictions.
Check if phone numbers belong to known TCPA litigators.
### Reassigned Number Verification
Check if a phone number has been reassigned using the FCC Reassigned Numbers
Database. Requires consent date. Provides safe harbor.
Check if a phone number has been reassigned using carrier deactivation data.
Requires consent date. Does not provide safe harbor.
### Identity & Phone Data
Verify if a name and/or address matches the phone number owner. Confirms
consent is still valid.
Returns whether a phone number is residential or business. Useful for B2B
campaigns.
Real-time check if a phone number is disconnected or no longer in service.
Look up international phone numbers outside North America. Returns country,
carrier, timezone, and location.
### Timezone & Calling Hours
Returns timezone, UTC offset, DST info, and state/province for phone
numbers.
Real-time check if it's currently legal to call based on recipient's local
time and state regulations.
Returns legal calling windows (start/end times in UTC) for phone numbers on
a given date.
### Compliance Reference
Searches the Compliance Guide and returns ranked, citable regulatory guidance
to ground AI agents' compliance answers in DNCScrub's authoritative source.
Returns all state holidays where telephone solicitation calls are prohibited.
Returns states currently under emergency declarations that restrict
telephone solicitations.
### List Management
Add or remove phone numbers from your Internal Do Not Call list. Use when
consumers request to opt out.
Add Existing Business Relationship records for DNC exemptions. Supports Sale
(18-month), Inquiry (3-month), and Permission types.
## Use Cases
Voice AI screening, dialer integration, agent assist, and lead qualification.
## Support
* Create a support ticket at [dncscrub.com/help/new](https://dncscrub.com/help/new)
* Email: [support@dnc.com](mailto:support@dnc.com)
# scrub_phone_numbers Tool
Source: https://docs.dncscrub.com/mcp/applications/scrub-phones
Scrub phone numbers against DNC lists and get compliance status
The `scrub_phone_numbers` tool checks phone numbers against federal, state, and your internal DNC lists, returning compliance status and phone metadata.
## Parameters
Phone numbers in 10-digit North American format. Supports single or batch requests.
API key. Only required if not provided via the `x-dncscrub-api-key` HTTP header.
Campaign ID for usage tracking and campaign-specific settings.
Project ID for usage tracking and project-specific settings.
## Response
Whether the API call succeeded.
Array of scrub results, one per phone number.
The phone number checked.
* `C` - Clean (OK to call)
* `D` - Do Not Call
Why the number is blocked (if `resultCode` is `D`). Examples: `National (USA)`, `State (California)`, `Litigator`, `Internal DNC`.
State/province abbreviation (e.g., `CA`, `NY`).
Country code (e.g., `US`, `CA`).
Phone line type: `Wireless`, `Landline`, `VoIP`, or `Unknown`.
`true` if the number is wireless or VoIP.
Timezone code for the phone number's location.
Carrier name when available.
EBR exemption type if one exists (`S`, `I`, or `P`).
Machine-readable error code (when failed).
Human-readable error description (when failed).
## Result Codes
| Code | Meaning | Action |
| ---- | ----------- | ----------------------------------------- |
| `C` | Clean | OK to call (subject to time-of-day rules) |
| `D` | Do Not Call | Do not contact this number |
## Examples
```json theme={null}
{
"phoneNumbers": ["5039367187", "7075276405"]
}
```
```json theme={null}
{
"success": true,
"results": [
{
"phone": "5039367187",
"resultCode": "D",
"reason": "Litigator",
"region": "OR",
"country": "US",
"lineType": "Wireless",
"isWireless": true,
"timezone": "America/Los_Angeles",
"carrier": "Verizon Wireless"
},
{
"phone": "7075276405",
"resultCode": "D",
"reason": "National (USA)",
"region": "CA",
"country": "US",
"lineType": "Landline",
"isWireless": false,
"timezone": "America/Los_Angeles",
"carrier": "AT&T California"
}
]
}
```
```json theme={null}
{
"success": true,
"results": [
{
"phone": "8005551234",
"resultCode": "C",
"reason": "",
"region": "TX",
"country": "US",
"lineType": "Landline",
"isWireless": false,
"timezone": "America/Chicago",
"carrier": "AT&T Texas"
}
]
}
```
## Usage Notes
* Batch multiple numbers in a single request for better performance
* Results include rich metadata (carrier, timezone, line type) useful for routing decisions
* The `isWireless` flag is critical for TCPA compliance—wireless numbers have additional consent requirements
* Use `campaignId` or `projId` to apply campaign-specific DNC settings
# search_compliance_guide Tool
Source: https://docs.dncscrub.com/mcp/applications/search-compliance-guide
Search DNCScrub's Compliance Guide and return ranked, citable regulatory content for AI agents
The `search_compliance_guide` tool performs a retrieval-augmented (RAG) search over DNCScrub's Compliance Guide — the authoritative source for federal and state telemarketing, TCPA, and Do Not Call regulatory guidance — and returns the most relevant content chunks, each with a source name and a link to the Compliance Guide.
Use it to **ground compliance answers in source material** before responding. Do not answer regulatory questions from memory alone; search the guide first to ensure accuracy.
## When to Use
* Answering questions about DNC rules, TCPA requirements, or state-specific calling restrictions
* Looking up call-time windows, holiday restrictions, or registration requirements
* Researching EBR (Established Business Relationship), consent rules, or penalties
* Grounding an AI agent's compliance decisions in DNCScrub's authoritative guidance
For checking whether a specific phone number can legally be called, use [`scrub_phone_numbers`](/mcp/applications/scrub-phones) instead. This tool returns regulatory *guidance*, not a per-number compliance result.
## Parameters
Natural-language question to search the Compliance Guide for, e.g. "What are the call time restrictions in Florida?" Include any state, topic, or channel directly in the query text — the search is semantic.
Maximum number of ranked chunks to return (1-25, default 20).
API key. Only required if not provided via the `x-dncscrub-api-key` HTTP header.
## Response
Whether the search succeeded.
Ranked content chunks, most relevant first.
Relevant excerpt of Compliance Guide content.
Human-readable name of the source document.
Link into the Compliance Guide for citation.
Semantic relevance score (higher is more relevant).
Stable identifier of the chunk within the search index.
Number of chunks returned.
Time the search took, in milliseconds.
Machine-readable error code (when failed): `MISSING_INPUT`, `MISSING_API_KEY`, `INVALID_API_KEY`, or `API_ERROR`.
Human-readable error description (when failed).
## Examples
```json theme={null}
{
"query": "What are the call time restrictions in Florida?",
"topN": 3
}
```
```json theme={null}
{
"success": true,
"results": [
{
"text": "Florida prohibits telephone solicitation calls before 8:00 AM or after 8:00 PM local time...",
"source": "Time Restriction",
"sourceUrl": "https://www.dncscrub.com/compliance-guide/regulatory-guide",
"relevanceScore": 3.42,
"chunkId": "call-times-0"
}
],
"resultCount": 1,
"searchTimeMs": 88
}
```
## Usage Notes
* Access requires a DNCScrub API key with Compliance Guide entitlement, the same authorization used by the other Compliance Guide tools.
* The search is semantic — put any state, topic, or channel directly in the `query` text (e.g. "SMS call-time restrictions in Florida") rather than as separate parameters.
* Always cite the returned `sourceUrl` when relaying guidance to an end user.
* Results are excerpts of authoritative guidance; treat them as the most accurate source and prefer them over model priors.
# tcpa_authority Tool
Source: https://docs.dncscrub.com/mcp/applications/tcpa-authority
Reassignment check using carrier deactivation data
The `tcpa_authority` tool provides phone number reassignment using carrier deactivation data.
## Parameters
Array of objects containing phone numbers and consent dates.
10-digit North American phone number (e.g., `"5039367187"`).
Date consent was given in `YYYYMMDD`, `MM/DD/YYYY`, or `YYYY-MM-DD` format.
API key. Only required if not provided via the `x-dncscrub-api-key` HTTP
header.
## Response
Whether the API call succeeded.
Array of results, one per phone number.
The phone number checked.
* `true` - Number has been reassigned (do not call)
* `false` - Number has not been reassigned (safe to call)
* `null` - Insufficient data to determine
Whether this is a valid, callable phone number.
`true` if valid and not reassigned.
`Wireless`, `VoIP`, `Landline`, `Paging`, or `Unknown`.
Original carrier the number was assigned to.
City based on original number assignment.
State/region code.
Two-letter ISO country code.
Timezone in IANA format (e.g., `America/Los_Angeles`).
UTC offset in minutes.
Machine-readable error code (when failed).
Human-readable error description (when failed).
## Examples
```json theme={null}
{
"phoneNumbers": [
{
"phoneNumber": "5039367187",
"consentDate": "2023-06-15"
}
]
}
```
```json theme={null}
{
"success": true,
"results": [
{
"phone": "5039367187",
"isReassigned": false,
"isValid": true,
"isSafeToCall": true,
"lineType": "Wireless",
"carrier": "Verizon Wireless",
"city": "Portland",
"state": "OR",
"country": "US",
"timezone": "America/Los_Angeles",
"utcOffset": -480
}
]
}
```
## Usage Notes
* Requires Reassigned Authority access on your DNCScrub account
# Use Cases
Source: https://docs.dncscrub.com/mcp/applications/use-cases
How AI applications use the DNCScrub MCP Server for compliance
## Voice AI Pre-Call Screening
Screen phone numbers before your AI agent places calls to avoid contacting known TCPA litigators.
**How it works:**
1. Before initiating an outbound call, the voice AI queries `is_litigator`
2. If `isLitigator: true`, the call is skipped or flagged for review
3. Clean numbers proceed to dialing
**Compatible platforms:** Vapi, Retell, Bland.ai, and other voice AI platforms that support MCP.
***
## AI-Driven Dialer Integration
Integrate compliance checking directly into your dialing workflow to screen contacts in real-time.
**How it works:**
1. Dialer pulls the next batch of numbers to call
2. MCP tool checks all numbers against the litigator database
3. Flagged numbers are removed from the dial queue
4. Clean numbers proceed to agents
**Benefits:**
* No manual list scrubbing required
* Real-time protection as lists are dialed
* Automatic compliance logging via `campaignId`
***
## Agent Assist Tools
Enable agent assist tools to flag compliance risks during live conversations.
**How it works:**
1. Customer provides a callback number during conversation
2. Agent assist AI automatically checks the number
3. If flagged, the agent receives a warning before adding to callback queue
**Benefits:**
* Protects against litigators who call in
* Works with inbound and outbound scenarios
* No disruption to agent workflow
***
## Lead Qualification Bots
Validate phone numbers against the litigator database before launching marketing campaigns.
**How it works:**
1. Lead capture form collects phone number
2. Qualification bot checks number via MCP
3. Flagged leads are routed differently or excluded from calling campaigns
4. Clean leads proceed to sales workflow
**Benefits:**
* Screen leads at point of capture
* Reduce risk before leads enter your dialer
* Integrate with existing lead qualification logic
# verify_phone_owner Tool
Source: https://docs.dncscrub.com/mcp/applications/verify-phone-owner
Verify if a name and/or address matches the phone number owner
The `verify_phone_owner` tool verifies if a name and/or address matches the current owner of a phone number. Use this to confirm the person who gave consent is still the phone owner.
## When to Use
Use this tool when you have contact information (name, address) and want to verify it matches the phone number owner before calling.
## Parameters
10-digit phone number to verify (e.g., `"5039367187"`).
First name to verify (50 characters max).
Last name to verify (50 characters max). Required if no `consentDate` provided.
Address line 1 (30 characters max).
Address line 2 (30 characters max).
City (25 characters max).
2-letter state code.
5-digit zip code.
Date consent was given in `YYYYMMDD` format. Required if no `lastName` provided.
Your internal reference ID (50 characters max). Returned in response.
API key. Only required if not provided via the `x-dncscrub-api-key` HTTP header.
## Response
Whether the API call succeeded.
The phone number verified.
Your reference ID if provided.
Verification result code:
* `N` - Name does not match
* `YA` - Name matches with full address match
* `YPA` - Name matches with partial address match
* `YL` - Name matches and phone is a landline
* `Y` - Name matches (no address match)
* `YP` - Phone ownership unchanged since consent date
* `YX` - Identity verified via high-confidence sources
* `U` - Unknown (no records to verify)
Human-readable explanation of the verification code.
`true` if identity verified (any `Y` code).
Phone type code: `L` (Landline), `W` (Wireless), `V` (VoIP), `N` (Not available), `O` (Other).
Human-readable phone type.
## Examples
```json theme={null}
{
"phone": "5039367187",
"firstName": "John",
"lastName": "Smith",
"address1": "123 Main St",
"city": "Portland",
"state": "OR",
"postalCode": "97201"
}
```
```json theme={null}
{
"success": true,
"phone": "5039367187",
"verificationCode": "YA",
"verificationDescription": "Name matches phone number with full address match",
"isVerified": true,
"phoneType": "W",
"phoneTypeDescription": "Wireless"
}
```
```json theme={null}
{
"success": true,
"phone": "5039367187",
"verificationCode": "N",
"verificationDescription": "Name does not match specified phone number",
"isVerified": false,
"phoneType": "W",
"phoneTypeDescription": "Wireless"
}
```
## Usage Notes
* Provide as much information as possible for best match results
* Either `lastName` or `consentDate` is required
* Address matching improves confidence level
* Use `referenceId` to correlate responses with your internal records
# MCP Server for Developers
Source: https://docs.dncscrub.com/mcp/developers/overview
Connect AI tools to Contact Center Compliance documentation for enhanced development assistance
## Overview
Speed up your development efforts by using our MCP Server for Developers.
Instead of the LLM hallucinating how our APIs work, it can instantly look up the correct way to integrate.
We maintain two MCP Servers: one that executes tools for agentic AI, and
another that provides search across our documentation for developing with our
APIs. This server is the latter.
## Quickstart
### Usage
1. Add the **ccc-docs** MCP server to your MCP-compatible client.
2. Point the client to the URL:
```json theme={null}
{
"mcpServers": {
"ccc-docs": {
"url": "https://docs.dnc.com/mcp"
}
}
}
```
## How it helps you
**Without MCP:**
```
You: "How do I check for litigators using the API?"
AI: generates generic code that might not work with DNCScrub_
```
**With MCP:**
```
You: "How do I check for litigators using the API?"
AI: _searches CCC docs automatically_
AI: _generates code using actual DNCScrub API parameters_
```
When you connect MCP to your AI tools, the AI becomes a Contact Center Compliance expert that can:
* **Generate accurate code** using our latest API endpoints and parameters
* **Answer specific questions** about DNCScrub APIs and authentication
* **Suggest best practices** for TCPA compliance, scrubbing, and litigator checks
* **Find the right documentation** when you're stuck on implementation
This MCP server provides documentation **search only**. It doesn't execute API
calls directly—that keeps your development secure. For real-time compliance
operations, see [MCP for Applications](/mcp/applications/overview).
## Claude
To use the CCC MCP server with Claude:
1. Navigate to the [Connectors](https://claude.ai/settings/connectors) page in Claude settings
2. Select **Add custom connector**
3. Add the following:
* Name: `Contact Center Compliance`
* URL: `https://docs.dnc.com/mcp`
4. Select **Add**
1. When using Claude, select the attachments button (the plus icon)
2. Select the Contact Center Compliance connector
3. Query Claude with CCC documentation as context
## Cursor
To connect the CCC MCP server to Cursor, you can either use the automatic connection or configure it manually:
1. On any CCC documentation page, select the **Copy page** dropdown next to the document header
2. Select **Connect to Cursor**
3. Cursor will automatically open with the CCC MCP server configured
In Cursor's chat, ask "What tools do you have available?" to verify that Cursor has access to CCC documentation search.
1. Use Command + Shift + P (Ctrl + Shift + P on Windows) to open the command palette
2. Search for "Open MCP settings"
3. Select **Open MCP settings** to open the `mcp.json` file
In `mcp.json`, add the CCC configuration:
```json theme={null}
{
"mcpServers": {
"contact-center-compliance": {
"url": "https://docs.dnc.com/mcp"
}
}
}
```
In Cursor's chat, ask "Do you have access to an MCP server?" to verify that Cursor has access to CCC documentation search.
## VS Code
The CCC MCP server can also be configured with VS Code extensions that support MCP:
1. Install an MCP-compatible extension (such as [Continue](https://continue.dev/) or [Cline](https://github.com/cline/cline))
2. Add the CCC server URL: `https://docs.dnc.com/mcp`
3. Test the connection by querying CCC documentation
VS Code MCP support varies by extension. Check your specific extension's
documentation for setup instructions.
## Testing your MCP connection
Once configured, test your MCP connection by asking your AI tool:
````
"What MCP tools do you have available?"
```
You should see the CCC documentation search tool listed. Then try:
```
"Search for information about the Scrub API in the CCC documentation"
```
The AI should be able to search and return relevant Contact Center Compliance documentation.
## Troubleshooting
### Connection issues
**Problem:** MCP server not connecting
**Solution:**
- Verify the URL is exactly: `https://docs.dnc.com/mcp`
- Check your internet connection
- Restart your AI tool after configuration
**Problem:** Search tool not available
**Solution:**
- Confirm the MCP server was added correctly
- Try removing and re-adding the server configuration
- Check the AI tool's MCP support documentation
### Search issues
**Problem:** Search returns no results
**Solution:**
- Try different search terms
- Use more general terms (e.g., "scrub" instead of "scrub multiple phone numbers API")
- Verify the MCP connection is working
## Additional resources
- [Model Context Protocol documentation](https://modelcontextprotocol.io/docs/tutorials/use-remote-mcp-server#connecting-to-a-remote-mcp-server)
- [Mintlify MCP documentation](https://mintlify.com/docs/ai/model-context-protocol)
## Support
If you need assistance with the MCP server or documentation:
- Create a support ticket at [dncscrub.com/help/new](https://dncscrub.com/help/new)
- Email: support@dnc.com
```
````
# Product Lines
Source: https://docs.dncscrub.com/usage
Compliance, Call Deliverability, and Data Enhancement.
We provide **three complementary product lines** designed to help you manage call-list compliance, improve call deliverability, and enrich your customer data for better decision-making.
## 🛡️ Compliance
Protect yourself and your callers from legal and regulatory risk using our suite of compliance tools. These services ensure your outreach stays within federal and state requirements and help prevent costly violations.
Our compliance products include:
* **TCPA Compliance**\
Ensure that your outbound calling processes adhere to Telephone Consumer Protection Act requirements.
* **Do-Not-Call List Checking**\
Automatically scrub numbers against Federal and State Do-Not-Call lists.
* **Reassigned Number Detection**\
Identify numbers that have changed ownership, reducing the risk of calling the wrong consumer.
* **Compliance Guide**\
A comprehensive, always-current reference manual for TCPA, DNC, and calling rules.
* **Calling Time Restrictions**\
Verify whether a number can be legally called at the current time based on state and local regulations.
* **Additional Compliance Scrubs & Validations**\
Support for special-category scrubbing, litigators, wireless identification, exemptions, and more.
## 📞 Call Deliverability
Our Call Deliverability tools help ensure your calls successfully reach customers and avoid unwanted spam labeling. These services allow you to maintain a healthy caller ID reputation and identify patterns that may harm call performance.
Call Deliverability includes:
* **Spam Labeling Reduction**\
Tools and monitoring designed to reduce "Spam Likely" or "Scam Likely" labels on outbound calls.
* **Reputation Monitoring**\
Track how carriers and analytics engines perceive your numbers over time.
* **Bad Number Remediation**\
Identify problematic or flagged numbers and replace or remediate them.
* **Pattern & Volume Analysis**\
Detect calling behaviors that may trigger spam filters and carrier analytics systems.
* **Enhanced Caller ID Presentation**\
Improve trust by ensuring outbound numbers display correctly across networks and devices.
***
## 🔍 Data Enhancement
Our Data Enhancement product line enriches the phone numbers and contact information you already have—improving accuracy, validation, and the overall confidence of your outreach.
Data Enhancement includes:
* **Phone Append**\
Add missing phone numbers to your contact records to increase reachability.
* **Disconnected Number Identification**\
Determine whether a number is active, disconnected, or otherwise invalid.
* **Business vs. Residential Classification**\
Identify whether a number is Business or Residential to apply the correct compliance rules.
* **International Number Intelligence**\
Look up detailed information about an international phone number.\
Returns: country, region, city, timezone, carrier, line type, and geographic coordinates.\
Use this for validating and understanding international numbers outside North America.
* **Name & Address Verification (Reverse Match)**\
Verify whether a name and/or address matches a phone number.\
This helps confirm whether the person who gave consent is still the current number owner.\
Returns verification codes indicating match quality and is particularly useful for TCPA compliance.
* **Consent Validation Support**\
When paired with compliance tools, Data Enhancement helps prove contact legitimacy and maintain compliant outreach records.