The problem with trusting the seller’s ping
You’re a buyer. A ping comes in carrying a phone number, a claimed line type, and an opt-in timestamp. You post, get charged, dial the number, and hit a Google Voice VoIP that was ported six months ago from a prepaid carrier. Your dialer flags it as uncontactable. Your compliance team flags it as a potential TCPA exposure. You just paid for garbage.
This happens constantly in ping-post lead-gen, and it happens because most networks validate the phone number exactly once, on the seller side, at form submit, and then trust that result forever. The fix is straightforward: validate at form submit on the seller side, attach the raw API response fields to the ping payload, and re-validate on the buyer side at post time before you accept the lead. Two API calls, two chances to catch a bad number.
Here is how to wire that up.
Seller side: validate at form submit, not at ping dispatch
The seller’s job is to call POST https://api.checkthatphone.com/v1/lookup the moment the user submits the form, before any ping goes out. Not in a background job. Not after the lead is stored. Right then, synchronously, while the user is still on the page.
A minimal request body looks like this:
{
"phone": "6505551234",
"litigatorFilter": true
}
Add landlineSmsLookup: true if your buyers run SMS campaigns. The response fields you want to capture and forward in the ping are:
nanpType: the line type. Values aremobile,landline, ornot-mobile. This is the single most important field for most buyers.dipCarrier: the current serving carrier name.dipCarrierTypeanddipCarrierSubType: carrier category.dipCarrierSubTypeis where you catch values likeVoIPorprepaid, which many buyers reject outright.dipPorted: boolean. A number ported in the last 90 days is a different risk profile than one stable for years.deliverable: whether the number is reachable at all.action: the API’s recommended disposition. Typical values areaccept,review, orreject.litigator: boolean, only present whenlitigatorFilter: trueis set. If this comes backtrue, stop. Do not ping.litigator_typeandlitigator_name: context on why the number hit the litigator list.ipResult: geo-consistency check between the number’s area code and the submitting IP.geoState: the state associated with the number.
Do not just log these and move on. Store the full response against the lead record and include the key fields in your ping payload as structured metadata, not a freeform notes field. Buyers who have written good acceptance rules need to read these values programmatically.
If litigator is true or action is reject, kill the lead at the source. Do not ping it. The litigator scrub add-on exists precisely for this moment. For more on why that matters from a TCPA liability standpoint, see the TCPA litigator scrub use case.
What the ping payload should carry
Different networks use different ping schemas (LeadConduit, proprietary XML, JSON over HTTP). Whatever your format, the phone validation metadata should ride alongside the lead data as first-class fields, not as a blob or an encoded string.
At minimum, buyers need to see:
phone_nanp_type: mobile
phone_carrier: T-Mobile USA
phone_carrier_subtype: postpaid
phone_ported: false
phone_deliverable: true
phone_action: accept
phone_litigator: false
phone_ip_result: match
phone_geo_state: CA
If you ran landlineSmsLookup, include dipMessagingEnabled and dipMessagingProvider too. A buyer running an SMS sequence on a landline number that happens to have a wireless area code is a real scenario, and dipMessagingEnabled: false is a fast rejection signal.
One thing I have seen sellers get wrong: they validate at ping time using a cached result from earlier in the session, or worse, from a prior lead with the same number. Numbers get ported and deactivated. A validation from 20 minutes ago is fine. One from yesterday is not. Call the API fresh at form submit, every time.
Buyer side: re-validate at post, not just read the ping fields
Here is the part most buyers skip. The ping fields tell you what the seller claims. The post is when you commit money. Before you accept, call POST https://api.checkthatphone.com/v1/lookup yourself.
Your post-time request should include the same add-ons you care about:
{
"phone": "6505551234",
"litigatorFilter": true,
"landlineSmsLookup": true
}
Then compare the response against what came in on the ping. Specifically:
- Does
nanpTypematch what the seller sent? A seller claimingmobileon a number that returnslandlineis a red flag. - Does
dipCarrierSubTypeshowVoIPwhen the seller claimed postpaid wireless? Reject. - Is
litigatornowtrue? Could have changed between ping and post, or the seller may not have run the scrub. Either way, reject. - Is
deliverablefalse? The number may have been deactivated in the window between ping and post. It happens. - Does
ipResultshow a mismatch? Not always a reject on its own, but a good signal to combine with other flags.
Your acceptance rules should be explicit. Something like: accept only if nanpType is mobile, dipCarrierSubType is not VoIP, litigator is false, and deliverable is true. Everything else goes to review or auto-reject. Write these as code, not as a checklist in a wiki. The sales lead validation use case has more detail on building these filters.
The latency cost of the buyer-side call is real. CheckThatPhone’s lookup is fast, typically under 200ms, but you need to budget for it in your post acceptance SLA. If your network requires a post response in 500ms, you have enough headroom. If it requires 100ms, you need to think about async post acceptance with a callback.
Handling bulk historical lists
The ping-post flow above covers real-time lead traffic. If you’re a buyer auditing a batch of leads you already received, or a seller cleaning a list before activating a campaign, the single-number /v1/lookup endpoint is the wrong tool. Calling it in a loop at volume is slow, fragile, and will hit rate limits.
For that, use the bulk CSV verification in the CheckThatPhone dashboard: Dashboard, then Bulk CSV. Upload your file, select the add-ons you want (litigator scrub, landline SMS lookup), and download the result file. It deduplicates automatically, runs carrier and line-type validation on every row, and the files are deleted within 24 hours of delivery. This is the right path for contact list hygiene work. See contact list hygiene for more on that workflow.
A practical rejection threshold
If you’re a buyer building your acceptance rules from scratch, here is a reasonable starting point based on what I have seen work in practice:
- Hard reject:
litigator: true,action: reject,deliverable: false,dipCarrierSubType: VoIP - Soft reject / review:
dipPorted: truewithin the last 30 days,ipResult: mismatch,nanpType: not-mobile - Accept:
nanpType: mobile,litigator: false,deliverable: true,action: accept
Adjust based on your vertical. A home services buyer might accept landlines. An insurance SMS campaign cannot.
The full field reference is in the API docs, and the pricing page has current costs for the litigator add-on and landline SMS lookup if you’re modeling unit economics on a per-lead basis.
Stop trusting the ping. Validate it yourself.