Come usare
- Copia il comando e controlla il pacchetto prima di installarlo nel tuo ambiente agente.
- Controlla strumenti, credenziali e ambienti richiesti nel documento originale.
- Descrivi input e risultato desiderato; confronta l’output con le fonti.
npx skills add https://github.com/sshvarzman-salesforce/claude-skills --skill connecting-channels-to-asaPrima di iniziare
- L’installazione non include abbonamenti, quote API o accesso ai file.
- Stelle e installazioni indicano attività, non un test indipendente di qualità o sicurezza.
Contenuto dal repository con titoli, esempi, codice, tabelle, link e immagini preservati.
Connecting Voice + Messaging Channels to an ASA (inbound + escalation)
What this skill is for
An ASA needs wiring on both ends of a conversation, on both channels:
INBOUND (customer → agent) ESCALATION (agent → human)
VOICE inbound omni-flow → routeWork Copilot → agent | escalation flow → routeWork QueueBased/Skills → human
⤷ bound in SETUP (voice channel) | ⤷ bound in SETUP (voice channel)
MESSAGING inbound omni-flow → routeWork Copilot → agent | escalation flow → routeWork QueueBased/Skills → human
⤷ bound on the MessagingChannel metadata | ⤷ bound in the AGENT .agent metadataThat's four flows and two very different binding stories. This skill is the map — it tells you which flow you need, which target to route to, and where the binding lives (metadata vs. Setup). The full deployable XML lives in the deep-dive skills; this skill keeps you from wiring the wrong thing to the wrong place.
The deep-dive skills (this skill routes you to them)
- `routing-inbound-messaging-to-agentforce-agent` — INBOUND messaging: the RoutingFlow (resolve Contact from pre-chat phone → link
MessagingEndUser.ContactId→routeWorkCopilot), theEmbeddedMessagingchannel with the custom pre-chat param, and the Setup-only Embedded Service deployment. Full XML in itsassets/. - `replicating-omnichannel-routing-flows` — ESCALATION (both channels): the
routeWorkQueueBasedflows that hand a live conversation to a human queue, with complete voice + messaging XML templates inassets/and the queue-Id-is-org-specific porting procedure. - `building-voice-asa-agent` — the ASA build spine; its step 9 sketches the inbound voice omni-flow and the per-channel escalation binding, and step 10 is the voice Setup handoff.
The four flows at a glance
| Flow | ProcessType | Reads/links | routeWork target | Where it binds |
|---|---|---|---|---|
| Voice inbound | RoutingFlow | VoiceCall.FromPhoneNumber → findMatchingIndividuals(Phone, Contact) → set VoiceCall.Contact__c + RelatedRecordId | routingType=Copilot, copilotId→BotDefinition, serviceChannelDevName=sfdc_phone | Setup (voice channel inbound flow) |
| Messaging inbound | RoutingFlow | pre-chat CustomerPhone → findMatchingIndividuals → set `MessagingEndUser.ContactId` (parent) | routingType=Copilot, copilotId→BotDefinition, serviceChannelDevName=sfdc_livemessage | `MessagingChannel.sessionHandlerFlow` (metadata) |
| Voice escalation | RoutingFlow | update VoiceCall.Escalated_to_Human__c=true (+ KPI stamps) | routingType=QueueBased/skills, serviceChannelDevName=sfdc_phone | Setup (voice channel escalation flow) |
| Messaging escalation | RoutingFlow | update MessagingSession.Escalated_to_Human__c=true (+ KPI stamps) | routingType=QueueBased/skills, serviceChannelDevName=sfdc_livemessage | Agent `.agent` connection block (metadata) |
Every one is a ProcessType=RoutingFlow with an isInput recordId variable and a bare start (connector only, no triggerType). RoutingFlows reject <runInMode> — they already run system context; adding the tag fails the deploy.
INBOUND: getting the call/chat to the agent
Both inbound flows do the same three things — read the conversation record, resolve the caller's Contact and link it, then routeWork to the agent — and differ only in how the caller's phone arrives and which record holds the Contact link.
routeWork for inbound-to-agent:
| Param | Value |
|---|---|
recordId | elementReference → recordId (the VoiceCall / MessagingSession) |
routingType | `Copilot` (not QueueBased — that's escalation) |
serviceChannelDevName + serviceChannelId | sfdc_phone (voice) / sfdc_livemessage (messaging) |
copilotId | setupReference = <Agent_Api_Name>, setupReferenceType = `BotDefinition` |
queueId | a real Group.Id — the fallback queue if the agent can't take it |
Resolve the agent: sf data query --json -q "SELECT Id, DeveloperName FROM BotDefinition WHERE DeveloperName='<Agent_Api_Name>'" (BotDefinition is queryable).
- Messaging inbound — see
routing-inbound-messaging-to-agentforce-agentfor the full flow + channel + deployment. Link the Contact on `MessagingEndUser.ContactId` (the session'sEndUserContactIdfills in automatically; there is noContact__con MessagingSession). The channel'ssessionHandlerFlow= this flow — that binding is pure metadata. - Voice inbound — same shape but reads
VoiceCall.FromPhoneNumberand writesVoiceCall.Contact__c+RelatedRecordId = Contact.Id. Seebuilding-voice-asa-agentstep 9. The flow deploys by metadata, but which flow the voice channel calls is a Setup binding (below).
ESCALATION: handing the conversation to a human — queue, skill, or direct rep
On @utils.escalate the agent invokes the channel's escalation flow. The flow flips Escalated_to_Human__c (and, if you're tracking KPIs, stamps Entered_Queue_Timestamp__c — see building-contact-center-kpis-agentwork) and then routeWorks to a human. Three destinations, chosen by the routeWork params:
A) To a QUEUE (routingType=QueueBased)
The default and simplest. Route to an Omni queue's Group.Id.
routingType = QueueBased
queueId = <Group.Id of the queue> (org-specific — look up by DeveloperName)
queueLabel = <display label>
serviceChannelDevName = sfdc_phone | sfdc_livemessageFull XML: replicating-omnichannel-routing-flows (assets/escalation-routingflow-voice.flow-meta.xml, ...-messaging.flow-meta.xml).
B) To a SKILL (skills-based routing)
Route on required skills instead of a fixed queue — Omni matches an available agent who has them.
routingType = SkillsBased
serviceChannelDevName = sfdc_phone | sfdc_livemessage
skillRequirementsResourceItem = <a collection of skill-requirement rvars>Build the skill-requirement collection by looping the target Skill Ids into routeWork's skills input (the pattern in calling-prompt-templates-in-flows / the NewRez skills-routing flow: Get_Skill → build requirement rvar → Add to the collection → routeWork with skillRequirementsResourceItem). Use this when "who can take it" depends on capability (language, product, tier), not a static queue.
C) DIRECT to a specific rep (agent-based routing)
Route straight to one named user (e.g. a relationship manager, a named specialist).
routingType = AgentBased (route to a specific Omni-Channel-enabled user)
userId / agentId = <the User Id> (as a routeWork input)
serviceChannelDevName = sfdc_phone | sfdc_livemessage
fallback queueId = <Group.Id> (still supply a fallback in case the rep is unavailable)Direct-to-rep is the most brittle — the rep must be present and Omni-available — so always include a fallback queue. Prefer skills-based (B) over hardcoding a user unless the demo specifically needs "always goes to this person."
Whatever the target, the escalation flow'srecordUpdateobject MUST match the channel:VoiceCallfor the voice flow,MessagingSessionfor the messaging flow. A messaging escalation gets aMessagingSessionrecordId — pointing it at the voice flow (which filters/updatesVoiceCall) fails at runtime. One escalation flow per channel, always.
THE BINDING — the part everyone gets wrong
Deploying a RoutingFlow Active does nothing until the channel is told to use it. And the two channels bind completely differently:
Messaging — binds in metadata ✅ (Claude can do it end to end)
- Inbound: set
MessagingChannel.sessionHandlerFlow = <inbound flow>(+sessionHandlerQueuefallback). Deploy the channel. - Escalation: set it in the agent `.agent`
connectionblock and re-publish + re-activate the agent:
connection customer_web_client:
outbound_route_name: "flow://<Messaging_Escalation_Flow>"
outbound_route_type: "OmniChannelFlow"
escalation_message: "Please hold while I transfer you to a representative."Voice — binds in Setup 🧑 (NOT metadata-settable — hand the user a runbook)
Both the voice inbound flow and the voice escalation flow are bound at the Service Cloud Voice channel in Setup — SessionHandlerId / FallbackQueueId and the flow assignments are not API/metadata-writable. Do not promise a "deploy" for these; deliver a runbook:
Setup → the Service Cloud Voice channel → set inbound flow →<Voice_Inbound_Omniflow>and escalation flow →<Voice_Escalation_Flow>.
⚠️ The voice .agent connection telephony.outbound_route_name often points at the inbound omni-flow (the flow that brings the call to the agent), not the voice escalation flow. Do not overwrite it to "add" voice escalation — that breaks inbound voice. Voice escalation lives in Setup; leave telephony alone.
| Inbound bind | Escalation bind | |
|---|---|---|
| Messaging | MessagingChannel.sessionHandlerFlow (metadata) | agent .agent connection … outbound_route_name (metadata) |
| Voice | Setup (voice channel inbound flow) | Setup (voice channel escalation flow) |
Build order (per channel)
- Confirm the field the escalation flow sets (
Escalated_to_Human__c, plus any KPI fields) exists + FLS-editable on the conversation object — create first if missing, or the flow'srecordUpdatewon't deploy. - Author + deploy the inbound RoutingFlow and the escalation RoutingFlow (Active) — voice and/or messaging, from the deep-dive skills' assets. Swap the org-specific
queueIds. - Bind: messaging inbound → channel metadata; messaging escalation → agent metadata (re-publish/activate); voice inbound + escalation → Setup runbook to the user.
- Verify each flow Active (
FlowDefinitionView ProcessType=RoutingFlow, IsActive=true, standard API — not--use-tooling-api),copilotIdresolves to the agent, escalationqueueId/skills/userId resolve.
Verification checklist
- Four flows (or the two for your single channel) deployed Active,
ProcessType=RoutingFlow, norunInModetag,recordIdisInput. - Inbound:
routingType=Copilot,copilotId→BotDefinition; contact linked on the right record (VoiceCall.Contact__c/MessagingEndUser.ContactId). - Escalation:
routingTypematches the chosen target (QueueBased / SkillsBased / AgentBased); target resolves in-org;recordUpdateobject matches the channel; fallback queue present for skills/direct-rep. - Bindings: messaging inbound on the channel, messaging escalation in the agent metadata (re-published); voice both in Setup; telephony
outbound_route_nameleft untouched. - Per-channel confirmed end to end: a voice call reaches the agent and escalates to a human on voice; a chat reaches the agent and escalates on messaging — never cross-wired.
Gotchas (hard-won)
- Messaging escalation pointed at the voice flow = runtime failure. Messaging gets a
MessagingSessionId; the voice flow filtersVoiceCall. One flow per channel. - Voice binding is Setup-only. It is not metadata. Don't promise a deploy; hand the user the Setup runbook.
- Don't overwrite telephony `outbound_route_name` — it's usually the inbound flow. Voice escalation is a separate Setup binding.
- Queue Ids are per-org. A copied escalation flow validates + deploys with a stale
queueIdand then silently routes nowhere. Look the queue up byDeveloperNameand swap the Id. (replicating-omnichannel-routing-flows.) - `routingType=Copilot` is inbound; `QueueBased`/`SkillsBased`/`AgentBased` is escalation. Mixing them is the usual "agent won't pick up" / "escalation goes nowhere" cause.
- `FlowDefinitionView` is standard API (
ApiName/ProcessType/IsActive). Querying it--use-tooling-apithrowsINVALID_TYPE. - Direct-to-rep needs a fallback queue — a specific user is often Omni-unavailable; without a fallback the escalation dead-ends.


