> ## 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.

# 10DLC error taxonomy: registry rejections vs. delivery errors

> Tell a TCR registry rejection (30883, 40016, EIN-MISMATCH) from a runtime delivery error (30001, 30007) on a failed message, and route each to the right decoder — the re-submission fix-card endpoint for registry codes, the carrier-error dictionary for delivery codes.

# Two error lanes, one ambiguous code string

A failed 10DLC workflow surfaces one string of code and leaves you to decide
where it came from. Get that wrong and you pay for it twice — a delivery
error filed as a brand re-submission burns a TCR vetting fee you never
needed to pay, and a registry rejection retried as a resend just fails
again.

There are two independent error systems, and they never intersect:

| —                            | Registry rejections                                                                                                                                                                 | Runtime delivery errors                                                                                                                                                                                                                        |
| ---------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **What failed**              | The brand or campaign *registration* — TCR (The Campaign Registry) or a carrier's independent audit refused the filing.                                                             | A single *message send* — the recipient carrier filtered, throttled, or refused delivery of one payload.                                                                                                                                       |
| **What the code looks like** | Numeric 30xxx / 40xxx TCR codes (`30883`, `40016`) or short uppercase slugs (`EIN-MISMATCH`, `BRAND-DCA-FAIL`, `DUPLICATE-BRAND`).                                                  | Numeric 30xxx carrier codes (`30001`, `30007`), SMPP `err` values (`8`, `58`, `299`), WhatsApp 13xxxx codes, or Orbit-internal sentinels (`OPTED_OUT`, `ORBIT_RATE_CAP`).                                                                      |
| **Where it surfaces**        | The `rejectionReason` field on a `FAILED` / `REJECTED` brand or campaign — in the 10DLC wizard, the dashboard notification, or `GET /api/v1/compliance/10dlc/campaigns/:id/status`. | The `error_code` / `error_message` fields on a failed message status row — the message detail panel, message webhooks, and the messaging-insights analytics endpoint.                                                                          |
| **The decoder**              | `POST /api/v1/compliance/10dlc/decode-rejection` — resolves the raw code into a fix card with one corrective step and a resubmit verdict.                                           | `GET /api/v1/analytics/messaging-insights` — resolves each failed-message `error_code` into a human-readable name, description, and failure category, grouped into the carrier-filtering / content / opt-out / rate-limit / network breakdown. |
| **The next action**          | Amend the filing and resubmit (or re-register, when the card locks the record).                                                                                                     | Fix the payload, recipient list, or send rate — the message level, never the registration level.                                                                                                                                               |

Overlap confuses readers because both lanes share a numeric family: the
registry's `30883` (content violation, caught at filing) and the delivery
lane's `30007` (carrier violation, caught at send time) are cousins, not
twins. The check is always the same: **does the code live on a brand or
campaign, or on a message?**

## The lookup matrix — where to paste a code

