
Integrating DNC Scrubbing Into Your Dialer via API
Uploading a CSV before every campaign works until it doesn't: until you're loading leads all day, pulling them from web forms in real time, or dialing at a volume where a manual step becomes a bottleneck and a source of mistakes. At that point you want Do Not Call scrubbing built into your systems through an API, so no number reaches the dialer without being checked.
This guide shows the integration patterns that work for dialers and CRMs, with working examples against the Carrier Fence API.
Where API scrubbing fits
There are two common patterns, and most teams end up using both:
| Pattern | When to use it | How it works |
|---|---|---|
| Real-time check | Leads arrive one by one from forms, ads or partners | Your CRM checks each number the moment the lead is created, and flags or suppresses it before an agent sees it |
| Batch pre-dial scrub | You load lists into the dialer for a campaign | A scheduled job sends the list in chunks of up to 1,000, then loads only the clean numbers |
Either way, the rule is the same: the dialer should never hold a number that hasn't been scrubbed in the last 31 days. See how often the DNC registry updates.
Step 1: Get an API key
Create a key under Account → API Keys after you sign up. The key is shown once and stored only as a hash, so save it in your secrets manager or environment variables, never in front-end code. Send it as a bearer token:
Authorization: Bearer cf_live_xxxxxxxxxxxxxxxxxxxxxxxxStep 2: Check numbers
Send POST /api/v1/scrub with up to 1,000 numbers and the checks you want (dnc, honeypot or both). Numbers can be in any common format, with dashes, spaces, brackets or a leading 1.
curl -X POST https://carrierfence.com/api/v1/scrub \
-H "Authorization: Bearer $CF_API_KEY" \
-H "Content-Type: application/json" \
-d '{"numbers": ["2125551234", "(415) 555-9876"], "checks": ["dnc", "honeypot"]}'Each result tells you whether the number is valid and whether it's on DNC data, a honeypot or a known litigator. It also includes free extras: the number's original carrier and line type (mobile, landline, VoIP or pager), and a callTime object that says whether a sales call is allowed right now in that number's local time.
{ "number": "4155559876", "valid": true, "dnc": false, "honeypot": false, "litigator": false,
"callTime": { "status": "early", "state": "CA", "nextAllowedLocal": "Tue, Oct 6, 8:00 AM PDT" },
"carrier": "T-Mobile USA", "lineType": "Mobile" }Step 3: Act on the results
A simple suppression rule covers most teams:
- Suppress any number with
dnc,honeypotorlitigatorset to true - Drop numbers with
validset to false; they can't be dialed and weren't charged - Hold numbers whose
callTime.statusisearly,lateorclosed_dayuntilnextAllowed - Use
lineTypeto route mobile numbers only to campaigns with written consent for automated calls - Store the full response with the lead, as dated evidence of the check
A batch example in Node.js
This script splits a list into chunks of 1,000, removes duplicates first (duplicates within a request are charged), and keeps only the numbers that are safe to dial.
const KEY = process.env.CF_API_KEY;
async function scrub(numbers) {
const unique = [...new Set(numbers)];
const clean = [];
for (let i = 0; i < unique.length; i += 1000) {
const res = await fetch("https://carrierfence.com/api/v1/scrub", {
method: "POST",
headers: { Authorization: `Bearer ${KEY}`, "Content-Type": "application/json" },
body: JSON.stringify({ numbers: unique.slice(i, i + 1000), checks: ["dnc", "honeypot"] }),
});
if (res.status === 402) throw new Error("Out of coins: top up before dialing");
if (!res.ok) throw new Error(`Scrub failed: ${res.status}`);
const data = await res.json();
for (const r of data.results) {
if (r.valid && !r.dnc && !r.honeypot && !r.litigator) clean.push(r.number);
}
}
return clean;
}A real-time example in Python
For a CRM webhook that fires when a new lead is created:
import os, requests
def is_safe_to_call(phone):
r = requests.post(
"https://carrierfence.com/api/v1/scrub",
headers={"Authorization": f"Bearer {os.environ['CF_API_KEY']}"},
json={"numbers": [phone], "checks": ["dnc", "honeypot"]},
timeout=30,
)
r.raise_for_status()
res = r.json()["results"][0]
return res["valid"] and not (res["dnc"] or res["honeypot"] or res["litigator"])Handling errors
| Status | Error | What to do |
|---|---|---|
| 400 | invalid_request | The numbers array is missing or empty, or no valid check was requested |
| 400 | too_many_numbers | Split the request into chunks of 1,000 or fewer |
| 401 | unauthorized | The key is missing, mistyped or revoked; create a new one |
| 402 | insufficient_balance | Top up coins; the response says how many more you need |
Nothing is charged when a request fails, because the charge and the lookup happen in one transaction. If a request times out, retry it; don't skip the check. If the scrub can't run, the number shouldn't be dialed.
You can check your balance for free with GET /api/v1/balance, which is useful for an alert before a nightly batch runs.
Integration mistakes to avoid
- Fail open: dialing numbers when the scrub request errors out
- Scrubbing once at import and never again, while the list is dialed for months
- Putting the API key in browser JavaScript, where anyone can copy it
- Scrubbing the main list but not leads that are added later
- Throwing away the results, and with them your proof of the check
What it costs
The API uses the same coin balance as the web uploader. A DNC check is 1 coin, a honeypot check is 1.5 coins, and invalid numbers are free. On the $25 Basic pack, that's $0.00025 per DNC check, about $25 for 100,000 numbers. There's no monthly fee, so a nightly batch and a trickle of real-time checks cost exactly what they use. See what DNC scrubbing should cost.
Frequently asked questions
How many numbers can I check per API request?
Up to 1,000. For larger lists, split them into chunks of 1,000 and send them one after another.
Can I check a single number in real time?
Yes. Send one number in the numbers array. This works well in a CRM webhook that checks each new lead as it arrives.
Am I charged for invalid numbers or failed requests?
No. Numbers that aren't valid 10-digit US numbers come back with valid: false and aren't charged, and a failed request charges nothing.
Does the API tell me if it's a legal time to call?
Yes. Every result includes a free callTime check covering the federal 8 AM to 9 PM window, stricter state hours, and Sunday and holiday bans, along with the next allowed time if it's too early or too late.
Where is the full API reference?
On the API documentation page, which lists every field, error and example.
Get an API key free: new accounts start with 500 coins to test the integration.
This article is general information, not legal advice.