Loquent · Twilio Config Roadmap Mode B · updated 2026-06-12 · decisions locked · issues filed
Decision / Roadmap

Twilio configuration — what's next

The regulatory-bundle work closed the international purchase gap. This doc maps the full "buy a number → send & receive messages" journey, what still blocks it, and what to build next — ordered by the value it brings a small-business org.

Goal · a user can buy a number and message customers without leaving Loquent Audience · non-technical business owners, mostly US Basis · codebase audit of mods/twilio, mods/phone, mods/messaging, settings
↳ Updated 2026-06-12: all four open questions are now resolved (§6) — toll-free ships first, setup is assistant-driven with no manual config UI for now, BYO orgs are in scope, fees are handled per tier. GitHub issues are filed under spike #1525 in the Twilio Configuration milestone (§7).

TL;DR

01

Purchase is now solid: search → address → regulatory bundle → buy → voice webhook auto-configured. International compliance is covered.

02

The #1 gap is US A2P 10DLC. Regulatory bundles do not register US messaging — unregistered US local numbers get their SMS blocked by Twilio & carriers. For a US org, messaging effectively doesn't work yet.

03

Toll-free verification is the simpler sibling path — one form, no campaign fees — and is also missing.

04

Small compliance + UX gaps compound: no STOP/HELP auto-reply, failed messages show a generic "Failed", numbers can't be released.

05

Locked order (Q1): toll-free verification → STOP/HELP responder → 10DLC → error surfacing, then number lifecycle, porting, caller-ID branding. Setup is assistant-driven (Q2).

01What we have today

The journey a user can already complete, and where each piece lives.

