Help & Support
Elevate Your Agents with AgentExchange Solutions
Have Questions?
Service De Channel Consent Configure
- references/
- SKILL.md
Configuring Channel Consent
What this skill does
Ensures an Enhanced MessagingChannel has valid consent configured before activation. Consent has two parts, and both are checked by the server-side activation-readiness gate (MessagingChannelReadinessChecker.isConsentConfiguredForChannel):
Channel-level fields on
MessagingChannel:ConsentType— static enum:ImplicitOptIn,ExplicitOptIn, orDoubleOptIn.OptInPrompt— message sent when an end-user reply doesn't match an opt-in keyword (required for ExplicitOptIn/DoubleOptIn, except on Unified SMS / WhatsApp / RCS where it's optional).DoubleOptInPrompt— message sent when a reply doesn't match a double-opt-in keyword (required for DoubleOptIn).IsRequireDoubleOptIn— boolean flag; set true alongsideConsentType=DoubleOptIn.
Per-language keyword records — one or more
MsgChannelLanguageKeywordchild rows (master-detail toMessagingChannel, key prefix3Or). Each holds the keywords an end-user sends (opt-in, double-opt-in, opt-out, help, custom) and the confirmation replies, for one language. Keyword fields are comma-separated strings (e.g."STOP,UNSUBSCRIBE,CANCEL").
Consent is never a no-op for activation. Even ImplicitOptIn requires at least one MsgChannelLanguageKeyword with an opt-out keyword + opt-out confirmation. (The one exception is an outbound-only channel, which the readiness check passes automatically.)
Consent settings apply only to Enhanced channels (PlatformType=Enhanced) of a supported message type. On a Standard channel these fields aren't used; this skill only touches Enhanced channels.
Where this fits
This skill runs between routing and activation in the Enhanced-channel setup pipeline. service-de-channel-routing-configure sets the channel's SessionHandler; this skill configures consent; then service-de-channel-activate flips the channel live. The activation readiness check requires both routing and consent, so run this before activating. The service-de-headless-channel-configure orchestrator sequences all three automatically — invoke this skill directly only when you want to configure consent on its own.
Reference File Index
| Reference file | Load when |
|---|---|
references/language-keywords.md |
Creating or updating the per-language MsgChannelLanguageKeyword records — full field list, CSV keyword semantics, create-vs-update logic, and the Unified-SMS help/custom-keyword rules. |
references/gotchas.md |
Troubleshooting an unexpected result, or before modifying this skill. |
references/worked-examples.md |
You want a reference run of the ImplicitOptIn, ExplicitOptIn, or DoubleOptIn paths. |
When NOT to use this skill
- The channel isn't Enhanced. Consent fields apply to Enhanced channels only. This skill confirms
PlatformType=Enhancedand stops otherwise. - The channel is outbound-only. Outbound-only channels pass the consent-readiness check automatically; there's nothing to configure.
- The channel doesn't exist yet. Run the insertion skill first; this skill expects a real
MessagingChannel.Id.
Inputs (from caller)
{CHANNEL_ID}— a 15- or 18-charMessagingChannel.Id(prefix0Mj). Must already exist and be Enhanced.{CONSENT_TYPE}— optional; one ofImplicitOptIn|ExplicitOptIn|DoubleOptIn. If omitted, the skill prompts.{LANGUAGE}— optional; theMasterLanguagefor the keyword record (e.g.en_US). Defaults toen_USif not provided.{ORG_ALIAS}— optional;sfCLI target-org alias. Default: whateversf config get target-orgreturns.
The individual keyword/confirmation/prompt values are collected interactively in Stage 3–4 (or accepted from the caller if pre-supplied).
Output (to caller)
Success — no change needed:
{"ok": true, "noop": true, "consentType": "ImplicitOptIn|ExplicitOptIn|DoubleOptIn", "languageKeywordIds": ["3Or..."], "message": "Consent already configured and activation-ready"}
Success — consent configured:
{"ok": true, "consentType": "ExplicitOptIn", "channelFieldsSet": ["ConsentType","OptInPrompt"],
"languageKeywordId": "3Or...", "language": "en_US", "created": true|false, "activationReady": true}
Precondition / validation not met:
{"ok": false, "kind": "not-enhanced", "hint": "consent fields apply to Enhanced channels only; this channel is PlatformType=<x>"}
{"ok": false, "kind": "missing-consent-input", "hint": "<which required keyword/prompt for the chosen ConsentType is missing>"}
Failure:
{"ok": false, "kind": "channel-patch-failed", "message": "..."}
{"ok": false, "kind": "keyword-record-failed", "message": "..."}
{"ok": false, "kind": "verify-failed", "hint": "writes returned success but a re-read shows the channel is still not consent-ready"}
Stage 1: Read current consent state
Read the channel's consent fields and any existing language-keyword records.
sf data query --target-org '{ORG_ALIAS}' \
--query "SELECT Id, DeveloperName, PlatformType, MessageType, MessagingPlatformKey, ConsentType, OptInPrompt, DoubleOptInPrompt, IsRequireDoubleOptIn FROM MessagingChannel WHERE Id = '{CHANNEL_ID}'" \
--json > /tmp/cc-channel.json
sf data query --target-org '{ORG_ALIAS}' \
--query "SELECT Id, MasterLanguage, OptInKeywords, DoubleOptInKeywords, OptInConfirmation, OptOutKeywords, OptOutConfirmation, HelpKeywords, HelpResponse, CustomKeywords, CustomResponse FROM MsgChannelLanguageKeyword WHERE MessagingChannelId = '{CHANNEL_ID}'" \
--json > /tmp/cc-keywords.json
If the channel record is missing — halt with Error: Channel {CHANNEL_ID} not found — check the id, or run the insertion skill first.
If PlatformType != 'Enhanced' — emit {ok:false, kind:"not-enhanced", ...} and stop.
No-op check: if ConsentType is non-null AND the existing language-keyword records already satisfy the readiness matrix for that ConsentType (see Stage 5), emit the noop:true envelope and return. Don't re-prompt or overwrite a channel that is already activation-ready.
Stage 2: Choose the ConsentType
If {CONSENT_TYPE} wasn't supplied, prompt (do NOT auto-pick):
Channel '{developerName}' ({CHANNEL_ID}) — choose a consent model:
1) ImplicitOptIn — end users are opted in by default; you only handle opt-OUT (STOP) keywords.
2) ExplicitOptIn — end users must send an opt-in keyword before you can message them.
3) DoubleOptIn — explicit opt-in plus a second confirming keyword.
Pick [1-3]:
Record {CONSENT_TYPE}. Note the field checks that follow (this is the exact server-side activation-readiness contract — see references/gotchas.md for the source):
| ConsentType | MessagingChannel fields | MsgChannelLanguageKeyword (≥1 record) |
|---|---|---|
| ImplicitOptIn | (none required) | OptOutKeywords + OptOutConfirmation |
| ExplicitOptIn | OptInPrompt¹ |
above + OptInKeywords |
| DoubleOptIn | OptInPrompt¹ + DoubleOptInPrompt + IsRequireDoubleOptIn=true |
above + DoubleOptInKeywords |
¹ OptInPrompt is optional (not required for readiness) on Unified SMS / WhatsApp / RCS channels — detect via MessageType IN ('Text','WhatsApp','Rcs') on an Enhanced channel (the queryable proxy for the server's isUnifiedSMSOrWhatsappOrRCS). Still recommend setting it for a good end-user experience.
Stage 3: Collect channel-level prompt values
Only prompt for the fields the chosen ConsentType requires (see the matrix above). Skip this stage entirely for ImplicitOptIn — it needs no channel-level prompt fields.
For ExplicitOptIn / DoubleOptIn:
Opt-in prompt (sent when a reply doesn't match an opt-in keyword):
For DoubleOptIn, also:
Double-opt-in prompt (sent when a reply doesn't match a double-opt-in keyword):
Trim whitespace. If a required prompt is empty after trimming, re-prompt once; on a second empty, emit {ok:false, kind:"missing-consent-input", hint:"..."}.
Stage 4: Configure the per-language keyword record
Collect the keyword lists and confirmation replies for {LANGUAGE} (default en_US), then create or update the MsgChannelLanguageKeyword record.
Load references/language-keywords.md and follow it — it holds the full field list, the comma-separated-keyword semantics, the create-vs-update decision (reuse an existing record for the same language rather than duplicating), and the Unified-SMS help/custom-keyword rules.
The minimum per ConsentType (again, from the readiness contract):
- ImplicitOptIn:
OptOutKeywords(e.g.STOP,UNSUBSCRIBE) +OptOutConfirmation. - ExplicitOptIn: the above +
OptInKeywords(e.g.START,YES). - DoubleOptIn: the above +
DoubleOptInKeywords(e.g.CONFIRM).
OptInConfirmation, HelpKeywords/HelpResponse, and CustomKeywords/CustomResponse are optional for the base readiness check (help/custom are only required on Unified SMS — see the reference), but collect them if the user wants them.
Stage 5: Write channel fields + keyword record
Write the channel-level fields in one PATCH (only the fields the ConsentType requires).
Quoting rule (load-bearing): sf data update record --values splits on spaces, so any value containing a space must be wrapped in single quotes inside the double-quoted --values string — e.g. OptInPrompt='Reply YES to receive messages'. An unquoted OptInPrompt=Reply YES ... fails with Malformed key=value pair (verified live on sdb6c). Prompts almost always contain spaces, so always quote them.
# ImplicitOptIn — ConsentType only
sf data update record --target-org '{ORG_ALIAS}' --sobject MessagingChannel \
--record-id '{CHANNEL_ID}' --values "ConsentType=ImplicitOptIn" --json > /tmp/cc-patch.json
# ExplicitOptIn
sf data update record --target-org '{ORG_ALIAS}' --sobject MessagingChannel \
--record-id '{CHANNEL_ID}' --values "ConsentType=ExplicitOptIn OptInPrompt='{OPT_IN_PROMPT}'" --json > /tmp/cc-patch.json
# DoubleOptIn
sf data update record --target-org '{ORG_ALIAS}' --sobject MessagingChannel \
--record-id '{CHANNEL_ID}' \
--values "ConsentType=DoubleOptIn OptInPrompt='{OPT_IN_PROMPT}' DoubleOptInPrompt='{DBL_PROMPT}' IsRequireDoubleOptIn=true" --json > /tmp/cc-patch.json
If status !== 0: emit {ok:false, kind:"channel-patch-failed", message: ...} and return.
Then create or update the MsgChannelLanguageKeyword record per references/language-keywords.md. If it fails: {ok:false, kind:"keyword-record-failed", message: ...}.
Stage 6: Verify activation readiness
Re-read both the channel and its keyword records (same two queries as Stage 1). Confirm, per the chosen ConsentType's row in the Stage 2 matrix, that every required field is now non-null on the channel AND on at least one keyword record for the configured language.
If any required field is still null: emit {ok:false, kind:"verify-failed", hint:"<which requirement is unmet>"}.
Otherwise emit the success envelope with activationReady: true.
Stage 7: Report to caller
Report the JSON envelope. If this skill is the leaf (user invoked it directly), render:
Success — Consent configured — channel {CHANNEL_ID} is now {CONSENT_TYPE} with a {LANGUAGE} keyword record. Activation-ready.Info: Consent already configured — {CONSENT_TYPE}, {N} language record(s). No changes.(no-op path)Warning: This channel is PlatformType={x}, not Enhanced — consent fields don't apply here.(not-enhanced)Warning: Missing required consent input for {CONSENT_TYPE}: {what}. Re-run and provide it.(missing-consent-input)Error: {kind}: {message}(other failures)
Worked examples
For reference runs of the ImplicitOptIn (opt-out only), ExplicitOptIn, and DoubleOptIn paths, see references/worked-examples.md.
Gotchas
Known gotchas — the exact per-ConsentType activation-readiness contract (and its source), comma-separated keyword storage, the "ImplicitOptIn still needs a keyword record" trap, one-record-per-language uniqueness, the Unified-SMS help/French-custom rules, and the OptInPrompt Unified-SMS/WhatsApp/RCS exemption.
When troubleshooting an unexpected result, or before modifying this skill, load references/gotchas.md and follow it.
Related Skills
Salesforce
Activate an Enhanced `MessagingChannel` (WhatsApp / Apple / Facebook / SMS / RCS) by PATCHing `MessagingChannelUsage.DeploymentStatus` from `Disabled` to `Provisioning` via the standard REST sobject endpoint. The UDD save-hook fires on the REST write, dis
Categories
Agentforce Content
Salesforce
Configure routing on a newly-inserted Enhanced `MessagingChannel` so that activation will accept it. Given a `{CHANNEL_ID}`, walks the user through picking a routing type (Omni-Channel Queue, Omni-Flow, Agentforce Service Agent, Digital Worker, or direct
Categories
Agentforce Content
Salesforce
Top-level orchestrator: given a messaging channel type and its type-specific inputs, produces an activated Enhanced `MessagingChannel` in the target Salesforce org — without the Meta/LINE/Apple setup popups. Prompts for `{MESSAGE_TYPE}` if not supplied, t