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

# Scrub Multiple Numbers

> Scrub multiple phone numbers in a single API call

Submit multiple phone numbers in a single request for efficient batch processing.

<Note>
  To add or refresh EBR records in the same call as a scrub, use
  [Scrub + Add EBR](/api-reference/scrub/scrub-ebr).
</Note>

<Warning>
  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.
</Warning>

## Request

### Headers

<ParamField header="loginId" type="string" required>
  Your API Key
</ParamField>

### Request Body

<ParamField body="phoneList" type="string" required>
  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}`;
  the identifier may be empty, `||{postalCode}` (e.g.,
  `5039367187|abc-10232|10001,7075276405||97205`). See [Postal Code Time
  Zones](/api-reference/scrub/scrub-single#postal-code-time-zones).
</ParamField>

<ParamField body="version" type="string" required default="8">
  API version. Use `8` (latest). Version `6` adds `EBRExpiresOn`; version `7`
  adds `WirelessPortDate` and `VoIPDate`; version `8` adds `PostalCode`, `TZSource`,
  `IsCallAllowedNonATDS`, `IsCallAllowedATDS` and `IsCallAllowedAI`.
</ParamField>

<ParamField body="output" type="string" default="json">
  Response format: `json` or `csv`
</ParamField>

<ParamField body="projId" type="string">
  Optional. Project ID
</ParamField>

<ParamField body="campaignId" type="string">
  Optional. Campaign ID
</ParamField>

## Example Request

<CodeGroup>
  ```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();
  }
  ```
</CodeGroup>

<ResponseExample>
  ```json Response theme={null}
  {
    "version": 8,
    "results": [
      {
        "Phone": "5039367187",
        "ResultCode": "D",
        "Reserved": null,
        "Reason": "Litigator",
        "RegionAbbrev": "OR",
        "Country": "US",
        "Locale": "Portland",
        "CarrierInfo": "5820;WIRELESS;\"Verizon Wireless:Verizon Wireless\"",
        "NewReassignedAreaCode": null,
        "TZCode": 4,
        "CallingWindow": null,
        "UTCOffset": -420,
        "DoNotCallToday": false,
        "CallingTimeRestrictions": 4,
        "EBRType": null,
        "IsWirelessOrVoIP": true,
        "LineType": "Wireless",
        "EBRExpiresOn": null,
        "WirelessPortDate": "2019-03-14",
        "VoIPDate": null,
        "PostalCode": null,
        "TZSource": "areaCode",
        "IsCallAllowedNonATDS": false,
        "IsCallAllowedATDS": false,
        "IsCallAllowedAI": false
      },
      {
        "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
      }
    ]
  }
  ```
</ResponseExample>

## Response Fields

<ResponseField name="Phone" type="string">
  The phone number that was scrubbed
</ResponseField>

<ResponseField name="ResultCode" type="string">
  The scrub result code (see [Result
  Codes](/api-reference/scrub/overview#result-codes))
</ResponseField>

<ResponseField name="Reserved" type="string | null">
  Your unique identifier if you passed one (`PHONE|ID`), otherwise `null`
</ResponseField>

<ResponseField name="Reason" type="string">
  Explanation of why the number is flagged
</ResponseField>

<ResponseField name="RegionAbbrev" type="string">
  State/region abbreviation (e.g., "CA")
</ResponseField>

<ResponseField name="Country" type="string">
  Country code (e.g., "US")
</ResponseField>

<ResponseField name="Locale" type="string">
  City or locality
</ResponseField>

<ResponseField name="CarrierInfo" type="string">
  Carrier information in format: `ID;TYPE;"Name"`
</ResponseField>

<ResponseField name="TZCode" type="integer">
  Timezone code
</ResponseField>

<ResponseField name="UTCOffset" type="integer">
  UTC offset in minutes for the destination, adjusted for DST (e.g. `-240`)
</ResponseField>

<ResponseField name="EBRType" type="string | null">
  Type of EBR applied: `S` (Sale), `I` (Inquiry), or `P` (Permission). `null` if no EBR
</ResponseField>

<ResponseField name="IsWirelessOrVoIP" type="boolean">
  `true` if wireless or VoIP
</ResponseField>

<ResponseField name="LineType" type="string">
  Line type: `Wireless`, `VoIP`, or `AllOther`
</ResponseField>

<ResponseField name="EBRExpiresOn" type="string | null">
  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)
</ResponseField>

<ResponseField name="WirelessPortDate" type="string | null">
  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
</ResponseField>

<ResponseField name="VoIPDate" type="string | null">
  Date the number was identified as VoIP, `YYYY-MM-DD`. `null` if not VoIP. Requires
  `version=7` or higher
</ResponseField>

<ResponseField name="PostalCode" type="string | null">
  Normalized postal code used for the time zone calculation (`10001`, `M5V`).
  `null` if none was supplied. Requires `version=8` or higher
</ResponseField>

<ResponseField name="TZSource" type="string">
  `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
</ResponseField>

<ResponseField name="IsCallAllowedNonATDS" type="boolean">
  `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
</ResponseField>

<ResponseField name="IsCallAllowedATDS" type="boolean">
  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
</ResponseField>

<ResponseField name="IsCallAllowedAI" type="boolean">
  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
</ResponseField>

## 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);

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

<AccordionGroup>
  <Accordion title="Batch Size">
    While the API can handle large batches, consider breaking very large lists
    into batches of 1,000-5,000 numbers for optimal performance.
  </Accordion>

  <Accordion title="Output Format">
    Use `output=csv` for large batches. CSV parsing is more efficient for
    high-volume processing.
  </Accordion>

  <Accordion title="Error Handling">
    Operations are atomic. If one phone number is invalid, the entire batch
    fails. Validate phone numbers before sending.
  </Accordion>
</AccordionGroup>


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