10DLC preflight: score, verdict, and finding codes
A 10DLC brand + campaign submission goes through TCR vetting, and most first-time rejections come from a small set of deterministic content and completeness patterns — missing opt-out wording, public link shorteners, placeholder sample messages, an opt-in description that is too thin. Every rejected resubmission costs a new vetting fee and restarts the review clock. The preflight engine scores your submission against that known rejection-pattern catalog before you pay the fee, and returns a score, a verdict, and per-field findings with the exact offending fragment and a concrete rewrite suggestion. This page is the reference for that engine: the three endpoint surfaces that run it, the request/response contract, every rule code and remediation, rate limits, and a worked CI gate that blocks a submission until the verdict ispass. For the end-to-end registration walkthrough
(registering the brand, creating the campaign, tracking vetting), see
Register for 10DLC.
Three surfaces, one engine family
Three endpoints run preflight engines. The two 10DLC surfaces both run the same engine (tcr-preflight/v1); the short-code surface runs the
parallel engine (shortcode-preflight/v1) against a program-brief
payload shape. All routes below are rooted at
https://api.orbit.devotel.io/api/v1:
Pick the surface by what you want linted, not by the rule set — the
two 10DLC surfaces emit identical finding structures. The ad-hoc
endpoint needs no persisted state; the wizard endpoint reads the draft
saved through the wizard flow. The short-code engine is a sibling
surface: same
score/verdict/findings[] contract, different rule
catalog and payload shape. All three endpoints are idempotent reads —
nothing is sent to TCR or a carrier, and nothing is created or stored.
Request and response contract
Ad-hoc 10DLC payload
POST /compliance/10dlc/preflight accepts brand and campaign objects
shaped like the submission you intend to send:
brand_vetting_score— your current TCR vetting score (0–100) when you already hold one. It drives the throughput-tier rule (R-CAMP-THROUGHPUT-TIER); omit it or passnullfor an un-vetted brand and the linter assumes the Low Volume Standard baseline tier.campaign.expected_msg_per_day_per_number— your declared forecast volume per number per day, used by the same tier rule.
Wizard payload
POST /compliance/10dlc/wizard/preflight takes no brand or campaign
body — it loads the draft you saved through
PATCH /compliance/10dlc/wizard/draft and lints that. Both body fields
are optional:
expected_msg_per_day_per_number— forecast volume from your volume-planning widget, applied on top of the persisted draft.brand_vetting_score— current score, same semantics as the ad-hoc endpoint.
Response shape
Both 10DLC endpoints return the same envelope:score— 0–100; 100 means no known pattern matched. Eacherrorfinding deducts 25 points, eachwarn8, eachinfo2.verdict—blockwhen anyerror-severity finding is present,warnwhen anywarnfinding is present or the score lands below 75, otherwisepass.findings[]— one entry per rule hit.fieldis the dot-path of the offending field (e.g.campaign.sample_message[2]);matchquotes the exact fragment when one exists;suggestionis the rewrite that resolves the finding.engine— the rule-engine version, stamped on every response so you can correlate score changes when the catalog evolves.
pass verdict means “no known
rejection pattern matched.” Your submission still goes through the
normal TCR and per-carrier review, which includes human vetting. Treat
the preflight as the deterministic first pass that removes the
rejectable-by-pattern defects; the carrier review that follows is the
authoritative pass.
Failure catalogue
Each finding carries a stableruleId. The table covers every code the
tcr-preflight/v1 engine emits, with the remediation for each.
The scoring weights and verdict thresholds above (
error −25, warn
−8, info −2; warn verdict below 75) are fixed for
tcr-preflight/v1. If the catalog or weights change, the engine label
rolls to a new version stamp, which lets you correlate a score change to
an engine release rather than to your own payload edit.
Rate limits and correlation
- Both 10DLC preflight endpoints are rate-limited to 30 requests per minute per organization. The wizard surface additionally enforces an admin role.
- A
429means you exceeded the per-minute budget; back off and retry after the window closes. There is no monthly quota. - Every response carries
meta.request_id. Log that ID in the job that calls the linter — the linter is deterministic for a given payload and catalog version, so pairing the request ID with the result lets you reconstruct any deviation between two runs of the same payload.
Worked example: pre-submit CI gate
Run the preflight as a gate in the pipeline that prepares a 10DLC submission, and fail the job on any verdict other thanpass. The
linter is a pure function of the payload and engine version, so a green
run means there is no known rejection pattern left to match at this
engine version.
warn as a gate failure. A warn verdict means a finding
carriers frequently reject on is present (missing STOP wording, too few
samples, throughput-tier mismatch often not fatal but worth fixing).
Failing only on block lets those through. Log verdict + score on
every run; when a submission is rejected despite a pass, diff the
stored payload against what TCR saw — the engine stamp tells you
whether the rule catalog moved between the two runs.
See also:
- Register for 10DLC — the end-to-end walkthrough: register the brand, create the campaign, track vetting.
- 10DLC rejections and re-vet — decode a rejection code and correct the filing.
- Short-code preflight — the sibling engine and rule catalog for short-code program briefs.
- 10DLC brand and campaign profiles — how the brand and campaign objects the linter scores map to the TCR registration lifecycle.