Troubleshooting: SMS to a landline skipped before sending
Your Delivery Log shows an SMS row with statusundelivered, 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
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:
"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:
The Verify gate is covered in the
FAQ entry for 422 VERIFY_LINE_TYPE_BLOCKED.
What the skip means for the row
- Terminal
undelivered, notfailed. The send closed cleanly before dispatch; nothing erred on the send path. The row still fans out on themessage.failedwebhook like every terminal outcome, withstatus: "undelivered"anderror_code: "LINE_TYPE_FILTERED_LANDLINE". - No charge.
is_billableisfalseand 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 theline-typefield) 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
undeliveredrows. - 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
organizationIdfromGET /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-typefield), plus the raw HLRline_typefrom the row’s route trace (GET /api/v1/messages/:id/trace) where it is visible.
See also
- Number Lookup — classify a destination’s line type before you send.
- Troubleshooting: message undelivered or failed — the decoder for every terminal failure status.
- FAQ: Why did my Verify send get refused with 422 VERIFY_LINE_TYPE_BLOCKED? — the Verify-side line-type gate and its org policy slots.
- Message status lifecycle — per-status semantics and the full transition table.