* **Code arrived on a brand or campaign record, with a `FAILED` /
  `REJECTED` registration status.** It is a registry rejection. Decode it
  with the [rejection decoder](/guides/10dlc-rejections-and-revet#decode-a-raw-rejection-code-into-a-fix-card)
  and follow the fix card — see
  [10DLC rejections, re-vetting, and the post-approval lifecycle](/guides/10dlc-rejections-and-revet)
  for the full amend-and-resubmit loop.
* **Code arrived on a failed message (`GET /messages/:id`, a
  `message.failed` webhook, or the message detail panel).** It is a
  delivery error. The message detail panel already resolves it through the
  carrier-error dictionary; for batch analysis,
  `GET /api/v1/analytics/messaging-insights` groups all failed codes over a
  window by category with resolved names and descriptions (worked example B
  below). There is no single-code API for delivery errors because no
  per-code action is needed beyond what the resolved description states.

One amplifier of the confusion: a failed registration *also* suppresses
sends. While a campaign sits un-approved, its messages fail with a
registration-side reason — that error is delivery-shaped (a message row
with an `error_code`) but the remedy is the registry lane: complete the
registration, and the sends clear with it.

## Worked example A — `40016`, a registry rejection

The 10DLC wizard shows a brand stuck at `REJECTED`:

```bash theme={null}
curl "https://api.orbit.devotel.io/api/v1/compliance/10dlc/brands/B4D2E1" \
  -H "X-API-Key: $ORBIT_API_KEY"
```

```json theme={null}
{
  "data": {
    "brandId": "B4D2E1",
    "status": "REJECTED",
    "rejectionReason": "TCR-40016: EIN verification failed"
  }
}
```

The brand record carries the code, so this is registry lane. Decode it:

```bash theme={null}
curl -X POST "https://api.orbit.devotel.io/api/v1/compliance/10dlc/decode-rejection" \
  -H "X-API-Key: $ORBIT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"code": "TCR-40016", "free_text": "EIN verification failed"}'
```

```json theme={null}
{
  "data": {
    "code": "40016",
    "title": "EIN does not match IRS records",
    "fix": "Verify the EIN format is NN-NNNNNNN. Confirm the legal company name EXACTLY matches the IRS-registered name.",
    "resubmit_allowed": true,
    "category": "identity",
    "field": "brand.ein"
  }
}
```

The card says the EIN or legal name disagrees with IRS records and points
at the brand step of the wizard. Correct the two fields, resubmit the same
brand, pay one fresh vetting fee, and review completes in the usual 1–5
business days.

## Worked example B — `30007`, a delivery error

A campaign is approved and sending, but individual messages fail:

```bash theme={null}
curl "https://api.orbit.devotel.io/api/v1/messages/msg_a1b2c3" \
  -H "X-API-Key: $ORBIT_API_KEY"
```

```json theme={null}
{
  "data": {
    "id": "msg_a1b2c3",
    "status": "failed",
    "error_code": "30007",
    "error_message": "Carrier violation"
  }
}
```

The code lives on a message, so this is delivery lane. `30007` resolves in
the carrier-error dictionary to *Carrier violation — message content or
sender violated carrier policies*, category `carrier_filter`. That
category is non-retryable: resending the unchanged message fails again.
The fix is message-side — clean the content (drop the blocked URL, remove
SHAFT-class wording, shorten the risky phrase) — then resend. The brand
stays untouched and no vetting fee moves.

For a fleet-wide view, the same resolution runs as a histogram:

```bash theme={null}
curl "https://api.orbit.devotel.io/api/v1/analytics/messaging-insights?channel=sms&window=24h" \
  -H "X-API-Key: $ORBIT_API_KEY"
```

Each failed `error_code` comes back with a resolved name, description, and
category (`carrier_filter` / `content` / `opt_out` / `rate_limit` /
`network` / `invalid_destination` / `unknown`), so you can tell in one
glance whether filtering, content, or opt-outs dominate — this endpoint is
owner/admin scoped for that reason.

## Anti-pattern: re-registering a delivery error

When operators see "carrier violation" on failed messages, a common
escalation is to re-file or re-vet the brand. That is the wrong lane:
`30007` (and delivery codes generally) target one message payload, and no
amount of brand-side work rewrites your sample sends. The costs of the
mistake are concrete — TCR charges a new vetting fee per re-submission and
per re-vet, and every resubmission restarts a 1–5 business-day review
during which nothing changes about the failing sends. Route delivery codes
through payload fixes; route registration codes through the decoder. When
a registry code arrives with `resubmit_allowed: false` (e.g.
`BRAND-DCA-FAIL`), even the registry lane says start a fresh registration
rather than amend — the verdict on the fix card is the authority for both
lanes.

## See also

* [10DLC rejections, re-vetting, and the post-approval lifecycle](/guides/10dlc-rejections-and-revet)
  — the full fix-card loop: decode, amend, resubmit, re-vet, throughput tiers
* [Troubleshooting: 10DLC campaign rejected](/troubleshooting/10dlc-campaign-rejection)
  — the static symptom-to-cause matrix the rejection decoder automates
* [Delivery lifecycle](/concepts/delivery-lifecycle) — what each message
  status means, including where `error_code` attaches to a failed row
* [Message status map](/concepts/message-status-map) — the four owners of
  the outbound state machine, for reading webhook statuses
