A2P 10DLC Compliance Embeddable Onboarding Guide
Info
With global regulatory requirements frequently changing across jurisdictions, navigating compliance is an expensive, ongoing challenge. Complex requirements lead to customer confusion and registration drop-offs, while maintaining internal compliance tooling consumes significant engineering resources. The Compliance Embeddable helps address these challenges by this by shifting the development and regulatory management burden away from your team, allowing you to scale onboarding effortlessly.
The Compliance Embeddable is a white-label, self-service solution designed to integrate seamlessly into an Independent Software Vendor's (ISV) existing portal or web application. It empowers your end customers to independently manage their registrations and verifications requests while Twilio manages the underlying registration workflow infrastructure".
No Twilio Branding: Twilio manages the UI logic and regulatory question flows behind the scenes, but the entire experience can be fully customized to match your platform's exact design, typography, and color palette. Request Theme: https://forms.gle/tvSuXpvwJE9aPj9B9
Minimize Manual Data Entry: When initializing the Compliance Inquiry, Twillo allows ISV's to pre-fill their customer data for an expedited registration experieince.
The Compliance Embeddable requires two integrations:
- Server-side integration: Call Twilio's API to initialize a Compliance Inquiry and retrieve a session token and inquiry ID.
- Client-side integration: Embed the UI in an iframe, and include the session token and inquiry ID as URL parameters.
All calls must be authenticated using Twilio's REST API credentials with Basic Auth, where the account SID is either your primary Twilio Account SID or a subaccount SID. The Account SID given in the credentials is the account that the registration will be associated with after completion of the ComplianceInquiry.
Learn more about the Compliance Embeddable in the Compliance Embeddable FAQ
Before you begin, you must have a Trust Hub Primary Customer Profile for a business whose Business Identity is set to ISV or Reseller. See Create a Trust Hub Primary Customer Profile to learn more.
Only ISV accounts with approved Trust Hub profiles can access the Compliance Embeddable API. Trial accounts are not eligible to use this API.
A2P 10DLC registration is a two-step process that requires both Brand Registration and Campaign Registration. The Compliance Embeddable supports this flow through two separate form submissions:
- Brand Registration: First, you initialize a brand inquiry to collect business information. This registers the brand with The Campaign Registry (TCR).
- Campaign Registration: After the brand is approved, you initialize a campaign inquiry to register specific messaging campaigns under that brand.
The Compliance Embeddable supports both steps by separately calling the Initialize Inquiry API in your workflow twice:
- Once to initialize the brand registration inquiry
- A second time to initialize the campaign registration inquiry after the initial brand approval
The Compliance Embeddable's data collection process is secured via server-side authentication and is triggered by a server-side API call. This API call initializes a ComplianceInquiry and returns a token, which you can then pass to your web client to authenticate into a submission flow. The Compliance Embeddable supports both new submissions and resumption of existing inquiries. If a verification is already in progress, approved, or rejected with an error that cannot be resubmitted, the API returns an error response. See the Error responses table for details.
To initialize a ComplianceInquiry for A2P 10DLC Brand registration, make an HTTPS request to the following API:
POST https://trusthub.twilio.com/v1/A2PBrandRegistrations
If you provide data for optional fields, they're pre-filled in any of your users' subsequent forms.
The body must use the application/json content type.
| Field | Field type | Field Specifics | Description |
|---|---|---|---|
brandType [required] | Enum | Allowed Values: STANDARD, SOLE_PROPRIETOR | A SOLE_PROPRIETOR is an unregistered individual with strict messaging limits and no EIN, while a STANDARD Business is a legally registered entity with an EIN that unlocks high-volume, high-throughput messaging capabilities. |
friendlyName [required] | String | Max length: 255 | A descriptive name for this brand or campaign registration inquiry. |
notificationEmail [required] | String | Email regex. Max length: 500 | The email address to which all notifications for the status of the registration will be sent. |
themeSetId [optional] | String | Max length: 255 | Theme ID for customized UI styling. To request a customized Theme, follow the instructions in our FAQ. |
businessName [optional] | String | Max length: 255 | The name of the business or organization using the phone number. |
businessRegistrationAuthority [opt] | String | Allowed Values: TBD | The authority that issued the business registration. For US businesses, this is typically EIN. Required for all business types except SOLE_PROPRIETOR. |
businessRegistrationNumber [opt] | String | Max length: 21 | A legally recognized business registration number such as an EIN. Required for all business types except SOLE_PROPRIETOR. |
businessIndustry [optional] | Enum | Allowed Values: AGRICULTURE, AUTOMOTIVE, BANKING, COMMUNICATION, CONSTRUCTION, CONSUMER, EDUCATION, ELECTRONICS, ENERGY, ENGINEERING, FAST_MOVING_CONSUMER_GOODS, FINANCIAL, FINTECH, FOOD_AND_BEVERAGE, GAMBLING, GOVERNMENT, HEALTHCARE, HOSPITALITY, INSURANCE, JEWELRY, LEGAL, MANUFACTURING, MEDIA, NOT_FOR_PROFIT, OIL_AND_GAS, ONLINE, PROFESSIONAL_SERVICES, RAW_MATERIALS, REAL_ESTATE, RELIGION, RETAIL, TECHNOLOGY, TELECOMMUNICATIONS, TRANSPORTATION, TRAVEL | |
businessWebsite [optional] | String | URL regex (https://). Max length: 255 | The website of the business or organization using the phone number. |
brandType [required] | Enum | Allowed Values: PRIVATE_PROFIT, PUBLIC_PROFIT, NON_PROFIT, SOLE_PROPRIETOR, GOVERNMENT | |
brandExternalVettingToken [opt] | String | Max length: 10 | The unique vetting token from the vetting provider. The token is case sensitive and must match the format provided by the vetting provider exactly. |
businessStockSymbol [optional] | String | Max length: 10 | The unique publicly traded company or organization stock or ticker symbol |
businessIndustry [optional] | Enum | Allowed Values: AMEX, AMX, ASX, B3, BME, BSE, FRA, ICEX, JPX, JSE, KRX, LON, NASDAQ, NONE, NYSE, NSE, OMX, OTHER, SEHK, SGX, SSE, STO, SWX, SZSE, TSX, TWSE, VSE | |
businessTaxExemptStatus [optional] | Boolean | Allowed Values: TRUE, FALSE | A value of true will mark the business as excempt from local government taxes. |
businessStreetAddress [optional] | String | Max length: 100 | The address of the business or organization using the phone number. |
businessStreetAddress2 [optional] | String | Max length: 100 | The second row of the street address of the business or organization using the phone number. |
businessCity [optional] | String | Max length: 100 | The city of the business or organization using the phone number. |
businessStateProvinceRegion [opt] | String | Max length: 20 | The state/province or region of the business or organization using the phone number. |
businessPostalCode [optional] | String | Max length: 10 | The postal code of the business or organization using the phone number. |
businessCountry [optional] | String | Max length: 2 | The ISO country code of the business or organization using the phone number. |
businessContactFirstName [opt] | String | Max length: 100 | The first name of the contact for the business or organization using the phone number. |
businessContactLastName [opt] | String | Max length: 100 | The last name of the contact for the business or organization using the phone number. |
businessContactEmail [optional] | String | Email regex. Max length: 100 | The email address of the contact for the business or organization using the phone number. |
businessContactPhone [optional] | String | E.164 regex. Max length: 20 | The phone number of the contact for the business or organization using the phone number. |
authorizedContactVerificationEmail [opt] | String | Email regex. Max length: 255 | The first and last name of the designated representative for the business or organization. |
authorizedContactMobilePhoneNumberE164 [opt] | String | E.164 regex. Max length: 20 | The phone number of the designated representative for the business or organization. |
isTest [optional] | Boolean | Allowed Values: TRUE, FALSE | A value of true will mark the bundle as a test bundle. The test bundle will be auto-rejected without verification and cannot be used for phone number purchases. If this field is not provided, by default the bundle will NOT be created as a test bundle |
skipAutomaticSecVet [optional] | Boolean | Allowed Values: TRUE, FALSE | A value of true skips the message volume questions in UI |
1POST https://trusthub.twilio.com/v1/A2PBrandRegistrations23Auth: Basic auth (AccountSid:AuthToken)45Request body:6{7"brandType": "STANDARD",8"customerProfileId": "BU1213242784782",9"friendlyName": "Acme Corp",10\\following fields are optional11"themeSetId": "theme_abc123",12"statusNotificationEmail": "notify@example.com",13"businessName": "Acme Corp",14"businessRegistrationAuthority": "EIN",15"businessRegistrationNumber": "123456789",16"businessIndustry": "TECHNOLOGY",17"businessWebsite": "https://acme.com",18"businessType": "PRIVATE_PROFIT",19"businessStockSymbol": "TWLO",20"businessStockExchange": "NYSE",21"businessTaxExemptStatus": false,22"businessStreetAddress": "123 Main St",23"businessStreetAddress2": "Suite 100",24"businessCity": "San Francisco",25"businessStateProvinceRegion": "CA",26"businessPostalCode": "94105",27"businessCountry": "US",28"businessContactFirstName": "Jane",29"businessContactLastName": "Doe",30"businessContactEmail": "jane@acme.com",31"businessContactPhone": "+14155551234",32“authorizedContactVerificationEmail”: “verification@example.com”33“authorizedContactMobilePhoneNumberE164”: “+14333045678”,34“brandExternalVettingToken”: “cv|10dlctcr|...”35“isTest”: “true”, (would want to skip the mock option Persona screen asking about Message volume),36"skipAutomaticSecVet": true37}3839Response (201 Created):40{41"id": "tri1.us1.account.AC238276e6.registration.BU6469a51f"42"sessionId": "inq_XXXXXXXXXXXXXXXXXXXXXXXX",43"sessionToken": "eyJhbGciOiJIUzI1NiIs..."44}45}46
To resume a ComplianceInquiry for A2P 10DLC Brand registration, make an HTTPS request to the following API:
POST https://trusthub.twilio.com/v1/A2PBrandRegistrations/{id}/EmbeddedSessions
The value for id is tri1.us1.account.(AccountSID).registration.(BrandBundleSID)
To retrieve a list of all A2P 10DLC registrations, including their Bundle SIDs, make an HTTPS request to the following API:
GET https://messaging.twilio.com/v1/a2p/BrandRegistrations
To learn more about query parameters for filtering results, see the Brand Registration API docs.
To initialize a ComplianceInquiry for A2P 10DLC Campaign registration, make an HTTPS request to the following API:
POST https://trusthub.twilio.com/v1/A2PCampaignRegistrations
If you provide data for optional fields, they're pre-filled in any of your users' subsequent forms.
The body must use the application/json content type.
| Field | Field type | Field Specifics | Description | |
|---|---|---|---|---|
a2pBrandRegistrationSid [required] | String | BN SID | The Brand Registration SID from the approved brand registration. | |
messagingServiceSid [required] | String | MG SID | The Messaging Service SID to associate with this campaign. | |
themeSetId [optional] | String | Max length: 255 | Theme ID for customized UI styling. To request a customized Theme, follow the instructions in our FAQ. | |
useCaseCategories [optional] | Enum | Allowed Values: 2FA, ACCOUNT_NOTIFICATION, AGENTS_FRANCHISES, CARRIER_EXEMPT, CHARITY, CUSTOMER_CARE, DELIVERY_NOTIFICATION, EMERGENCY, FRAUD_ALERT, HIGHER_EDUCATION, K12_EDUCATION, MARKETING, POLITICAL, POLLING_VOTING, PROXY, PUBLIC_SERVICE_ANNOUNCEMENT, SECURITY_ALERT, SOCIAL, SWEEPSTAKE | The category that best describes the use case for this campaign. | |
useCaseDescription [optional] | String | Min Length: 40 Max length: 4096 | Detailed description of the campaign's messaging use case. | |
useCaseSampleMessage1 [optional] | String | Min Length: 40 Max length: 1024 | First sample message demonstrating typical message content for this campaign. | |
useCaseSampleMessage2 [optional] | String | Min Length: 40 Max length: 1024 | Second sample message demonstrating typical message content for this campaign. | |
useCaseSampleMessage3 [optional] | String | Min Length: 40 Max length: 1024 | Third sample message demonstrating typical message content for this campaign. | |
useCaseSampleMessage4 [optional] | String | Min Length: 40 Max length: 1024 | Fourth sample message demonstrating typical message content for this campaign. | |
useCaseSampleMessage5 [optional] | String | Min Length: 40 Max length: 1024 | Fifth sample message demonstrating typical message content for this campaign. | |
useCaseCategories [optional] | Enum | Allowed Values: VERBAL, WEB_FORM, PAPER_FORM, VIA_TEXT, MOBILE_QR_CODE | The method by which end users opt-in to receive messages. | |
useCaseOptInDescription [optional] | String | Min Length: 40 Max length: 2048 | Description of how end users opt-in to receive messages from this campaign. | |
hasEmbeddedLinks [optional] | Boolean | Allowed Values: TRUE, FALSE | A value of true indicates that messages will include embedded links. | |
hasEmbeddedPhone [optional] | Boolean | Allowed Values: TRUE, FALSE | A value of true indicates that messages will include embedded phone numbers. | |
embeddedUrlSample [optional] | String | URL regex (https://). Max length: 255 | Sample URLs that will be embedded in messages. | |
directLending [optional] | Boolean | Allowed Values: TRUE, FALSE | A value of true indicates this campaign involves direct lending or loan arrangements. | |
ageGated [optional] | Boolean | Allowed Values: TRUE, FALSE | A value of true indicates this campaign has age restrictions. | |
privacyPolicyUrl [optional] | String | URL regex (https://). Max length: 2048 | URL to the privacy policy applicable to this messaging campaign. | |
termsAndConditionsUrl [optional] | String | URL regex (https://). Max length: 2048 | URL to the terms and conditions applicable to this messaging campaign. | |
optInKeywords [optional] | String | Max length: 255 | Keywords that users can send to opt-in to messages. | |
optInMessageSample [optional] | Array of Strings | Min Length: 20 Max length: 1024 | Sample message sent to users after they opt-in. | |
optOutKeywords [optional] | Array of Strings | Max length: 255 | Keywords that users can send to opt-out of messages. | |
optOutMessageSample [optional] | String | Min Length: 20 Max length: 1024 | Sample message sent to users after they opt-out. | |
helpKeywords [optional] | Array of Strings | Max length: 255 | Keywords that users can send to request help. | |
helpMessageSample [optional] | String | Min Length: 20 Max length: 1024 | Sample message sent to users when they request help. |
1POST https://trusthub.twilio.com/v1/A2PCampaignRegistrations2Auth: Basic auth (AccountSid:AuthToken)34Request body:5{6"a2pBrandRegistrationSid": "BN01cab0515ca623fc3d3bc9ee0879b50f",7\\following fields are optional8"messagingServiceSid": "MG12345678901234567890123456789000",9"themeSetId": "theme_abc123",10"useCaseCategories": ["ACCOUNT_NOTIFICATIONS", "CUSTOMER_CARE"],11"useCaseDescription": "Order status updates and customer support responses",12"useCaseSampleMessage1": "Hi Jane, your order #4821 has shipped and will arrive by Thursday. Track at acme.com/track/4821",13"useCaseSampleMessage2": "Hi Jane, your order #4821 has shipped and will arrive by Thursday. Track at acme.com/track/4821",14"useCaseSampleMessage3": "Hi Jane, your order #4821 has shipped and will arrive by Thursday. Track at acme.com/track/4821",15"useCaseSampleMessage4": "Hi Jane, your order #4821 has shipped and will arrive by Thursday. Track at acme.com/track/4821",16"useCaseSampleMessage5": "Hi Jane, your order #4821 has shipped and will arrive by Thursday. Track at acme.com/track/4821",17"useCaseOptInTypes": ["WEB_FORM"],18"useCaseOptInDescription": "End users opt-in by visiting www.acme.com and adding their phone number. They then check a box agreeing to receive text messages from Acme, Inc. Additionally, end users can also opt-in by texting START to (111) 555-3333 to opt in. Terms and Conditions at www.acme.com/tc. Privacy Policy at www.acme.com/privacy.",19"hasEmbeddedLinks": false,20"hasEmbeddedPhone": false,21"embeddedUrlSample": "https://acme.com/privacy",22"directLending": false,23"ageGated": false,24"privacyPolicyUrl": "https://acme.com/privacy",25"termsAndConditionsUrl": "https://acme.com/terms",26"optInKeywords": ["START", "SUBSCRIBE"],27"optInMessageSample": "For help, visit acme.com/support or call 1-800-555-0123. Reply STOP to opt out.",28"optOutKeywords": ["START", "SUBSCRIBE"],29"optOutMessageSample": "For help, visit acme.com/support or call 1-800-555-0123. Reply STOP to opt out.",30"helpKeywords": ["START", "SUBSCRIBE"],31"helpMessageSample": "For help, visit acme.com/support or call 1-800-555-0123. Reply STOP to opt out."32}3334Response (201 Created):35{36"id": "tri1.us1.account.AC238276e6.registration.BU6469a51f"37"sessionId": "inq_XXXXXXXXXXXXXXXXXXXXXXXX",38"sessionToken": "eyJhbGciOiJIUzI1NiIs..."39}40
To resume a ComplianceInquiry for A2P 10DLC Campaign registration, make an HTTPS request to the following API:
POST https://trusthub.twilio.com/v1/A2PCampaignRegistrations/{id}/EmbeddedSessions
Once the campaign is created, its associated Bundle SID will be removed. Going forward, delivery status and errors by using the Messaging Service API.
By default, Twilio sets your Messaging Service to "Defer to sender's webhook," meaning inbound messages to any sender within the Messaging Service's sender pool hit the webhook configured on each sender. The delivery status of your message, including any delivery errors, is sent asynchronously to your status callback URL.
GET https://messaging.twilio.com/v1/Services/{MessagingServiceSid}/Compliance/Usa2p/QE2c6890da8086d771620e9b13fadeba0b
This endpoint returns the following details:
sidcampaign_status(for example,IN_PROGRESS,VERIFIED, orFAILED)failure_reason(if any)
Track your A2P registration status automatically with Twilio Event Streams. You can now get instant webhook notifications for any changes to your Brands, Campaigns, or 10DLC numbers without having to manually poll APIs or refresh the console. To learn more, see the Event Streams docs.
After initializing a ComplianceInquiry, you may embed the ComplianceInquiry UI in your website using the TwilioComplianceEmbed React client.
Install the package in your React project using your preferred package manager.
NPM:
npm install @twilio/twilio-compliance-embed
Yarn:
yarn add @twilio/twilio-compliance-embed
The ComplianceInquiry UI can be embedded in your site using following code snippet:
1import * as React from "react";2import { TwilioComplianceEmbed } from "@twilio/twilio-compliance-embed";34const ComplianceInquiry = () => {5return (6<TwilioComplianceEmbed7inquiryId='<your inquiry ID from calling the Initialize ComplianceInquiry API>'8inquirySessionToken='<your inquiry session token from calling the Initialize ComplianceInquiry API>'9/>10);11};
The ComplianceInquiry UI may take a few seconds to load and render.
| Name | Type | Description |
|---|---|---|
inquiryId | (Required) String | A valid inquiryId returned by calling the Initialize ComplianceInquiry API. |
inquirySessionToken | (Required) String | A valid inquirySessionToken returned by calling the Initialize ComplianceInquiry API. |
onInquirySubmitted | () => void | An event handler that fires when the user has completed the ComplianceInquiry process. This event is fired when the user lands on the last screen. |
onComplete | () => void | An event handler that fires when a user completes the ComplianceInquiry process. This event is fired when the user clicks the Done or Exit button on the last page. Note: This event is not guaranteed to be fired as the user could choose not to click the button on the last page. If you wish to track when a user has finished the flow and submitted the bundle, use onInquirySubmitted instead. |
onCancel | () => void | An event handler that fires when the user has canceled the ComplianceInquiry process. |
onError | () => void | An event handler that fires when an unexpected error occurs during the ComplianceInquiry process. |
onReady | () => void | An event handler that fires when the ComplianceInquiry UI has finished loading. |
widgetPadding | { top?: number; bottom?: number; left?: number; right?: number; } | Allows customizing the internal padding inside the iframe. If you omit the property, the component applies the default padding: {top: 74, left: 24, right: 24, bottom: 24}. The value should be an object with the following structure: {top?: number; bottom?: number; left?: number; right?: number;} |
1import * as React from "react";2import { Spinner } from "@twilio-paste/core/spinner";3import { TwilioComplianceEmbed } from "@twilio/twilio-compliance-embed";45function MyComplianceInquiry() {6const [data, setData] = React.useState(null);7const [isLoading, setLoading] = React.useState(true);89React.useEffect(() => {10fetch("https://trusthub.twilio.com/v1/ComplianceInquiries/Tollfree/Initialize", {11method: "POST",12})13.then((res) => res.json())14.then((data) => {15setData(data);16setLoading(false);17});18}, []);1920return !isLoading ? (21<TwilioComplianceEmbed22inquiryId={data.inquiry_id}23sessionToken={data.inquiry_session_token}24onReady={() => {25console.log("Ready!");26}}27onInquirySubmitted={() => {28console.log("Registration complete");29}}30widgetPadding={{top: 0, left: 100, right: 100, bottom: 0}}31/>32) : (33<Spinner decorative={false} title="Loading" />34);35}3637export default MyComplianceInquiry;
We don't yet provide native integrations for frontend frameworks other than React. However, we are releasing a JS SDK soon, so customers using non-React frameworks or older versions of React can also use the Compliance Embeddable.