# 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: Opt-in Lead Scrubbing Workflow ### 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: Opt-in Lead Scrubbing Workflow ### 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**.
  1. In the search box (top right), type DNC.
  2. Select the CCC DNCScrub app by Contact Center Compliance.
The GoHighLevel App Marketplace with DNC entered in the search box and the CCC DNCScrub app by Contact Center Compliance highlighted
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. The CCC DNCScrub app page set to Agency View with the Install button highlighted 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. The Select Sub-Account window with a sub-account checked and the Continue button highlighted On the **Install confirmation** page, review the selected location and the permissions the app requests, then select **Allow & Install** to finish installing DNCScrub. The Install confirmation page showing the selected location and requested permissions with the Allow and Install button highlighted 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. The Connected Successfully page confirming the GoHighLevel account is now connected to DNC Scrub, with a Close This Tab button
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. The agency DNC Scrub Settings page: DNCScrub Settings in the sidebar, the API key and campaign ID fields, the Save and Test buttons, and two green connection indicators at the bottom right 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. The Sub-Accounts tab with the sub-account selector and an App Not Installed message 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 | The DNC Credentials Override fields and the Scrub Behavior toggles for a sub-account ### 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 The Note Appearance color pickers for the scrub link note, clean result, and blocked result ### 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. The DNC Tags settings with the Manage DNC tags toggle and the Blocked, Clean, Wireless, and Invalid status tag checkboxes ### 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. The Bulk Scrub Schedule with Frequency, time, and timezone fields and a plain-English summary of when it runs 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 Onboarding actions (Create Custom Fields, Create Onboarding Notes) and the Offboarding actions (Delete All DNC Notes, Delete Custom Fields) 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. Contact notes panel showing the pinned DNC Scrub note with a scrub link The scrub page lists every phone number on the contact. Select **Scrub All Numbers** to screen them against DNCScrub. Scrub page listing contact phone numbers marked Not scrubbed 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. Scrub results showing clean and do-not-call phone cards with result details 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. Contact note showing a blocked DNC Scrub result with per-phone details ### 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. Add Existing Business Relationship form with EBR type, date of last contact, and reference ## 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 n8n Header Auth credential setup ## 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 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 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 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. *** ## ChaseData 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 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. CCC DNCScrub Settings tab showing API credentials, scrub options with rescrub interval and unit, the daily cleanup job status, audit log retention, notifications, and the installed version 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. CCC DNCScrub Dashboard with activity statistics, quick scrub, and a recent activity table ## 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. Lightning App Builder editing a Lead Record Page, with the CCC DNC Scrub Panel and other CCC components listed under Custom in the components palette Lightning App Builder showing the CCC DNC Scrub panel added to the Lead Record Page canvas ### 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. A Lead record page with the CCC DNC Scrub panel in the sidebar showing an Internal DNC result, line type, scrub time, and a Re-Scrub button 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. Quick Scrub tab with a list of phone numbers and callable versus non-callable results ## 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. Internal DNC Manager tab with phone number input, Check Status, Add to IDNC, and Remove from IDNC buttons, and a status results table ## 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 Management tab with an Add EBR form (phone number, EBR type, date, reference, brand) and a Check EBR panel | 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. Reassigned Number Check tab with a phone number, consent date, and Safe Harbor result ## 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. Bulk Scrub tab showing a new schedule with object, phone fields, frequency, and record-count preview 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. Bulk Scrub schedules list showing a daily Contact schedule with phone field, result field, timing, active status, and last run details **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.