Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.tracklysms.com/llms.txt

Use this file to discover all available pages before exploring further.

This guide shows the end-to-end flow most accounts use to maximize SMS deliverability:
  1. Run phone validation on a list (LRN + internal DNC)
  2. Build an audience that excludes landlines, VoIP, and unreachable numbers
  3. Send to the cleaned audience

Why this matters

Carrier networks reject roughly 20–30% of SMS sent to landline / VoIP numbers, and the FTC DNC + state DNC + carrier DNC lists evolve daily. Validating a list once and then segmenting on the result gives you a reusable, deliverable subset — and the cache makes re-validating that same list essentially free forever.

Step 1: validate the list

Two ways to trigger validation depending on whether you’re using the platform UI or the public API.

From the Contact Lookup UI

  1. Open Contact Lookup → select your list from the dropdown.
  2. Click Run phone validation.
  3. The modal shows a count + cost estimate (e.g., “500 of 9,300 contacts are unvalidated. Estimated cost: $1.50”) and lets you confirm.
  4. Validation runs as a background job. The progress bar updates every few seconds; you can close the dialog and the job continues server-side.
  5. When the job completes, the per-contact badges in the list flip to Validated ✓ / Validation failed.
This batches up to 500 unvalidated contacts per click. For larger lists, click again after the first batch finishes — already-validated contacts are free (cached: true), so the cost only ever covers the new portion.
Updated 2026-04-27: the per-click 500-contact cap was removed. A single click now validates every unvalidated contact in the list. Validation runs as one background job per account — re-clicking while a job is in flight returns “a validation job is already running” instead of starting a duplicate. The caching behavior above is unchanged: re-validating a list still costs only the new portion.

From the public API

For programmatic cleans (e.g., before importing a fresh data drop), use POST /v1/phone/validate/batch:
curl -X POST https://api.tracklysms.com/api/v1/phone/validate/batch \
  -H "X-Api-Key: $TRACKLY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "phones": [
      "+14155551234",
      "415-555-9876",
      "(212) 555-0100"
    ]
  }'
Each response entry tells you exactly what the number is:
{
  "phone": "+14155551234",
  "valid": true,
  "line_type": "mobile",
  "carrier": "T-Mobile USA",
  "ported": true,
  "country": "US",
  "disposition": "ok",
  "cost": 0.003,
  "cached": false
}
Phone numbers are normalized server-side before any provider call:
You sendNormalized
4155551234+14155551234
(415) 555-1234+14155551234
415-555-1234+14155551234
+1 415 555 1234+14155551234
14155551234+14155551234
So you can pass numbers in whatever format you have them — the normalize_e164 helper handles the conversion. Our LRN provider only accepts strict E.164, so anything that can’t be normalized is rejected at the validation step (HTTP 400, before any provider call).

Step 2: build an audience for cleaned, deliverable contacts

Once contacts are validated, the line_type, carrier, and is_valid fields populate on each contact. You can filter on them directly in Audiences.

Example: US/CA mobile-only, no DNC, no VoIP

In the audience builder:
FieldOperatorValue
validation_statusequalsvalidated_valid
line_typeequalsmobile
countryinUS, CA
on_dncequalsfalse
This produces an audience of only fully-validated, mobile-line, US/Canada numbers that aren’t on the federal or per-account DNC list. Every contact in this audience is one your carrier will accept and the recipient can actually receive. The same audience expressed via the Audiences API:
{
  "name": "US/CA Mobile — DNC clean",
  "rules": {
    "all": [
      { "field": "validation_status", "op": "eq", "value": "validated_valid" },
      { "field": "line_type", "op": "eq", "value": "mobile" },
      { "field": "country", "op": "in", "value": ["US", "CA"] },
      { "field": "on_dnc", "op": "eq", "value": false }
    ]
  }
}

Variations worth knowing

  • Drop landlines but keep VoIP (some VoIP can SMS): line_type in [mobile, voip]
  • Carrier-specific A/B: split a campaign by carrier eq "Verizon Wireless" vs carrier eq "AT&T Mobility" to compare delivery rate / clicks across carriers
  • Re-clean cadence: the validation cache is permanent per (account, phone). To force a re-validation (e.g., for numbers you suspect have ported), pass force=true to the API or click Re-validate selected in the UI

Step 3: send to the audience

Schedule a campaign against the audience as you normally would. Because the audience is dynamic, every new validated contact that matches the rules automatically gets included on the next send — no need to re-run the audience query manually.

How the cost adds up over time

Validation pricing is $0.003 per non-cached lookup, with a permanent per-account cache (see Phone Validation: Caching Behavior). A typical cycle:
PassCost
Day 0: validate a fresh 100k list$300 (100,000 × $0.003)
Day 30: re-clean the same list (no new contacts)$0 (all cache hits)
Day 30: re-clean with 5,000 new opt-ins added$15 (5,000 × $0.003)
Day 365: re-clean again$0 — older numbers still cached
In practice, re-validation costs trend toward “new contacts since last pass × $0.003” rather than total list size.

Common pitfalls

  • Trying to send before validation finishes. If you queue a send on a partially-validated list, the as-yet-unvalidated contacts will be sent to under their pre-validation flags (which means landlines/VoIP are NOT excluded). Wait for the badges to flip before scheduling.
  • Forgetting country in the audience. Without it, the rule still includes UK/AU mobiles where applicable — fine if intentional, but a surprise if you assumed US/CA.
  • Caching surprises after carrier porting. LRN data is rare-change, but a number ported in the last week may still show its old carrier in our cache. Pass force=true if exact current-carrier accuracy matters for your use case.