agentforce-custom-channel-dev
Use this skill when building custom channel integrations with the Agentforce Agent API or BYOC (Bring Your Own Channel) for CCaaS — covering session lifecycle management, webhook handling, externalSessionKey design, sequenceId sequencing, BYOC Interaction API integration, and conversation state management. NOT for standard channels (Embedded Service, Slack, SMS/MMS via standard Messaging). NOT for agent-channel-deployment (which handles standard channel setup and activation). NOT for custom agent actions or Apex topics.
Best use case
agentforce-custom-channel-dev is best used when you need a repeatable AI agent workflow instead of a one-off prompt.
Use this skill when building custom channel integrations with the Agentforce Agent API or BYOC (Bring Your Own Channel) for CCaaS — covering session lifecycle management, webhook handling, externalSessionKey design, sequenceId sequencing, BYOC Interaction API integration, and conversation state management. NOT for standard channels (Embedded Service, Slack, SMS/MMS via standard Messaging). NOT for agent-channel-deployment (which handles standard channel setup and activation). NOT for custom agent actions or Apex topics.
Teams using agentforce-custom-channel-dev should expect a more consistent output, faster repeated execution, less prompt rewriting, better workflow continuity with your supporting tools.
When to use this skill
- You want a reusable workflow that can be run more than once with consistent structure.
- You already have the supporting tools or dependencies needed by this skill.
When not to use this skill
- You only need a quick one-off answer and do not need a reusable workflow.
- You cannot install or maintain the underlying files, dependencies, or repository context.
Installation
Claude Code / Cursor / Codex
Manual Installation
- Download SKILL.md from GitHub
- Place it in
.claude/skills/agentforce-custom-channel-dev/SKILL.mdinside your project - Restart your AI agent — it will auto-discover the skill
How agentforce-custom-channel-dev Compares
| Feature / Agent | agentforce-custom-channel-dev | Standard Approach |
|---|---|---|
| Platform Support | Not specified | Limited / Varies |
| Context Awareness | High | Baseline |
| Installation Complexity | Unknown | N/A |
Frequently Asked Questions
What does this skill do?
Use this skill when building custom channel integrations with the Agentforce Agent API or BYOC (Bring Your Own Channel) for CCaaS — covering session lifecycle management, webhook handling, externalSessionKey design, sequenceId sequencing, BYOC Interaction API integration, and conversation state management. NOT for standard channels (Embedded Service, Slack, SMS/MMS via standard Messaging). NOT for agent-channel-deployment (which handles standard channel setup and activation). NOT for custom agent actions or Apex topics.
Where can I find the source code?
You can find the source code on GitHub using the link provided at the top of the page.
SKILL.md Source
# Agentforce Custom Channel Dev
This skill activates when a practitioner needs to integrate an external system, application, or communication platform with Agentforce using the Agent API session lifecycle or the BYOC (Bring Your Own Channel) for CCaaS pattern — covering webhook design, session state management, and the sequenceId/externalSessionKey protocol. Use this skill for programmatic, API-driven integrations, not standard channel deployments.
---
## Before Starting
Gather this context before working on anything in this domain:
- Confirm whether the integration targets the raw Agent API directly (mobile apps, IVR, custom web surfaces) or uses BYOC for CCaaS (routing through Omni-Channel via Interaction API and Establish Conversation API). These use different endpoints, different auth scopes, and different record types.
- The most common wrong assumption: that context variables can be updated mid-session. They cannot. All context variables set at session creation via the `variables` payload are immutable for the entire session lifetime, with the single exception of `Context.EndUserLanguage`.
- Platform constraints: the Agent API requires the `chatbot_api` OAuth scope in addition to the standard `api` scope. Sessions are tied to a single agent and cannot be re-routed mid-session. The `externalSessionKey` must be a valid UUID (RFC 4122 format) — arbitrary strings are rejected. The `sequenceId` must be a monotonically increasing integer per session — gaps or resets cause message ordering errors.
---
## Core Concepts
### Agent API Session Lifecycle
The Agentforce Agent API follows a strict three-phase lifecycle for every conversation:
**1. Session Creation (POST)**
```
POST /services/data/v63.0/einstein/ai-agent/agents/{agentId}/sessions
```
Request body:
```json
{
"externalSessionKey": "550e8400-e29b-41d4-a716-446655440000",
"instanceConfig": {
"endpoint": "https://your-org.salesforce.com"
},
"variables": [
{ "name": "Context.Channel", "type": "Text", "value": "custom-mobile-app" },
{ "name": "Context.EndUserLanguage", "type": "Text", "value": "en_US" }
],
"bypassUser": false
}
```
The response returns a `sessionId` (Salesforce-generated UUID) distinct from the `externalSessionKey`. Store both — the `sessionId` is used for all subsequent calls; the `externalSessionKey` is your idempotency key.
**2. Message Exchange (POST with sequenceId)**
```
POST /services/data/v63.0/einstein/ai-agent/agents/{agentId}/sessions/{sessionId}/messages
```
Request body:
```json
{
"message": {
"sequenceId": 1,
"type": "Text",
"text": "Hello, I need help with my order"
},
"variables": []
}
```
The `sequenceId` must start at 1 and increment by 1 for each message in the session. The platform uses this to enforce message ordering — a duplicate or out-of-order `sequenceId` results in a 400 error.
**3. Session Termination (DELETE)**
```
DELETE /services/data/v63.0/einstein/ai-agent/agents/{agentId}/sessions/{sessionId}
```
Always call DELETE when the conversation ends. Failing to do so leaves orphaned sessions that consume platform resources and may interfere with concurrent session limits.
### externalSessionKey and Session Idempotency
The `externalSessionKey` is a caller-supplied UUID that acts as an idempotency key for session creation. If the same `externalSessionKey` is submitted to POST a second time (e.g., after a network timeout), the platform returns the existing session rather than creating a duplicate. This guarantees exactly-once session semantics even in unreliable network conditions.
Requirements:
- Must conform to UUID format (RFC 4122) — e.g., `xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx`
- Must be unique per logical conversation
- Must be generated by the caller (not the platform)
- Recommended: use a UUIDv4 generator; do not use user IDs, timestamps, or sequential integers as the key value
### BYOC for CCaaS — Interaction API vs. Raw Agent API
BYOC (Bring Your Own Channel) for CCaaS is a distinct integration pattern from the raw Agent API. It is designed for Contact Center as a Service (CCaaS) providers that want to route conversations through Salesforce Omni-Channel while leveraging Agentforce Service Agents.
The BYOC flow uses two APIs:
**Establish Conversation API** — initializes the conversation and creates or retrieves a `MessagingEndUser` record in Salesforce. This record represents the end user across Omni-Channel sessions and stores conversation history.
**Interaction API** — sends and receives messages between the external CCaaS platform and the Agentforce Service Agent through the Omni-Channel routing engine.
Key distinctions from raw Agent API:
| Dimension | Raw Agent API | BYOC for CCaaS |
|---|---|---|
| Routing | Direct to agent, no Omni-Channel | Routes via Omni-Channel queue/agent assignment |
| End-user record | No Salesforce record created | Creates/reuses `MessagingEndUser` object |
| Conversation history | External responsibility | Stored in Salesforce Messaging Session |
| Auth scope | `api` + `chatbot_api` | `api` + `chatbot_api` + Omni-Channel permissions |
| Primary API | Agent API sessions endpoint | Establish Conversation + Interaction API |
### Webhook Handling Patterns
When integrating an external system, the integration layer typically acts as a bidirectional webhook bridge:
**Inbound (external system → Agentforce):** The webhook receiver accepts messages from the external channel (IVR DTMF, mobile app text, CCaaS event), translates them to the Agent API message format, increments the `sequenceId`, and posts to the Agent API sessions endpoint.
**Outbound (Agentforce → external system):** The Agent API returns the agent's response synchronously in the POST /messages response body. Parse the `messages` array in the response to extract agent reply text and any structured data (rich content, handoff signals).
For BYOC CCaaS, Agentforce sends responses via the Interaction API push mechanism to a pre-registered webhook endpoint on the CCaaS side.
---
## Common Patterns
### Pattern 1: Direct Agent API Integration for Mobile or IVR
**When to use:** A mobile app, IVR system, or custom web surface needs to interact with an Agentforce agent programmatically without Omni-Channel routing.
**How it works:**
1. Generate a UUIDv4 as `externalSessionKey` when the user starts a conversation.
2. POST to the sessions endpoint with context variables (channel, language, user tier, etc.).
3. Store the returned `sessionId` and initialize a `sequenceId` counter at 0.
4. For each user message: increment `sequenceId`, POST to `/messages`, parse `messages[].text` from the response.
5. On conversation end (user hangs up, session timeout, explicit close): DELETE the session.
6. Handle 409 Conflict on session POST by re-using the existing `sessionId` returned in the conflict response body.
**Why not the alternative:** Using a custom Apex REST endpoint to "wrap" the agent is not supported — Apex endpoints cannot invoke the Agentforce reasoning engine or route through the Einstein Trust Layer.
### Pattern 2: BYOC for CCaaS with Omni-Channel Routing
**When to use:** A CCaaS provider (e.g., Genesys, Amazon Connect, Five9) needs to surface an Agentforce Service Agent with full Omni-Channel routing, escalation to human agents, and Salesforce-side conversation history.
**How it works:**
1. Register a BYOC channel in Salesforce Setup and obtain the channel endpoint credentials.
2. Call the Establish Conversation API from the CCaaS platform when a new customer interaction begins. Salesforce creates or matches a `MessagingEndUser` record based on the provided identifier (phone number, email, or custom external ID).
3. Route the conversation through the Interaction API — send customer messages as `INBOUND_MESSAGE` events, receive Agentforce responses as `OUTBOUND_MESSAGE` events pushed to the registered webhook.
4. When the Agentforce agent determines escalation is needed, Omni-Channel handles the transfer to a human agent queue without additional API calls from the CCaaS side.
5. On conversation close, send an `END_CONVERSATION` event via the Interaction API.
**Why not the alternative:** Using raw Agent API for CCaaS integrations loses Omni-Channel routing, supervisor monitoring, conversation history storage in Salesforce, and the escalation handoff mechanism — all of which are available only through the BYOC pathway.
### Pattern 3: Stateful Conversation Context Design
**When to use:** The integration needs to carry user context (account tier, authenticated identity, preferred language) into the Agentforce session so the agent can personalize responses from the first message.
**How it works:**
Set context variables at session creation in the `variables` array. Common variables:
```json
{
"variables": [
{ "name": "Context.Channel", "type": "Text", "value": "mobile-ios" },
{ "name": "Context.EndUserLanguage", "type": "Text", "value": "fr_FR" },
{ "name": "Context.AuthenticatedUserId", "type": "Text", "value": "003xx000001GxyzAAC" }
]
}
```
Do not attempt to update these mid-session. If the user's language preference changes during the conversation, `Context.EndUserLanguage` is the only variable that can be updated — all others are locked for the session lifetime.
For state that genuinely changes during a conversation (e.g., items added to cart), manage that state externally (in your integration layer or a Salesforce custom object) and surface it to the agent via agent actions, not session variables.
---
## Decision Guidance
| Situation | Recommended Approach | Reason |
|---|---|---|
| Mobile app or custom web surface connecting directly to Agentforce | Raw Agent API (POST/DELETE lifecycle) | Direct, low-latency path; no Omni-Channel overhead needed |
| CCaaS platform needing Omni-Channel routing and human escalation | BYOC for CCaaS (Establish Conversation + Interaction API) | Omni-Channel routing, `MessagingEndUser` record, supervisor visibility, escalation |
| IVR system sending DTMF or voice-transcribed text to Agentforce | Raw Agent API with context variable for channel type | IVR has no need for Omni-Channel queue; direct API is simpler |
| Need to inject user identity or account tier at start of session | Context variables in session POST `variables` array | Only reliable injection point; variables are immutable post-creation |
| User language changes mid-conversation | Update `Context.EndUserLanguage` only | Only this variable is mutable post-session-creation |
| Network timeout during session creation | Retry POST with same `externalSessionKey` UUID | Platform returns existing session on duplicate key — idempotent |
| Conversation ends (any reason) | Always call DELETE on session | Prevents orphaned sessions and resource leaks |
---
## Recommended Workflow
Step-by-step instructions for an AI agent or practitioner building a custom Agentforce channel integration:
1. **Determine integration pattern** — Confirm whether the use case requires raw Agent API (direct, no Omni-Channel) or BYOC for CCaaS (Omni-Channel routing, human escalation, MessagingEndUser records). These use different APIs, endpoints, and data models. Do not mix them.
2. **Configure Connected App and OAuth** — Create or verify a Connected App with OAuth scopes `api` and `chatbot_api`. For BYOC CCaaS, also confirm Omni-Channel permissions. Retrieve the Agent ID from `SELECT Id, DeveloperName FROM BotDefinition WHERE DeveloperName = 'YourAgent'` or Setup > Agentforce Agents > Agent Detail.
3. **Design session management** — Implement a UUIDv4 generator for `externalSessionKey` (one UUID per logical conversation). Initialize a per-session `sequenceId` counter starting at 0. Plan the session creation, message exchange, and DELETE lifecycle. Handle 409 Conflict on session POST by extracting `sessionId` from the conflict response.
4. **Define context variables** — Determine which context variables to inject at session start (`Context.Channel`, `Context.EndUserLanguage`, authenticated user identifiers, account tier). Document that all variables except `Context.EndUserLanguage` are immutable for the session lifetime. Plan external state management for data that changes during a conversation.
5. **Implement webhook or event handling** — For raw Agent API: parse the synchronous `messages` array in POST /messages responses. For BYOC CCaaS: register the inbound webhook endpoint, implement the Establish Conversation API call, and handle `OUTBOUND_MESSAGE` push events from the Interaction API.
6. **Implement graceful session termination** — Ensure DELETE is called on session end in all code paths including timeouts, user drop-offs, errors, and explicit closes. Implement a session registry or TTL-based cleanup job for sessions that did not receive a DELETE.
7. **Test sequenceId sequencing and error handling** — Validate that sequenceId increments correctly with no gaps. Test retry behavior using the same `externalSessionKey`. Verify that context variables injected at creation are present in early agent responses. Test DELETE and confirm the session is no longer accessible.
---
## Review Checklist
Run through these before marking work in this area complete:
- [ ] `externalSessionKey` is generated as a valid UUIDv4 (not a user ID, timestamp, or sequential integer)
- [ ] `sequenceId` starts at 1 and increments by exactly 1 per message with no gaps or resets within a session
- [ ] Connected App includes both `api` and `chatbot_api` OAuth scopes
- [ ] Context variables are injected only at session creation; no code attempts to update non-language variables mid-session
- [ ] DELETE is called on session termination in all code paths (success, error, timeout, user drop)
- [ ] For BYOC CCaaS: Establish Conversation API is called before any Interaction API messages; `MessagingEndUser` record creation is handled
- [ ] Integration pattern (raw Agent API vs. BYOC CCaaS) is documented and the correct endpoints and auth are used for each
- [ ] Session creation retries use the same `externalSessionKey` UUID (not a new one) to leverage idempotency
---
## Salesforce-Specific Gotchas
Non-obvious platform behaviors that cause real production problems:
1. **sequenceId gaps cause 400 errors** — The platform enforces monotonically increasing sequenceIds with no gaps. If message 3 fails to send and the integration retries as message 4 without re-sending message 3, the session is corrupted and subsequent messages will be rejected. Always retry the failed message with the same sequenceId before incrementing.
2. **Context variables are immutable at session start (except EndUserLanguage)** — Variables passed in the `variables` array at session creation cannot be changed for the lifetime of the session. The only exception is `Context.EndUserLanguage`, which can be updated via a subsequent API call. Attempting to "update" other variables mid-session has no effect — the original values are retained.
3. **externalSessionKey must be a UUID** — The platform validates UUID format on session POST. Strings that look like session IDs (e.g., `user-123-conversation-456`, ISO timestamps, numeric IDs) are rejected with a 400 validation error. Use a proper UUIDv4 generator.
4. **BYOC CCaaS uses Interaction API, not raw Agent API** — BYOC integrations do not call the Agent API sessions endpoint directly. They use the Establish Conversation API and Interaction API, which have different base paths, different event schemas, and different authentication requirements. Mixing the two APIs in a single integration causes session state errors and routing failures.
5. **Orphaned sessions from missing DELETE** — Sessions not explicitly closed via DELETE remain active on the platform and count against concurrent session limits. In high-volume integrations (IVR, mobile), failure to call DELETE for dropped calls or timed-out sessions depletes the session pool. Implement a TTL-based background cleanup job.
---
## Output Artifacts
| Artifact | Description |
|---|---|
| Session management implementation | Code or pseudocode for session POST, message POST with sequenceId tracking, and session DELETE |
| externalSessionKey generator | UUIDv4 generation snippet with idempotency retry logic |
| Context variable injection plan | List of variables to inject at session creation with types and source data |
| Webhook endpoint design | Inbound/outbound message routing logic for raw Agent API or BYOC Interaction API |
| BYOC integration plan | Establish Conversation API call sequence, MessagingEndUser record handling, Omni-Channel routing config |
| Session cleanup job | TTL-based or event-driven job to DELETE orphaned sessions |
---
## Related Skills
- `agentforce/agent-channel-deployment` — use for standard channel setup (Embedded Service widget, Slack, standard Messaging), NOT for programmatic API integrations
- `agentforce/custom-agent-actions-apex` — use when building Apex-based agent actions that the Agentforce agent calls during a session; this skill handles the session/channel layer, not the action layer
- `agentforce/agentforce-agent-creation` — use for UI-driven agent setup, topic assignment, and activation in Setup before implementing any channel integration
- `integration/api-led-connectivity` — use when the external system connects to Salesforce through MuleSoft or an API gateway layer rather than directly to the Agent API
---
## Official Sources Used
- Agentforce Agent API Session Lifecycle — https://developer.salesforce.com/docs/einstein/genai/guide/agent-api-session-lifecycle.html
- Bring Your Own Channel for CCaaS Agentforce Service Agent — https://developer.salesforce.com/docs/einstein/genai/guide/byoc-ccaas-agentforce.html
- Agentforce Developer Guide — https://developer.salesforce.com/docs/einstein/genai/guide/agentforce.html
- Einstein Platform Services — https://developer.salesforce.com/docs/einstein/genai/guide/overview.html
- Salesforce Well-Architected Overview — https://architect.salesforce.com/docs/architect/well-architected/guide/overview.htmlRelated Skills
customer-data-request-workflow
Implement GDPR/CCPA data subject rights (access, deletion, rectification) using Salesforce Privacy Center and/or custom workflow. NOT for general backup or org-level data retention policy.
omnistudio-custom-lwc-elements
Creating and integrating custom Lightning Web Components within OmniScripts: LWC override patterns, pubsub event handling, custom validation, OmniStudio data passing conventions. Use when a standard OmniScript element cannot meet a UX requirement. NOT for standalone LWC development (use lwc/* skills). NOT for Integration Procedures (use integration-procedures). NOT for embedding an OmniScript inside an LWC (use omnistudio-lwc-integration).
message-channel-patterns
Use when implementing Lightning Message Service (LMS) to enable cross-DOM communication between LWC, Aura, and Visualforce components on the same Lightning page, using message channels. Triggers: 'communicate between unrelated LWC components', 'send data between Visualforce and LWC', 'lightning message service not working', 'APPLICATION_SCOPE vs default scope', 'message channel metadata deployment'. NOT for parent-child component communication (use component-communication) or server-side events.
lwc-custom-lookup
Custom lookup component in LWC — typeahead/autocomplete that searches records via Apex SOSL/SOQL, shows pills, supports keyboard navigation, and manages open/close state. Use when lightning-input-field or lightning-record-picker won't work (cross-org search, computed filters, custom result rendering). NOT for in-form lookups inside lightning-record-edit-form (use lightning-input-field) or lookup filters (use admin lookup filter config).
lwc-custom-event-patterns
When and how to design CustomEvent traffic out of an LWC — bubbles / composed / cancelable flag choices, detail payload shape, naming rules, and propagation control. Trigger keywords: 'event not reaching parent', 'composed shadow DOM', 'CustomEvent detail mutation', 'stopPropagation vs stopImmediatePropagation'. NOT for parent-to-child communication (use `@api` — see `lwc/component-communication`), NOT for sibling fan-out (use Lightning Message Service — see `lwc/lightning-message-service`), NOT for wire-service data plumbing.
lwc-custom-datatable-types
Use when you need to extend `lightning-datatable` with custom cell renderings: status pills, progress bars, image thumbnails, action cells, editable pickliststo, rich-text, or any column that `lightning-datatable` does not ship out of the box. Triggers: 'custom cell type lightning datatable', 'progress bar column', 'image column', 'inline edit picklist in datatable', 'rich text column'. NOT for basic datatable usage (see `lwc-data-table`) and NOT for tree-grid or large-dataset virtualization (see `virtualized-lists`).
experience-cloud-search-customization
Use this skill when configuring or extending search on an Experience Cloud site — covering Search Manager scope configuration, LWR vs Aura search component selection, federated search setup, guest user search access, and custom search result components. NOT for SOSL/SOQL query development. NOT for internal Salesforce global search or Einstein Search for agents.
custom-property-editor-for-flow
Use when building or reviewing an LWC Custom Property Editor for Flow screen or action configuration, including the `configurationEditor` metadata hook, builder-side APIs, validation, and value-change events. Triggers: 'custom property editor', 'Flow configuration editor', 'builderContext', 'inputVariables', 'configurationEditor'. NOT for ordinary runtime screen-component behavior when no Flow Builder design-time customization is involved.
flow-custom-property-editors
Use when designing or reviewing Flow custom property editor patterns for screen components or actions, including when Flow Builder needs guided design-time configuration, generic type mapping, or builder-context-aware validation. Triggers: 'Flow custom property editor', 'configurationEditor', 'builderContext', 'inputVariables', 'Flow screen component setup'. NOT for general LWC runtime behavior when Flow Builder customization is not involved.
feature-flag-custom-metadata
Implement environment-safe feature flags using Custom Metadata Types for Apex, LWC, and Flow. NOT for user-level entitlements or permission sets.
omni-channel-reporting-data
Omni-Channel analytics data: agent work records, queue metrics, capacity utilization, wait time reporting. NOT for admin routing setup.
custom-index-requests
Use when standard Salesforce indexes are insufficient for query performance on high-volume objects: requesting custom indexes via Salesforce Support for standard fields, deploying custom field indexes via Metadata API, requesting skinny tables, or designing two-column composite indexes. NOT for SOQL query optimization techniques (use data/soql-query-optimization) or general large data volume design (use architect skills).