# What bad phone data actually costs an outbound team

_2026-09-03 · Boundstone (https://boundstone.io/blog/what-bad-phone-data-costs-outbound)_


Every phone validation vendor prices the same way: per lookup, per credit, per thousand. It is the cheapest number in the equation and the only one anybody puts on a pricing page. The expensive part is downstream, and it never appears on an invoice — which is exactly why it goes unmanaged.

A wrong "valid" does not cost you a credit. It costs you whatever your team does next while believing it.

## The three places bad data bills you

**Rep-minutes on a number that cannot connect.** A disconnected line still consumes a dialer attempt, the seconds a rep waits on it, and the context-switch afterwards. Multiply by the share of your list that has aged and you have a real number — one denominated in your loaded cost per rep-hour, not in credits.

**Routing spend on the wrong channel.** Texting a fixed line spends the message and buys nothing. Calling a number your prospect only reads texts on spends the attempt. Line type is cheap to know before you commit and expensive to discover afterwards.

**A forecast that counts attempts as coverage.** This is the one nobody prices. Rows that were never contactable still appear as "worked" — dialed, no answer, follow up next week. The list looks covered, the pipeline looks proportionate, and the error compounds every cycle because nobody goes back to check whether the number could ever have rung.

## Price it with your own numbers

We are not going to hand you a cost-per-bad-record. Any figure like that is an average from a list that is not yours, and the inputs vary by an order of magnitude between teams.

Use yours instead:

```
bad-row cost ≈ (attempts per row)
             × (minutes per attempt, including follow-up)
             × (loaded cost per rep-minute)
             + (routing spend per attempt)
```

Then multiply by the rows you suspect are unreachable. You do not need that share to be precise — you need it to be honest. Run a sample of a few hundred rows through a validator and count how many come back `valid: false`, then reason from there.

The comparison that matters is that number against the per-row cost of checking first. On Boundstone's Starter tier a credit is about $0.004, so a 10,000-row list is roughly $40 to screen. Whether that is a good trade is arithmetic you can now do, not a claim we need you to accept.

## What validation removes, and what it does not

Removing the provably bad is a real saving and a bounded one. `POST /v1/verify/phone` returns `valid`, `line_type`, `country` and the E.164 form, with `checks.performed` naming `format`, `region`, `line_type` and `allocation`.

What it does not do by default is tell you the line is live. `carrier_lookup`, `ported_status` and `hlr_liveness` come back in `checks.not_performed`, which means a `valid: true` describes shape and range — a number that *could* ring, not one that *does*. A long-disconnected mobile validates perfectly.

That distinction is the entire reason the arrays are in the payload. You are meant to read them and size your expectations to what was actually checked.

## When the ceiling is worth paying past

If your economics turn on liveness rather than hygiene, the live layer exists: send `hlr:true` and Boundstone runs a real HLR network dip at 5 credits on a paid plan. `carrier_lookup`, `ported_status` and `hlr_liveness` move into `checks.performed`, and you get the current carrier, ported status and a `reachable` value that is only ever `true` when the network answered CONNECTED. When the network cannot resolve the number the dip abstains and the credits are refunded — you never pay for a non-answer.

Most teams do not need that on every row. Screening the whole list for shape and routing it by line type, then dipping only the segment where a wrong answer is expensive, is usually the cheaper shape.

## The short version

- **The credit is the cheapest number in the equation.** Rep-minutes, routing spend and forecast distortion are where bad phone data actually bills you.
- **Price it with your own inputs.** Attempts per row, minutes per attempt, loaded cost per rep-minute, routing spend — any published average is somebody else's list.
- **`valid: true` means shape and range, not liveness.** `carrier_lookup`, `ported_status` and `hlr_liveness` are `not_performed` by default, and a disconnected mobile still validates.
- **Dip selectively, not universally.** `hlr:true` costs 5 credits on a paid plan and is refunded when the network cannot answer, so it pays where a wrong answer is expensive.
- **Screening is arithmetic, not faith.** Roughly $0.004 a row on Starter against your own bad-row cost — run the comparison rather than taking ours.
