10DLC rejections, re-vetting, and the post-approval lifecycle
The 10DLC registration guide ends at “start sending.” This guide covers what happens next — a rejection with a cryptic code, a vetting score that caps your throughput, or an approved campaign whose daily cap no longer fits your volume. Everything here is a control on your own registrations; carrier and registry decisions remain theirs.Where rejections come from
A rejection is one of two things, and the difference decides everything you do next:- Registry rejections (TCR and the CSPs that proxy it) fire during or
after registration review — the filing itself is refused. These surface
as
FAILED/REJECTEDstatus records with arejectionReasonstring, in three places: the Settings > Compliance > 10DLC wizard, a dashboard notification on the terminal transition, and therejectionReasonfield onGET /api/v1/compliance/10dlc/campaigns/:id/status. - Carrier rejections (AT&T, T-Mobile) can land after TCR approval,
inside the per-carrier
mnoStatusesmap — a direct carrier audit on the brand, or one carrier disagreeing with the CSP-level decision.
DUPLICATE-BRAND
and the lowercase-usecase failure are submission-time signals, not
review-phase outcomes. A rejection the wizard shows immediately after you
submit usually falls in this class.
Two rejections lock the record instead of requesting an amendment —
BRAND-DCA-FAIL and DUPLICATE-BRAND return a fix card with
resubmit_allowed: false, meaning the brand id is burned and the fix is
a fresh registration, not an edit.
Decode a raw rejection code into a fix card
TCR and the CSPs return codes like30883, 40016, and
EIN-MISMATCH with a one-line free-text reason and no per-field fix.
The remediation table on
Troubleshooting: 10DLC campaign rejected
covers the common cases statically; the decoder endpoint applies the same
catalog to any code — including wording and codes the table does not
list.
POST /api/v1/compliance/10dlc/decode-rejection
Pass the raw code, plus the free-text rejectionReason when you have
it — the free text disambiguates codes that map to more than one cause:
200 OK):
fix— the single highest-probability corrective step, in the same register the wizard’s rejection banner uses.resubmit_allowed— the verdict that decides your next call.true: amend the payload and resubmit the same brand or campaign.false: the record is locked; start a fresh registration.category— a stable bucket (eligibility,content,identity,throughput,format,dca,unknown) for grouping in your own UI.field— the wizard step the fix applies to (campaign.sample_message,brand.ein, …), so you can deep-link the operator back to the right form.
TCR-30883, Twilio Error 30883, and
ein_mismatch all resolve to their canonical entries. An unrecognized
code returns an unknown-category card whose fix routes you to
Devotel compliance, so a UI that renders the card never shows an empty
panel.
Worked example: ‘use case mismatch’
A campaign status poll returns:30898 card:
resubmit_allowed: true says amend-and-resubmit. Now resubmit the
corrected campaign against the same brand — the same call as the initial
filing, re-filed like-for-like:
A second worked example: ‘SHAFT sample’
This is the same loop with a content-class card. A reason like"Sample 2 flagged: SHAFT sample" decodes to 30883 — content violation
— with resubmit_allowed: true and field: "campaign.sample_message".
Rewrite the flagged sample to state the declared vertical and drop the
prohibited wording, then re-file the campaign like-for-like. The point of
the loop: one decoder call, one corrected submission, and none of it
depends on which wording TCR happened to return.
Re-vet vs. re-submit
Rejected content fixes mean re-submission. A low vetting score is a different blocker — no amount of correction to a campaign payload repairs it, and it caps every campaign on the brand, not just the one under review. The score decides the limit, so the remedy is a re-vet, not a resubmission.POST /api/v1/compliance/10dlc/brands/:id/revet
200 OK):
provider names which registrar carries the brand; status is the
refreshed brand status once the re-vet kicks off. Before you re-vet,
complete the brand record — EIN, legal name matched to IRS records,
website, support email on your own domain — the re-vet re-scores the same
information, and an unchanged record returns an unchanged score.
The registrar rate-limits re-vets (once immediately after registration,
then once per roughly three months), so a rate-limited call returns 422
with the registrar’s wait-until text — read it, do not retry in a loop.
Throughput planning: what the score grants
Two endpoints turn the vetting score into the limits you operate under.GET /api/v1/compliance/10dlc/brands/:id/vetting returns the raw
result:
vettingScore: null means the EVP is still processing — render
“Pending”, not 0.
GET /api/v1/compliance/10dlc/brands/:id/throughput derives the
carrier-assigned limits from that score:
200 OK):
att.class— AT&T assigns a per-campaign throughput class, D→C→B→A (15 → 75 → 240 → 600 messages per minute), at trust-score floors 0/25/50/75.tmobile.tier— T-Mobile assigns a per-brand daily-cap tier (2k / 10k / 40k / 200k / unlimited) that covers every campaign and number on the brand.entity_type(optional query param) — sole-proprietor brands are capped at the 2k tier and Class D regardless of score; pass the registered entity type so the derivation sees the special case.sent_today(optional query param) — message parts already sent in the current rolling 24h window. When you pass it,consumptionreports headroom before the silent-filtering zone:okbelow 80% of the cap,warningat 80%,criticalat 95%,exceededat 100%.
consumption is null until you supply
sent_today.
Re-vet, or accept the tier?
Use thewarning / critical thresholds as the signal. When your
foreground volume consistently lands in the warning band, plan a re-vet —
it is rate-limited, so burn it only on a real trajectory change. When the
ceiling is the daily cap rather than the class, the constraint is
per-brand: assigning more numbers to the campaign does not raise it, and
a SOLE_PROPRIETOR upgrade to a full brand record does — that is an
entity-type change, not a re-vet.
Re-submission, re-vet: what each costs
TCR charges a new vetting fee per re-submission and per re-vet (typically a few USD), and carriers treat every re-submission as a fresh review — independent timing from your previous attempts.See also
- 10DLC registration guide — brand → campaign → approval, use-case codes, and the throughput tier table
- Troubleshooting: 10DLC campaign rejected — the static symptom → cause → fix matrix this guide’s decoder applies
- Pre-submit linter — run the corrected payload through preflight before resubmitting