forcedotcom/sf-skills7 files

Service De Channel Routing Configure

Configure routing on a newly-inserted Enhanced `MessagingChannel` so activation will accept it. Given a `{CHANNEL_ID}`, walks through picking a routing type (Omni-Channel Queue, Omni-Flow, Agentforce Service Agent, Digital Worker, or direct User), locates or provisions the target, then PATCHes `SessionHandlerId` (plus `FallbackQueueId` where required). Use between insertion and activation — activation fails server-side with `nullQueueId`/`LiveMessageSetupException` if no valid `SessionHandlerId` is set. Do not use for full end-to-end setup — use `service-de-headless-channel-configure`.

Specification
Skill ID
forcedotcom/sf-skills/service-de-channel-routing-configure
Publisher
forcedotcom
Repository
sf-skills
Installs
0
Files
7
Synced
Sep 23, 2026
How to use it

Open any RiverX project, open the Skills panel in the chat, and search for this identifier. The files are fetched from the source repository at install time.

forcedotcom/sf-skills/service-de-channel-routing-configureInstalls these files
  • SKILL.md
  • references/asa-routing.md
  • references/gotchas.md
  • references/queue-creation.md
  • references/target-locate.md
  • references/worked-examples.md
  • scripts/tests/test_skill_contract.py

What this skill tells the agent

Configuring Channel Routing

What this skill does

Ensures a MessagingChannel has valid routing configured before activation. The channel's SessionHandler field is a polymorphic foreign key (verified against MessagingChannel.entity.xml, domain="Queue, FlowDefinition, User, BotDefinition, AgenticCtxtDecorDefinition") — it names who the channel routes incoming sessions to. Some targets additionally require a FallbackQueue (an Omni-Channel Queue that catches sessions the primary target can't take).

