> ## Documentation Index
> Fetch the complete documentation index at: https://docs.orbit.devotel.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Troubleshooting: SMS to a landline skipped before sending

> A Delivery Log row reads undelivered with error code LINE_TYPE_FILTERED_LANDLINE and no charge: the opt-in pre-send line-type filter classified the destination as a fixed line and skipped the send. How the filter decides, how to enable or stop it, how the 24-hour lookup cache treats ported numbers, and when a resend makes sense.

# Troubleshooting: SMS to a landline skipped before sending

Your Delivery Log shows an SMS row with status `undelivered`, the error
code `LINE_TYPE_FILTERED_LANDLINE`, and no charge: the row carries
`is_billable: false` and your wallet was not deducted. In the dashboard
the row's error card reads **Landline number** with "The destination is
a landline and can't receive SMS."

This is not a carrier failure. Orbit's pre-send line-type filter
classified the destination as a fixed line before dispatch and skipped
the send, so you never pay for an SMS a landline physically cannot
receive.

## What the filter is

When the filter is enabled for a send (below), Orbit classifies the
destination's line type with an HLR-backed Number Lookup verdict before
the message is handed to a provider. If the verdict is a fixed-line
class (`fixed`, `landline`, `fixed_line`, or `fixed_voip`, depending on
how the HLR vendor labels the line), the send is skipped and the row is
written as a terminal `undelivered` with
`LINE_TYPE_FILTERED_LANDLINE`. Mobile numbers, unclassifiable numbers,
and plain VoIP numbers pass through: many VoIP DIDs are SMS-capable, so
VoIP is deliberately allowed.

The check applies to SMS only. It mirrors the landline pre-skip
protection Twilio and Sinch apply on their messaging paths, and it reuses
the same Number Lookup data that [Number Lookup](https://docs.orbit.devotel.io/numbers/lookup.md)
exposes to you. Verdicts are cached for 24 hours, so repeat sends to the
same number do not pay for another HLR query.

## Enabling and disabling it

The filter is **off by default**. You opt in per send by setting
`"line_type_filter": "true"` in the send request's `metadata`:

```json theme={null}
POST /api/v1/messages
{
  "channel": "sms",
  "from": "+15550001111",
  "to": "+15550002222",
  "text": "Your appointment is confirmed for Friday 10:00.",
  "metadata": {
    "line_type_filter": "true"
  }
}
```

To stop filtering, omit the flag (or send any value other than `"true"`)
and the send behaves as if the filter were not there.

Do not look for an org-wide SMS toggle. The line-type policy slots under
**Settings → Security** (`landline_sms`, `voip_sms`, and their voice
siblings) govern **Verify sends only**, and their refusal shape is a
`422 VERIFY_LINE_TYPE_BLOCKED` at send time, not this code. The two
gates are separate:

| | Verify line-type policy | SMS line-type filter |
| - | - | - |
| Applies to | Verify / OTP sends | SMS sends that carry the metadata flag |
| Control | Org policy slots under Settings → Security | Per-send `metadata["line_type_filter"]` |
| Refusal shape | `422 VERIFY_LINE_TYPE_BLOCKED` at send time | Terminal `undelivered` row, `LINE_TYPE_FILTERED_LANDLINE`, not billed |
| Default | `landline_sms: warn`, everything else off | Off unless a send opts in |

The Verify gate is covered in the
[FAQ entry for 422 VERIFY\_LINE\_TYPE\_BLOCKED](https://docs.orbit.devotel.io/reference/faq.md).

## What the skip means for the row

* **Terminal `undelivered`, not `failed`.** The send closed cleanly
  before dispatch; nothing erred on the send path. The row still fans
  out on the `message.failed` webhook like every terminal outcome, with
  `status: "undelivered"` and
  `error_code: "LINE_TYPE_FILTERED_LANDLINE"`.
* **No charge.** `is_billable` is `false` and no wallet deduction
  happens. That is the point of the filter: the classic landline-SMS
  failure mode is a send that bills you and then bounces at the carrier
  or dies silently.
* **Retrying is not useful.** Resending the same row runs the same
  classification and gets the same verdict back, served from cache.
  Resend only after you have confirmed the line type and concluded the
  destination is SMS-capable after all.

## When the filter lets a landline through, and when it holds a ported number

The filter is best-effort by design:

* **Lookup outages fail open.** If the HLR lookup errors or times out,
  the send proceeds as if the filter were not there. An HLR outage never
  blocks your SMS pipeline; you simply lose the billing protection for
  those sends.
* **The 24-hour cache lags ports.** If a number was ported between
  mobile and fixed, the cached verdict keeps applying until its 24-hour
  TTL expires. A recently ported landline can therefore stay skipped for
  up to a day after the port. The practical remedy is to wait out the
  cache window, and to confirm the current verdict with
  `POST /api/v1/numbers/lookup` (request the `line-type` field) before
  you resend. There is no customer-facing cache-invalidate switch; the
  cache expires on its own.

## What not to try

* **Do not retry the same rows at scale expecting a different verdict.**
  The classification is deterministic per number and cached for 24
  hours; a bulk replay produces a bulk pile of identical `undelivered`
  rows.
* **Do not set the flag expecting it to block mobile or VoIP
  destinations.** The filter only skips the fixed-line classes listed
  above; mobile, unknown, and VoIP pass. To stop sending to specific
  numbers, use your opt-out or suppression list instead.
* **Do not trace the row with the carrier as a reject.** Nothing was
  submitted; the carrier never saw the message.

## Escalation checklist

Open a support ticket when a destination you have confirmed as
SMS-capable keeps getting skipped, and include:

* Your **tenant ID** (Settings → Organization in the dashboard, or
  `organizationId` from `GET /api/v1/me`).
* One **message ID** (`msg_…`) of a representative skipped row.
* The **line-type verdict** for that destination from
  `POST /api/v1/numbers/lookup` (`line-type` field), plus the raw HLR
  `line_type` from the row's route trace
  (`GET /api/v1/messages/:id/trace`) where it is visible.

## See also

* [Number Lookup](https://docs.orbit.devotel.io/numbers/lookup.md) — classify a destination's line type
  before you send.
* [Troubleshooting: message undelivered or failed](https://docs.orbit.devotel.io/troubleshooting/message-undelivered-failed.md) —
  the decoder for every terminal failure status.
* [FAQ: Why did my Verify send get refused with 422 VERIFY\_LINE\_TYPE\_BLOCKED?](https://docs.orbit.devotel.io/reference/faq.md) —
  the Verify-side line-type gate and its org policy slots.
* [Message status lifecycle](https://docs.orbit.devotel.io/api-reference/messages-status-lifecycle.md) —
  per-status semantics and the full transition table.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.