readyDocs Open the appOpen the app

Checks on every contact

These routes run checks over every contact on your account at once: a TCPA scrub and a line-type validation, with their quotes. To check numbers one by one instead, use Scrub numbers and Validate numbers.

These run over the contacts on your account. If your key belongs to a team member who sees only their assigned contacts, they cover that member’s contacts and unassigned ones.

#Scrub your contacts

Checks your contacts against the TCPA litigator and do-not-call lists your account screens, and locks the ones that match, the same way a scrub before a send does. Each call checks up to 5,000 contacts that were never scrubbed, oldest first, for about 20 seconds; call it again with after_id set to next_after_id for the next ones. Needs the edit_contacts permission.

What it costs depends on how your scrubbing is billed. While scrubbing is billed per segment you send (the default), this run charges nothing: you pay your scrub rate per segment when you text (see Opt-outs and scrubbing). On per-number billing, each number checked is charged your per-number scrub rate (scrub_rate_usd in Get scrub categories), cached answers included. With rescan: true contacts are checked again and, on per-number billing, charged again. Get a scrub quote prices an import’s scrub, not this run.

Parameters

Idempotency-Keystring · header
Recommended. A repeat with the same key gets the first answer back and runs nothing (Idempotency).
after_idintegerDefault 0
Carry on after this contact: pass next_after_id from the previous answer. Without it a contact that got no answer (see data.errors) comes back first on the next call. Also needed to walk a rescan through all your contacts.
rescanbooleanDefault false
true checks up to 5,000 contacts whether they were scrubbed before or not. "false" and 0 count as false.
Returns
data.total, data.clean, data.landlines, data.litigatorsinteger
Your contacts after the run: all of them, the ones flagged neither landline nor litigator, and each flag.
data.scrubbed_nowinteger
Contacts checked in this call.
data.new_matchesinteger
Of those, how many matched a list you screen and are now blocked.
data.errorsinteger
Contacts that got no answer. They are left as they were. When TCPA scrubbing is off for your account, every contact lands here and data.note says so.
data.notestring
When TCPA scrubbing is off for your account (or every scrub list is off): nothing was checked or charged, and this says how to turn it on. Otherwise only when data.errors is above 0: how many got no answer, and to run this again later without after_id or rescan to check them.
data.moreboolean
true when the call stopped at its time limit before checking every contact it read. Call again with after_id.
data.next_after_idinteger or null
The last contact this call read; pass it as after_id to carry on. null when there was nothing to check.
data.scrubbed_atstring
When the run finished, ISO 8601.
Errors
HTTPCodeWhen
400invalid_fieldrescan isn’t true or false. Nothing was scrubbed or charged.
429scrub_already_runningA scrub is already running for this account. Nothing was charged.
429rate_limitedToo many requests in the last minute.
503tcpa_not_configuredScrubbing isn’t available right now. Nothing was scrubbed or charged.

#Get a scrub quote

What scrubbing count contacts on import costs, the same figure the import charges. On per-number billing the price per contact drops with the contacts you’ve already scrubbed this month (UTC). While scrubbing is billed per segment (the default) the import scrub is free and per_segment is true. Free, and charges nothing. Needs the view_contacts permission.

Parameters

countinteger · queryDefault 0Max 5000000
How many contacts to price.
Returns

The fields are at the top level, not in data.

countinteger
The count priced, after the cap.
freeboolean
true when your account is never billed for scrubbing.
per_segment, per_segment_usdboolean, number | null
Whether scrubbing is billed per segment you send, and your price per segment. per_segment_usd is null when it couldn’t be read or doesn’t apply.
prior_volumeinteger
Contacts already scrubbed this month that set the price. 0 when it doesn’t change the price.
cost_usdnumber
The total, in dollars.
per_contactnumber
The average price per contact. With count 0, the full per-contact price.
bulkboolean
true when part of the count gets a lower volume price.
Errors
HTTPCodeWhen
503account_unavailableYour account couldn’t be read, so no price. Retry.
503scrub_price_unavailableThis month’s scrub volume couldn’t be read. Retry.

#Validate your contacts