These skills create Enhanced channels (PlatformType=Enhanced, SCRT2). All five SessionHandler domains are writable on Enhanced channels. (A Standard/SCRT1 channel would only accept a Flow as SessionHandler — the server rejects any other domain with "Only flows of type Omni-Channel are supported". These skills never create Standard channels, so that path isn't handled here.)

Where this fits: the channel is inserted by service-de-channel-create (or a per-type leaf); this skill sets routing; service-de-channel-settings-configure sets consent; then service-de-channel-activate flips it live — activation requires both routing and consent. The service-de-headless-channel-configure orchestrator runs all four in sequence.

Supported routing types — all set SessionHandlerId, some also set FallbackQueueId:

TypeSessionHandler targetId prefixFallbackQueue
Omni-Channel QueueGroup (Type=Queue)00Gmust be null
Omni-FlowFlowDefinition (ProcessType=RoutingFlow)300required
Agentforce Service Agent (ASA)BotDefinition (Type=ExternalCopilot)0Xxrequired
Digital WorkerAgenticCtxtDecorDefinition1iErequired
UserUser (with a RoutingConfiguration)005must be null

Provisioning behavior:

  • Queue — pick an existing MessagingSession-capable Queue, or create a new Queue + QueueRoutingConfig via Metadata API.
  • Flow / ASA / Digital Worker / User — locate an existing eligible target and PATCH it. These skills do not create Flows, bots, digital workers, or users — if none eligible exist, the skill reports the precondition and points the user at Setup.

Reference File Index

Reference fileLoad when
references/queue-creation.mdThe user picked "create a new queue" on the Queue routing path — full Metadata API scaffold → deploy → ID lookup → optional member add.
references/target-locate.mdYou need the per-domain SOQL to locate and validate an eligible target (Queue, Flow, ASA, Digital Worker, User) and the FallbackQueue requirement matrix.
references/asa-routing.mdThe user picked ASA (Agentforce Service Agent) routing — precondition check, enumerating live ASAs, and selection.
references/gotchas.mdTroubleshooting an unexpected result, or before modifying this skill — the known gotchas.
references/worked-examples.mdYou want a reference run of the reuse-existing-queue, create-new-queue, Flow, or ASA paths.

When NOT to use this skill

  • The channel already has `SessionHandlerId` or `FallbackQueueId` set. This skill revalidates the existing target before no-op. An ASA must still have a BotUser and an Active BotVersion; otherwise it reports asa-target-inactive and does not claim readiness.
  • The channel doesn't exist yet. Run the insertion skill first; this skill expects a real MessagingChannel.Id.
  • You want to replace existing routing. Safer to clear SessionHandlerId manually in the UI, then re-run this skill. The no-op check is a guardrail, not a limitation worth bypassing automatically.

Inputs (from caller)

  • {CHANNEL_ID} — a 15- or 18-char MessagingChannel.Id (prefix 0Mj). The channel must already exist.
  • {ORG_ALIAS} — optional; the sf CLI target-org alias. Default: whatever sf config get target-org returns. All SOQL, PATCH, and Metadata deploys run against this org.

Output (to caller)

One of:

Success — no change needed:

{"ok": true, "noop": true, "routingType": "queue|flow|asa|digital_worker|user", "sessionHandlerId": "00G...|300...|0Xx...|1iE...|005...", "fallbackQueueId": "00G...|null", "targetName": "...", "message": "Routing already configured"}

Success — Queue routing configured:

{"ok": true, "routingType": "queue", "sessionHandlerId": "00G...", "fallbackQueueId": null, "queueName": "...", "queueDeveloperName": "...", "created": true|false}

Success — Flow routing configured:

{"ok": true, "routingType": "flow", "sessionHandlerId": "300...", "fallbackQueueId": "00G...", "flowName": "...", "flowDeveloperName": "...", "created": false}

Success — ASA routing configured:

{"ok": true, "routingType": "asa", "sessionHandlerId": "0Xx...", "fallbackQueueId": "00G...", "asaName": "...", "asaDeveloperName": "...", "botUserId": "005...", "botVersionId": "0X9...", "created": false}

Success — Digital Worker routing configured:

{"ok": true, "routingType": "digital_worker", "sessionHandlerId": "1iE...", "fallbackQueueId": "00G...", "workerName": "...", "created": false}

Success — User routing configured:

{"ok": true, "routingType": "user", "sessionHandlerId": "005...", "fallbackQueueId": null, "userName": "...", "created": false}

Precondition not met:

{"ok": false, "kind": "no-eligible-target", "routingType": "flow|asa|digital_worker|user", "hint": "no eligible <target> found on this org — <how to create one in Setup>, then re-run this skill"}
{"ok": false, "kind": "no-fallback-queue", "hint": "Flow/ASA/Digital Worker routing requires a FallbackQueue but no MessagingSession-capable queue exists — create one (Queue routing path) first"}
{"ok": false, "kind": "asa-not-supported", "hint": "this org doesn't have BotDefinition (Agentforce not licensed); use Queue routing instead"}
{"ok": false, "kind": "standard-channel", "hint": "this is a Standard (SCRT1) channel — only Flow routing is supported; these skills only create Enhanced channels, so this is unexpected"}

Failure:

{"ok": false, "kind": "metadata-deploy-failed", "message": "..."}
{"ok": false, "kind": "patch-failed", "message": "..."}
{"ok": false, "kind": "verify-failed", "hint": "PATCH returned success but re-read shows SessionHandlerId still null — permission or trigger issue"}

The PATCH failure message often carries the server-side validation error verbatim (from MessagingChannelFunctionsHelper.validateSessionHandler). Surface it — it tells the user exactly which linking rule failed. Common ones: MissingFallbackQueueForFlowRouting / ...ForAsaRouting / ...ForDigitalWorkerRouting (FallbackQueue required but null), UnsupportedFallbackQueue (FallbackQueue set on a Queue/User path where it must be null), InvalidSessionHandlerFlowType (Flow isn't ProcessType=RoutingFlow, or the channel is Standard/SCRT1), NoRoutingConfigDefined (User has no RoutingConfiguration).


Stage 1: Read current routing state

Query the channel. If it already has SessionHandlerId OR FallbackQueueId, no-op. Otherwise, continue.

sf data query --target-org '{ORG_ALIAS}' \
  --query "SELECT Id, DeveloperName, SessionHandlerId, FallbackQueueId FROM MessagingChannel WHERE Id = '{CHANNEL_ID}'" \
  --json > /tmp/ccr-channel.json

Parse with node -e or jq. If the record is missing — halt with Error: Channel {CHANNEL_ID} not found — check the id, or run the insertion skill first.

If SessionHandlerId is non-null, branch on the Id prefix to figure out what the existing routing target is, then no-op with the right envelope. The prefix maps 1:1 to the SessionHandler domain (verified against MessagingChannel.entity.xml). Existing routing is not automatically healthy: the target lookup must return exactly one eligible row before reporting a successful no-op.

More from forcedotcom

Use this skill in a project

Open any RiverX project, search the Skills panel for forcedotcom/sf-skills/service-de-channel-routing-configure, and install it in one click.

Use this skill