Signup ──▶ Twilio subaccount auto-created (or BYO connect) │ organization_twilio_settings · event sinks for SMS/call events ▼ Buy number ─▶ search (country/type/area code/pattern) │ address required? ──▶ Addresses tab (CRUD on Twilio) │ bundle required? ──▶ Bundle wizard (NEW, PR #1469) │ scope → identity → documents → submit │ webhook status → notification on approve/reject ▼ Configure ──▶ friendly name · voice agent · routing mode (ai_first / humans_first / ai_only) · text agent + auto-reply · member phone assignments · org-level recording toggle ▼ Send/receive SMS + MMS via Messages API · delivery status via Event Streams · STOP keyword detected → opt-out recorded → sends blocked pre-dispatch
CapabilityStatusWhere
Per-org subaccount or BYO credentialssolidorganization_twilio_settings, create_twilio_subaccount_util, /api/twilio/connect
Number search & purchase (country, type, area code, pattern)solidbuy_phone_component, buy_phone_number_api
Regulatory addresses (CRUD)solidphone_addresses_section_component, addresses utils
Regulatory bundles — wizard, docs, submit, status webhook, attach at purchasesolid · newregulatory_bundle_service, phone_bundles_section_component, /twilio/bundle-status
Voice webhook auto-config at purchasesolidset_phone_number_twiml_util, voice_webhook_active
Per-number config: voice/text agent, routing mode, auto-reply, member assignmentsolidphone_details_component, member_phone_picker_component
SMS + MMS send, delivery status, inbound via Event Streamssolidsend_message_api, twilio_events_api
STOP/UNSUBSCRIBE detection → opt-out record → pre-dispatch blockpartialdetect_opt_out_keyword, is_channel_opted_out_service — no confirmation auto-reply
US A2P 10DLC (brand, campaign, messaging service)missing
Toll-free verificationmissing
Number release / porting / CNAMmissing

02What the bundle work covers — and what it doesn't

Twilio has two unrelated compliance systems that are easy to conflate. We built one of them.

✓ Built — Regulatory bundles (Numbers v2)

Identity proof required to purchase numbers in regulated countries (DE, FR, AU, GB mobile, …). Gate is at buy time: no approved bundle → Twilio refuses the purchase (errors 21649/21650). Once bought, the number works.

✗ Not built — A2P 10DLC (TrustHub)

Carrier registration required to send SMS from US local numbers. Gate is at message time: US carriers + Twilio block or heavily filter traffic from unregistered numbers. Buying the number succeeds; messaging silently fails.

!

For a US org, the happy path is currently broken at the last step

A US business buys a local number in Loquent today, assigns a text agent, sends a campaign — and messages fail with error 30034 (unregistered 10DLC) or get carrier-filtered (30007). Since mid-2023 Twilio blocks unregistered US-bound long-code traffic outright. Everything upstream of this works; the send itself doesn't. This is the single highest-value gap.

The 10DLC chain has four pieces, all per-org, all absent from the codebase: a TrustHub Secondary Customer Profile (business identity), an A2P Brand (registered against the profile; sole-proprietor or standard), a Messaging Service (sender pool), and an A2P Campaign (use-case declaration; numbers attach to it via the messaging service).

The bundle wizard is 70% of the 10DLC wizard

Multi-step wizard, org-scoped Twilio resource rows, status-callback webhook, notifications on approve/reject, "required before X" purchase interception — all of that machinery was just built for bundles and maps one-to-one onto TrustHub profiles, brands, and campaigns. The marginal cost of 10DLC dropped dramatically with PR #1469.

03Limitations & gaps in what exists

Smaller issues in the shipped surface, worth fixing opportunistically or alongside roadmap items.

GapImpactNotes
No STOP confirmation / HELP reply CTIA compliance + customer confusion We detect STOP and record the opt-out, but send nothing back. Carriers expect a confirmation ("You've been unsubscribed…") and a HELP response. HELP isn't even detected today.
Generic failure surfacing User can't self-diagnose Delivery failures map to a bare Failed status. Twilio error codes (30034 unregistered, 30007 filtered, 21610 opted-out, 30003 unreachable) are dropped, so a compliance problem looks identical to a wrong number.
Numbers are immutable after purchase Orgs accumulate paid numbers they can't shed No release/delete UI or endpoint. Cost leaks silently every month.
Direct-from-number sending (no Messaging Service) Blocks 10DLC; loses sticky sender / scaler send_sms_util posts with a raw From number. 10DLC campaigns require numbers to live in a Messaging Service sender pool.
Bundle wizard: single end-user, no reuse Repeat data entry for multi-country orgs Each bundle re-collects identity. Twilio supports bundle copies across number types; we don't expose them. Fine for v1.
WhatsApp is an enum variant without onboarding Channel exists in types only MessageChannel::Whatsapp routes through the SMS path; there's no WABA sender registration, so no org can actually use it.
No per-number voicemail / business hours Multi-location orgs share one greeting Voicemail message, after-hours message, and timezone are org-level only (organization_profile).
No usage/cost visibility Surprise Twilio spend Number monthly fees, message segments, and carrier fees aren't shown anywhere in-app.

04Roadmap, ordered by org value

Value scoring assumes the target user: a non-technical US small business that wants to buy a number and start texting customers the same day.

  1. P1US A2P 10DLC registration · #1069 effort L–XL unblocks US SMS

    TrustHub Secondary Customer Profile → A2P Brand → Messaging Service → A2P Campaign, as a guided wizard mirroring the bundle wizard. Status webhooks + notifications on brand/campaign approval. Numbers auto-attach to the org's Messaging Service. Without this, US local-number messaging fails; with it, Loquent's core promise works. Sole-proprietor brand type keeps the form small for tiny businesses.

  2. P2Toll-free verification · #1517 effort M fast compliance path

    Twilio's TollfreeVerification API: one form (business info, use case, sample messages, opt-in proof), one approval, then full-volume US + CA messaging — no brand, no campaign, no per-campaign fees. For many SMBs this is the path we should actively steer to at purchase time: "Want to text customers? A toll-free number is verified in days with one form." Shares the wizard/status/notification machinery with P1.

  3. P3STOP/HELP compliance responder · #1518 effort S carrier requirement

    Auto-reply to STOP with an unsubscribe confirmation, detect + answer HELP with org name and contact info, handle START/UNSTOP to re-opt-in. Configurable copy in settings with sensible defaults. We already detect the keywords — this closes the loop carriers require and is table stakes for P1/P2 approval reviews.

  4. P4Delivery error surfacing · #1519 effort S–M

    Persist the Twilio error code on failed messages, map the common ones to friendly explanations ("This contact's carrier filtered the message — your number may need registration", "This contact opted out"), and show them inline in the conversation plus a deliverability snapshot in Insights. Turns silent failures into actionable guidance, and tells users why they need P1/P2.

  5. P5Number lifecycle: release · #1137 effort S

    Release a number back to Twilio with a destructive-confirm dialog (warn about losing the number permanently and active agent bindings). Stops silent monthly cost leak; completes CRUD on the phone tab.

  6. P6Number porting (port-in) · #1520 effort L

    Bring the org's existing business number into Loquent via Twilio's Porting API: eligibility check, LOA + bill upload (document upload machinery exists from bundles), port-date tracking with webhooks. High emotional value — SMBs rarely want a new number; they want their number to become AI-powered. Long async flow (1–4 weeks), so notifications matter.

  7. P7Per-number voicemail & business hours · #1521 effort M

    Move voicemail greeting, after-hours message, and hours/timezone from org-level to optional per-number overrides. Required by multi-location orgs; pairs naturally with humans_first routing which already references business hours.

  8. P8Caller-ID branding (CNAM + voice trust) · #1522 effort M

    Outbound CNAM so calls show the business name instead of a raw number, plus SHAKEN/STIR attestation via the org's subaccount (Voice Integrity / Trusted Calling later). Directly improves answer rates for the AI agent's outbound calls — but only matters once orgs do meaningful outbound voice volume.

  9. P9Usage & cost visibility · #1523 effort M

    Surface per-org Twilio spend (Usage Records API): number rentals, message segments, voice minutes, carrier fees. Foundation for billing pass-through later; until then, a transparency feature.

  10. P10WhatsApp sender onboarding · #1524 effort XL

    WABA registration via Twilio's Senders API, template management, quality ratings. The channel enum and inbound plumbing exist; everything else doesn't. Big lift, separate initiative — listed for completeness.

i

Why this order

P1–P4 complete the "messaging actually works and is compliant" story — they're sequenced by how many orgs they block (all US orgs → toll-free subset → every texting org → every org that hits an error). P5–P9 are quality-of-ownership features. Per decision Q1, P2 leapfrogs P1 in delivery order: it's smaller and unblocks the same user need via a different number type.

05Wave 1 in depth — the compliance setup family

P1 + P2 + P3 as one coherent "Messaging setup" experience rather than three disconnected features.

i

Decision Q2 — assistant-driven, no manual config UI for now

The flows below were originally framed as settings wizards. Per the 2026-06-12 decision, the assistant owns the experience from day one: it collects and prefills registration data (org profile, intake data), renders the filled form as a rich in-thread component the user reviews and edits, and submits only on explicit confirmation. Settings keep read-only status surfaces (badges, rejection reasons) whose CTAs open the assistant. This rescopes #1069's M4 (#1076) from a settings wizard to assistant tools + in-thread form rendering.

The user-facing frame: a per-number "Messaging status"

Users shouldn't learn the words "10DLC" or "TrustHub". Each phone card gets a messaging-readiness state, exactly like the existing "Not active" voice-webhook badge:

Phone card · Messaging ● Not set up → "Set up messaging" CTA → opens the assistant (Q2) ● Pending review → submitted; webhook flips state, notification on result ● Action needed → rejected with reason; CTA opens the assistant to fix ● Ready → quiet success state Assistant flow by number type: US local → 10DLC (profile → brand → campaign, multi-day waits) US toll-free → TFV (single verification form) ← ships first (Q1) International → bundle wizard (already built ✓ — stays in settings)

New Twilio surface needed

ResourceAPIStored where (new tables)
Secondary Customer ProfileTrustHub v1 CustomerProfiles + entity assignmentsorg_trusthub_profile (sid, status, failure_reason)
A2P BrandMessaging v1 BrandRegistrationsorg_a2p_brand (sid, type: sole-prop/standard, status, score)
Messaging ServiceMessaging v1 Services + PhoneNumbers sender poolmessaging_service_sid on organization_twilio_settings
A2P CampaignMessaging v1 UsAppToPerson (on the service)org_a2p_campaign (sid, use case, status, reason)
Toll-free verificationTollfreeVerification APIorg_tollfree_verification (sid per number, status, reason)

Send-path change

Once a Messaging Service exists, send_sms_util sends with MessagingServiceSid + the specific From number (keeps per-number agent identity while inheriting campaign registration, sticky sender, and Advanced Opt-Out if we enable it). Numbers join the sender pool automatically at purchase / on campaign approval.

!

Sequencing constraint inside P1

Brand approval requires an approved customer profile; campaign approval requires an approved brand. Sole-prop brands also require OTP verification of a contact phone. The flow must tolerate multi-day waits at two points — the bundle machinery's webhook + notification pattern handles this, and with the assistant-driven model (Q2) the assistant must be able to resume the registration in a later conversation, with the phone-card badge as the re-entry point.

06Decisions resolved 2026-06-12

The four open questions, with the calls that were made. These are reflected in the filed issues (§7).

Q1

Ship order within Wave 1 — 10DLC first or toll-free first?

  • 10DLC first (P1 → P2 → P3). Local numbers are what users instinctively pick (local presence, existing area code expectations), and area-code search is already a built feature we'd be soft-deprecating.
  • Build both behind one "Set up messaging" entry and ship together. Cleanest UX, slowest time-to-value.
Decided: toll-free first — P2 (#1517) → P3 (#1518) → P1 (#1069), as recommended.
Q2

Who fills the compliance forms — the user, or the AI assistant?

  • Standard wizard forms first; assistant pre-fill as a fast-follow (org profile + intake data already hold business name, address, website — most fields are derivable).
Decided: assistant-driven from day one — no manual config UI for the moment. The assistant renders the filled form as a rich in-thread component for review and explicit submit; settings keep read-only status badges that open the assistant. Rescopes #1069's M4 (#1076).
Q3

BYO-Twilio orgs — do the registration flows apply?

  • No — show "manage compliance in your Twilio console" for BYO, like we already do for voice webhooks. Less work, but BYO orgs get a second-class product.
Decided: yes — same registrations on BYO accounts, adopting existing resources. Note: #1069 originally scoped BYO out; flagged in the issue comment.
Q4

Who pays the registration fees?

  • Absorb into subscription tiers (one-time brand fee + monthly campaign fee per org; sole-prop is cheap, standard brands aren't).
  • Pass through at cost with a disclosure step.
Decided: per tier, as recommended — absorb sole-prop/toll-free fees in paid tiers, pass standard-brand fees through. Billing wiring is a prerequisite for P1/P2 shipping.

07Issues & execution

Everything is filed under spike #1525 in the Twilio Configuration milestone. The pre-existing 10DLC epic #1069 (with M1–M8: #1073–#1081) was adopted as P1 and moved into the milestone; #1137 (release) stays under the Monetization epic #1134 and is referenced, not re-parented.

#IssuePriorityWave
Spike#1525 — buy a number and set up everything needed to messageP1
P1#1069 — A2P 10DLC registration (epic, M1–M8: #1073–#1081)P11 · Track A
P2#1517 — assistant-driven toll-free verificationP11 · Track B · first
P3#1518 — STOP/HELP/START auto-responderP11 · Track C
P4#1519 — delivery error surfacingP11 · Track D
P5#1137 — number release (under #1134, Monetization)2
P6#1520 — port-in flowP22
P7#1521 — per-number voicemail & business hoursP22
P8#1522 — CNAM + SHAKEN/STIRP23
P9#1523 — usage & cost visibilityP23
P10#1524 — WhatsApp sender onboardingP23

Parallelization

Almost everything parallelizes — the only hard internal sequence is inside #1069 (M1 → M8). Wave boundaries are value groupings, not dependency barriers; a Wave 2/3 item can start any time someone is free.

Wave 1 — messaging works & is compliant (4 parallel tracks): Track A: #1069 10DLC epic (M1→M8 sequential inside; M4 rescoped per Q2) Track B: #1517 toll-free ← ships FIRST (Q1); independent of Track A Track C: #1518 STOP/HELP ← land BEFORE P1/P2 submission testing (carrier reviews check opt-out handling) Track D: #1519 error surfacing ← independent; deep-links into B/A flows Wave 2 — number lifecycle (parallel, independent): #1137 release (blocked on #1134 schema) · #1520 porting · #1521 voicemail/hours Wave 3 — reach & trust (parallel, independent): #1522 CNAM (needs #1069 M1–M3 profile) · #1523 usage · #1524 WhatsApp (own epic) Hard dependencies: #1522 → #1069 (customer profile) · #1137 → #1134 (schema) Soft dependencies: #1518 before #1517/#1069 submissions · Q4 billing wiring before P1/P2 ship