Custom Channel Setup (BYOC) 45 min
Outcome
A working Bring Your Own Channel (BYOC) pipeline where customers on any external messaging platform can reach your Agentforce Service Agent through a partner-managed integration.
When complete, you will have:
- A BYOC Messaging Channel connected to your Salesforce org via a managed package and the Interaction Service API
- Omni-Channel routing configured to deliver inbound messages to your Agentforce agent
- Verified end-to-end message flow from the external messaging provider through to your agent and back
- Escalation routing to a human agent queue when the agent hands off
BYOC channels require the Digital Engagement add-on license and a managed package from your messaging or CCaaS provider. Unlike native channels (WhatsApp, SMS, Messenger), BYOC requires developer integration work to translate messages between the external provider and Salesforce. No Experience Cloud site or EmbeddedServiceConfig is needed.
Salesforce offers two BYOC flavors. This guide covers Bring Your Own Channel for Messaging, which connects an external messaging provider to Salesforce using the Interaction Service API. The second flavor, Bring Your Own Channel for CCaaS, connects an external contact center with unified partner-owned routing and supports both messaging and voice. Choose the flavor that matches your provider.
Architecture
When a customer sends a message through the external messaging platform, the message flows through the following chain:
Click a node to jump to its configuration step.
Key metadata relationships:
MessagingChannel.MessageType=CustomMessagingChannel.SessionHandlerId= BotDefinition.IdsessionHandlerType=AgentforceServiceAgentsessionHandlerAsa= BotDefinition DeveloperNameServiceChannel.DeveloperName=sfdc_livemessageQueue.SobjectType=MessagingSession
The managed package from your messaging provider handles webhook ingestion, message format translation, and delivery status callbacks. Salesforce receives normalized messages through the Interaction Service API, creates MessagingSession records, and routes them to your Agentforce agent via Omni-Channel.
Configure Your Variables
Update these variables with your values and they will be substituted in the code blocks below.
Implementation Steps
1. Verify Your Starting Point
Confirm your agent exists, your org has the required licenses, and you have admin access.
Confirm your Service Agent exists and is active
Before building the routing chain, verify your Agentforce Service Agent is deployed and active in the target org.
sf data query \
--target-org <your-org-alias> \
--query "SELECT Id, DeveloperName, MasterLabel, AgentType FROM BotDefinition WHERE DeveloperName='Reservation_Agent' AND IsActive=true"
Verify the agent is active:
Expected result: One record returned with a valid Id.
If no record is returned, activate your agent in Agent Builder before proceeding.
Authenticate and verify org access
Ensure you have admin access to the target org and the CLI is connected.
sf org login web --alias <your-org-alias> --instance-url https://login.salesforce.com
sf org display --target-org <your-org-alias> --verbose
Verify org access:
Expected result: Org display shows your username and instance URL without errors.
Verify Digital Engagement license
BYOC channels require the Digital Engagement add-on. Confirm it is provisioned in your org.
sf data query \
--target-org <your-org-alias> \
--query "SELECT Id, Name, Status, IsProvisioned FROM PackageLicense WHERE NamespacePrefix='sfdc_livemessage'"
Verify Digital Engagement license:
Expected result: One record returned with IsProvisioned = true.
If not found, contact your Salesforce account executive to provision Digital Engagement.
2. Enable Messaging and Omni-Channel
Enable the org-level settings required for BYOC messaging.
Enable Messaging in Setup
Messaging must be enabled at the org level before any messaging channels can be created.
# Deploy Omni-Channel settings via metadata
mkdir -p force-app/main/default/settings
cat > force-app/main/default/settings/OmniChannel.settings-meta.xml << 'EOF'
<?xml version="1.0" encoding="UTF-8"?>
<OmniChannelSettings xmlns="http://soap.sforce.com/2006/04/metadata">
<enableOmniChannel>true</enableOmniChannel>
</OmniChannelSettings>
EOF
sf project deploy start \
--target-org <your-org-alias> \
--source-dir force-app/main/default/settings/OmniChannel.settings-meta.xml
Verify messaging is enabled:
Expected result: Messaging Settings page loads without errors and shows channel management options. Omni-Channel Settings shows "Omni-Channel is enabled."
Verify the service channel exists
The sfdc_livemessage service channel is automatically created when Digital Engagement is enabled.
sf data query \
--target-org <your-org-alias> \
--query "SELECT Id, DeveloperName, MasterLabel FROM ServiceChannel WHERE DeveloperName='sfdc_livemessage' LIMIT 1"
Verify the Live Message channel:
Expected result: One record returned with DeveloperName = sfdc_livemessage.
If not found, Messaging is not enabled. Return to Setup > Messaging Settings and enable it.
3. Install the Provider Managed Package
Install the managed package from your external messaging or CCaaS provider. This package provides the webhook handlers, message translation logic, and Interaction Service API integration that bridges your external platform to Salesforce.
Each messaging provider (Twilio, Vonage, MessageBird, custom platforms, etc.) distributes their own managed package. Contact your provider for the installation URL or find it on Salesforce AppExchange. The managed package may include sample Omni-Channel flows for routing.
Install the managed package
# Install the managed package using the installation URL from your provider
# Replace the URL with your provider's package installation link
sf package install \
--target-org <your-org-alias> \
--package "{{PROVIDER_PACKAGE_ID}}" \
--wait 10
# Verify installed packages
sf package installed list --target-org <your-org-alias>
Verify the managed package installation:
Expected result: The provider's managed package appears in Setup > Installed Packages with status "Installed".
Configure the managed package
Follow your provider's configuration guide to connect the managed package to your external messaging platform. This typically involves:
# Provider configuration is typically UI-driven.
# After configuration, verify the Named Credential exists:
sf data query \
--target-org <your-org-alias> \
--query "SELECT Id, MasterLabel, DeveloperName FROM NamedCredential WHERE DeveloperName LIKE '%{{PROVIDER_NAME}}%'"
The managed package configuration varies by provider. Consult your provider's documentation for exact field names, API credential formats, and webhook setup instructions. Common requirements include API keys, webhook URLs, and message format configuration.
Verify provider configuration:
Expected result: Provider configuration shows a connected/healthy status.
If the provider offers a test connection button, it succeeds.
4. Create the BYOC Messaging Channel
Create a Bring Your Own Channel in Salesforce Messaging Settings. This registers the channel and enables message routing through the Interaction Service API.
Create the channel via Setup
# The BYOC channel must be created via the Setup wizard.
# After creation, verify with:
sf data query \
--target-org <your-org-alias> \
--query "SELECT Id, DeveloperName, MasterLabel, MessageType, IsActive FROM MessagingChannel WHERE MessageType='Custom'"
Verify channel was created:
Expected result: Query returns one record with MessageType = 'Custom' and the DeveloperName matching your channel.
Verify channel details
After creation, confirm the channel is properly configured with the correct message type and platform key.
sf data query \
--target-org <your-org-alias> \
--query "SELECT Id, DeveloperName, MasterLabel, MessageType, IsActive, MessagingPlatformKey, SessionHandlerId, FallbackQueueId FROM MessagingChannel WHERE DeveloperName='AgentforceChannel'"
Verify channel is active:
Expected result: Channel record returned with MessageType = 'Custom' and IsActive = true.
5. Configure Routing to Your Agent
Set up the routing so inbound BYOC messages are handled by your Agentforce Service Agent, with a fallback queue for escalation.
Create a messaging queue for fallback routing
The queue handles messages when the agent is unavailable or escalates to a human. Even with direct agent routing, a fallback queue is required.
# Check if queue exists
sf data query --target-org <your-org-alias> \
--query "SELECT Id FROM Group WHERE Type='Queue' AND DeveloperName='AgentforceChannel_Queue'"
# If not found, create via Metadata API
mkdir -p force-app/main/default/queues
cat > force-app/main/default/queues/AgentforceChannel_Queue.queue-meta.xml << 'EOF'
<?xml version="1.0" encoding="UTF-8"?>
<Queue xmlns="http://soap.sforce.com/2006/04/metadata">
<fullName>AgentforceChannel_Queue</fullName>
<name>AgentforceChannel Queue</name>
<queueSobject>
<sobjectType>MessagingSession</sobjectType>
</queueSobject>
</Queue>
EOF
sf project deploy start --target-org <your-org-alias> --metadata Queue:AgentforceChannel_Queue
Verify queue creation:
Expected result: One queue record returned with DeveloperName = '{{CHANNEL_NAME}}_Queue'.
Route the channel to your Agentforce agent
Set the SessionHandlerId on the MessagingChannel to point to your agent's BotDefinition. This enables direct agent routing for all inbound BYOC messages.
# Get the Bot ID and Queue ID
BOT_ID=$(sf data query --target-org <your-org-alias> --json \
--query "SELECT Id FROM BotDefinition WHERE DeveloperName='Reservation_Agent'" \
| jq -r '.result.records[0].Id')
QUEUE_ID=$(sf data query --target-org <your-org-alias> --json \
--query "SELECT Id FROM Group WHERE Type='Queue' AND DeveloperName='AgentforceChannel_Queue'" \
| jq -r '.result.records[0].Id')
CHANNEL_ID=$(sf data query --target-org <your-org-alias> --json \
--query "SELECT Id FROM MessagingChannel WHERE DeveloperName='AgentforceChannel'" \
| jq -r '.result.records[0].Id')
# Update the channel with agent routing
sf apex run --target-org <your-org-alias> << EOF
MessagingChannel channel = [SELECT Id FROM MessagingChannel WHERE DeveloperName = 'AgentforceChannel' LIMIT 1];
channel.SessionHandlerId = '$BOT_ID';
channel.FallbackQueueId = '$QUEUE_ID';
update channel;
System.debug('Updated MessagingChannel: ' + channel.Id + ' with SessionHandlerId: $BOT_ID');
EOF
Verify agent routing:
Expected result: Query the channel and confirm SessionHandlerId matches your BotDefinition.Id.
If SessionHandlerId is not available in your org's API version, configure routing through an Omni-Channel inbound flow instead. Create a flow with the Route Work action: Service Channel = sfdc_livemessage, Route To = your Agentforce Service Agent.
Set up Omni-Channel flows for agent integration (optional)
For advanced routing, create inbound and outbound Omni-Channel flows. Your provider's managed package may include sample flows you can customize.
# Check if the provider included sample flows
sf data query \
--target-org <your-org-alias> \
--query "SELECT Id, MasterLabel, ProcessType FROM FlowDefinition WHERE ProcessType='Flow' AND MasterLabel LIKE '%{{PROVIDER_NAME}}%'"
Inbound flows handle how messages reach the agent. Outbound flows handle escalation from the agent to human agents. Both are optional when using direct SessionHandlerId routing, but required for advanced routing scenarios like skill-based routing or conditional agent assignment.
6. Test and Verify
Send a test message through your external messaging platform and confirm the full pipeline works end-to-end.
Testing BYOC requires the external messaging provider to be connected and operational. Unlike native channels, you cannot test purely within Salesforce. Ensure the managed package is configured and the external provider webhook is active before proceeding.
Send a test message
Use the external messaging platform to send a message and verify the agent responds.
# After sending a test message from the external platform, query for the session:
sf data query --target-org <your-org-alias> \
--query "SELECT Id, Status, AgentType, OwnerId, CreatedDate, MessagingChannelId FROM MessagingSession WHERE MessagingChannel.DeveloperName='AgentforceChannel' ORDER BY CreatedDate DESC LIMIT 5"
Verify the agent responds:
Expected result: Agent responds to the message. MessagingSession record created with Status = 'Active' or 'Ended'.
Verify agent routing and session records
Confirm messages are being routed to your agent by checking MessagingSession and AgentWork records.
# Check recent MessagingSessions for the BYOC channel
sf data query --target-org <your-org-alias> \
--query "SELECT Id, Status, AgentType, OwnerId, CreatedDate FROM MessagingSession WHERE MessagingChannel.MessageType='Custom' ORDER BY CreatedDate DESC LIMIT 5"
# Check AgentWork records
sf data query --target-org <your-org-alias> \
--query "SELECT Id, WorkItemId, BotId, RoutingType, CreatedDate FROM AgentWork ORDER BY CreatedDate DESC LIMIT 5"
# Check individual messages in the session
sf data query --target-org <your-org-alias> \
--query "SELECT Id, MessageText, SenderType, CreatedDate FROM MessagingEvent WHERE MessagingSession.MessagingChannel.DeveloperName='AgentforceChannel' ORDER BY CreatedDate DESC LIMIT 10"
Verify messaging session records:
Expected result: Recent MessagingSession exists with AgentType populated and messages visible in MessagingEvent records.
Test escalation to human agent
Verify that when the agent escalates, the conversation routes to your fallback queue.
# Send a message that triggers escalation (e.g., "I want to speak to a human")
# Then verify the session was transferred:
sf data query --target-org <your-org-alias> \
--query "SELECT Id, Status, OwnerId, Owner.Name, AgentType FROM MessagingSession WHERE MessagingChannel.DeveloperName='AgentforceChannel' ORDER BY CreatedDate DESC LIMIT 1"
Verify escalation routing:
Expected result: After escalation, the MessagingSession owner changes from the BotDefinition to the fallback queue or a human agent.
BYOC-Specific Considerations
| Consideration | Details |
|---|---|
| Setup complexity | Higher than native channels. Requires managed package installation and provider-specific configuration |
| Custom development | Provider must implement the Interaction Service API for message ingestion and delivery |
| Message format | Messages are normalized by the managed package before reaching Salesforce |
| Progress indicators | Supported. Agent can show "Doing research", "Analyzing" etc. to the customer |
| Interactive components | Supported if the external platform and managed package support rich message types |
| Session handling | Managed by Salesforce MessagingSession. Session lifecycle depends on provider configuration |
| Consent model | Depends on the external platform. Configure consent handling in the managed package |
Troubleshooting
Messages not reaching Salesforce
- Verify the managed package is installed and configured correctly
- Check the external provider's webhook status. The webhook must be active and pointing to your Salesforce instance
- Confirm the MessagingChannel is Active: query
IsActivefield - Review the managed package logs (if available) for message delivery errors
- Verify the Interaction Service API endpoint is accessible from the provider
Channel creation fails in Setup
- Verify the Digital Engagement license is provisioned and active
- Confirm the managed package from your provider is installed
- Check that the managed package version is compatible with your org's API version
- Clear browser cache and retry if the Setup wizard stalls
Agent not responding but session is created
- Verify
SessionHandlerIdis set and points to the correct BotDefinition.Id - Check the agent is Active (not Draft) in Agent Builder
- Verify the agent's
default_agent_userhas proper permissions (Einstein Agent User profile, AgentforceServiceAgentUser permission set) - Check for errors in the agent's trace logs via Agent Builder preview
- Verify the BotVersion is published and active:
sf data query --target-org <your-org-alias> \
--query "SELECT Id, DeveloperName, Status FROM BotVersion WHERE BotDefinition.DeveloperName='Reservation_Agent' AND Status='Active' LIMIT 1"
Messages arriving but responses not reaching the external platform
- The managed package outbound webhook may be misconfigured. Check the provider's delivery status dashboard
- Verify the Named Credential for the external provider is valid and not expired
- Check for API rate limits on the external provider side
- Review Salesforce debug logs for errors in the managed package's outbound message handling
Interaction Service API errors
- Check the API version. The Interaction Service API requires a minimum Salesforce API version
- Verify the Connected App used by the managed package has the correct OAuth scopes
- Review the provider's developer documentation for known issues and required API permissions
- Test the Interaction Service API endpoint directly using the BYOC for Messaging Developer Guide
Provider managed package not appearing in channel creation
- Confirm the package installation completed successfully (Setup > Installed Packages)
- Some packages require post-installation configuration steps before they register as a channel provider
- Check for package version updates that may be required for BYOC compatibility
- Contact the provider's support for channel registration issues
Developer Resources
For custom BYOC implementations:
- BYOC for Messaging Developer Guide -- Building custom integrations using the Interaction Service API
- BYOC for CCaaS Developer Guide -- Connecting external contact centers with unified routing
- Interaction Service API Developer Guide -- API reference for message ingestion and delivery
Definition of Done
Definition of Done:
- BYOC channel active in Messaging Settings with MessageType = Custom
- Managed package from messaging provider installed and configured
- Customer can send a message through the external platform and reach the Agentforce agent
- Agent responds to the message automatically
- MessagingSession record created with correct routing to agent
- Escalation to human agent fallback queue works when agent transfers
- Responses from the agent are delivered back through the external messaging platform