Twilio Gotchas
Twilio Gotchas
Consolidated tribal knowledge extracted from the SDK codebase and Twilio documentation.
Business Information
Business Name Must Match Tax Records
The business_name in Customer Profile creation must exactly match what the IRS or tax authority has on file. Even small differences (e.g., "Corp" vs "Corporation", missing punctuation) will cause brand registration to fail.
Solution: Use the exact legal name from your tax documents.
Disposable Email Domains Rejected
Twilio rejects Customer Profiles with disposable email domains (e.g., temp-mail.org, 10minutemail.com) during profile review.
Solution: Use a real business email address.
Address Must Be Valid US or Canadian
Customer Profiles and Sole Proprietor registrations require a valid US or Canadian mailing address. Invalid or fake addresses are rejected.
Solution: Use a real US/CA address. PO boxes may be rejected.
Direct Standard Flow
Brand Contact Email Required (Since Oct 2024)
brand_contact_email became required for Direct Standard flows in October 2024 for 2FA verification. Omitting it will cause Trust Product creation to fail.
Solution: Always provide brand_contact_email in Step 2.
Sole Proprietor Flows
Mobile Number 3-Use Limit
The mobile number used for OTP verification can only be used 3 times total for Sole Proprietor registrations across ALL vendors (not just your account). After 3 uses, the number is permanently blocked.
Solution: Warn customers about this limit. Use a different number if needed.
OTP 24-Hour Window
Customers must verify the OTP SMS within 24 hours or the verification expires.
Solution: Send clear instructions to customers immediately after triggering OTP. You can re-trigger from the Twilio Console if needed.
1 Campaign Per Brand Limit
Sole Proprietor brands can only have 1 campaign. Attempting to create a second campaign will fail.
Solution: Design your app to support only 1 campaign per Sole Prop customer.
1 Phone Per Campaign Limit
Sole Proprietor campaigns can only have 1 phone number. Attempting to add a second number will fail.
Solution: Clearly communicate this limit to customers.
~3,000 Messages/Day Throughput Cap
Sole Proprietor campaigns are hard-capped at approximately 3,000 messages per day, regardless of TCR trust score.
Solution: Set customer expectations. Suggest Standard flows for higher throughput.
Webhooks
BU SID Prefix Ambiguity
Both Customer Profiles and Trust Products use the BU SID prefix. The SDK's parseWebhookEvent() uses heuristics to disambiguate, but may return profile_or_trust_product.status_changed if it can't determine the type.
Solution: Track resource types in your database by SID.
Dual Field Casing
Twilio webhook bodies can use either PascalCase (ResourceSid, Status, FailureReason) or snake_case (resource_sid, status, failure_reason), depending on the endpoint and SDK version.
Solution: The SDK checks both formats automatically. If parsing webhooks manually, check both cases.
API Behavior
trustProductSid Maps to a2PProfileBundleSid
When calling createBrandRegistration(), the SDK parameter trustProductSid maps to Twilio's a2PProfileBundleSid field (and customerProfileSid maps to customerProfileBundleSid). This field name mismatch is non-obvious.
Solution: Use the SDK's typed methods — they handle the remapping.
refreshRegistrationState Silently Swallows Errors
refreshRegistrationState() wraps every Twilio API call in try/catch and silently ignores errors (assumes resources may have been deleted). If an API call fails for any reason, the old status is preserved.
Solution: If you need to detect failures, wrap refreshRegistrationState() in your own try/catch or call Twilio APIs directly.
Poll Timeouts Don't Throw
pollBrandUntil() and pollCampaignUntil() do NOT throw on timeout. They return the last-fetched status and expect the caller to check if it matches the target.
Solution: Always check the returned status:
const brand = await client.pollBrandUntil(brandSid, 'APPROVED');
if (brand.status !== 'APPROVED') {
console.warn('Timeout - brand still:', brand.status);
}Timelines
Campaign Vetting Takes 10-15 Business Days
Despite Twilio docs sometimes suggesting faster times, campaign manual vetting realistically takes 10-15 business days (up to 2-3 weeks).
Solution: Set customer expectations. Use webhooks for status updates instead of polling.
Brand Review: Minutes to 7+ Days
Brand review by The Campaign Registry can range from minutes (for high-trust brands) to 7+ business days (for newer or lower-trust brands).
Solution: Use webhooks for status updates.
Campaign Resubmission Costs $15
If a campaign fails manual vetting and you edit and resubmit it, Twilio charges an additional $15 fee.
Solution: Review campaign details carefully before submitting. Ensure description is detailed (≥40 chars), message samples are representative, and content complies with Twilio policies.
Brand Suspended
If a brand is suspended (SUSPENDED status), there is no programmatic fix. You must contact Twilio Support to understand the suspension reason and resolve it.
Solution: Contact Twilio Support immediately if a brand is suspended.
ISV Flows
Primary Profile Prerequisite
ISV Standard and ISV Sole Prop flows require an approved ISV Primary Customer Profile before you can create Secondary Customer Profiles for customers. The SDK checks for this prerequisite in Step 1 and throws if no eligible Primary Profile exists.
Solution: Create your ISV Primary Profile via the Twilio Console first, with business_identity: 'isv_reseller_or_partner', and wait for approval.
isEligiblePrimaryProfile Filter
The SDK filters out profiles with SECONDARY_CUSTOMER_PROFILE_POLICY_SID or STARTER_CUSTOMER_PROFILE_POLICY_SID when checking for an eligible Primary Profile. Only true Primary profiles qualify.
Solution: Ensure your ISV Primary Profile uses the correct policy SID (not Secondary or Starter).