A2P SDK
Guides

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

Next Steps

On this page