Looks up the line type (mobile or landline) of every contact not checked yet, up to 20,000 per call. Contacts already known to be landlines are skipped. It is quote first: without confirm: true it returns the count and price and charges nothing. With it, the check runs in the background. Needs the edit_contacts permission.

While validation is billed per segment you send (the default), this run is free and the quote says free: true. On per-number billing, each number that gets an answer costs per_number, your price per number, cached answers included. Billing-exempt accounts are never charged, and a run never takes your balance below zero. A charge over $50 needs confirmation_text: "VALIDATE".

Parameters

confirmboolean
Send true to run. Anything else, including "true", gets a quote.
quoted_countinteger
Recommended. The count from your quote. If more contacts need checking now, a paid run is refused with confirmation_required so you can see the new price.
confirmation_textstring
VALIDATE, when the quote says requires_typed_confirm: true.
Returns

The fields are at the top level, not in data.

quoteboolean
true on a quote. A quote also carries per_number, free, requires_typed_confirm and typed_confirm_phrase.
count, cost_usdinteger, number
Contacts to check (up to 20,000) and the price in dollars.
cappedboolean
true when more than 20,000 need checking. Call again after this run.
started, job_idboolean, integer | null
On a confirm: whether the check started, and the id of its background job. started: false with count: 0 when there is nothing new to check.
Errors
HTTPCodeWhen
400invalid_fieldA field has the wrong type, or quoted_count is negative.
400confirmation_requiredA paid run over $50 without VALIDATE, or more contacts than quoted_count. The body carries the new count and cost_usd.
429validation_already_runningA landline check is already running for this account, and nothing was charged for this request. Wait for it to finish (GET /bulk-jobs/{job_id}), then try again. The response carries a Retry-After header.
500internal_errorCouldn’t start. Nothing was charged.
503validation_unavailableValidation isn’t available right now. Nothing was charged.
503account_unavailableYour account couldn’t be read, so no price. Retry.

#Check number formats

Checks whether numbers are well formed, the check an import runs with validate_phones: true. Without it an import still takes numbers flagged invalid_length; it always skips the other reasons. No carrier lookup, nothing is saved, and it’s free. Only the first 1,000 numbers are checked. Needs the edit_contacts permission.

Parameters

phonesstring[]Required
The numbers to check.
Returns
data.valid, data.invalidinteger
How many passed and failed.
data.received, data.checked, data.truncatedinteger, integer, boolean
Numbers sent, numbers checked, and whether some weren’t checked.
data.details[]object[]
One per number checked: phone, valid, and normalized (E.164) when valid, or reason and message when not. reason is empty, invalid_length, invalid_area_code, restricted_number or fictional_number.
Errors
HTTPCodeWhen
400phones_requiredNo phones.
400invalid_fieldphones isn’t a list.

#Get a validation quote

What validating count numbers on import costs, priced the way the charge is. free is true when you’d be charged nothing, as while validation is billed per segment (the default). Free, and charges nothing. Needs the view_contacts permission.

Parameters

countinteger · queryDefault 0Max 5000000
How many numbers to price.

Returns count, free, per_segment (true while validation is billed per segment you send, so the import check itself costs nothing), cost_usd and per_contact (the price per answered number on per-number billing) at the top level.

Errors
HTTPCodeWhen
503account_unavailableYour account couldn’t be read, so no price. Retry.

#Estimate landlines

An estimate of how many of your contacts are landlines, what texting them costs per campaign, and what validating every contact would cost. It assumes a typical 7% unless your validated contacts show a higher share. Updated every few minutes. Free, and charges nothing. Needs the view_contacts permission.

Returns
data.total_contactsinteger
Your contacts.
data.est_landlinesinteger
Estimated landlines, never fewer than the ones already known.
data.landline_pct_sourcestring
typical (the 7% figure) or measured (your own share).
data.wasted_per_campaign_usdnumber | null
Estimated landlines times your price per segment. null when your price couldn’t be read.
data.validate_all_cost_usdnumber
What validating every contact costs today. 0 while validation is billed per segment.
data.per_numbernumber
The price per answered number on per-number billing.
data.freeboolean
true when your account is never billed for validation.
Errors
HTTPCodeWhen
500internal_errorYour contacts couldn’t be counted. Retry.
503account_unavailableYour account couldn’t be read. Retry.