@salesforce/afv-skills 1.58.0 → 1.60.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/skills/agentforce-architecture-analyze/SKILL.md +66 -17
- package/skills/agentforce-architecture-analyze/assets/cli/show_access_token.yaml +4 -7
- package/skills/agentforce-architecture-analyze/references/contract.json +1 -1
- package/skills/agentforce-architecture-analyze/scripts/emit_env.py +2 -2
- package/skills/agentforce-architecture-analyze/scripts/main.py +40 -44
- package/skills/agentforce-architecture-analyze/scripts/rest_client.py +11 -3
- package/skills/agentforce-architecture-analyze/scripts/sf_cli.py +77 -10
- package/skills/agentforce-architecture-analyze/scripts/tests/test_end_to_end_fixture.py +1 -0
- package/skills/agentforce-architecture-analyze/scripts/tests/test_flow_children_inflation.py +1 -0
- package/skills/agentforce-architecture-analyze/scripts/tests/test_main_pipeline.py +53 -2
- package/skills/agentforce-architecture-analyze/scripts/tests/test_resolve_creds.py +184 -36
- package/skills/agentforce-architecture-analyze/scripts/tests/test_rest_client.py +17 -0
- package/skills/agentforce-architecture-analyze/scripts/tests/test_sf_cli.py +165 -11
- package/skills/agentforce-architecture-analyze/scripts/tests/test_skill_md_pipeline_block.py +319 -0
- package/skills/agentforce-bot-upgrade/SKILL.md +3 -1
- package/skills/agentforce-d360-analyze/SKILL.md +28 -10
- package/skills/agentforce-d360-analyze/scripts/dc.py +200 -50
- package/skills/agentforce-d360-analyze/scripts/discover_sessions.py +10 -6
- package/skills/agentforce-d360-analyze/scripts/fetch_dc.py +22 -6
- package/skills/agentforce-d360-analyze/scripts/resolve_session.py +21 -13
- package/skills/agentforce-d360-analyze/scripts/tests/test_dc_and_resolve_session.py +298 -76
- package/skills/agentforce-d360-analyze/scripts/tests/test_default_target_org.py +432 -0
- package/skills/agentforce-d360-analyze/scripts/tests/test_discover_sessions.py +1 -1
- package/skills/agentforce-d360-analyze/scripts/tests/test_resolve_session_main.py +9 -3
- package/skills/agentforce-d360-analyze/scripts/tests/test_skill_md_prefix_block.py +176 -0
- package/skills/agentforce-generate/SKILL.md +21 -1
- package/skills/agentforce-generate/references/known-issues.md +51 -1
- package/skills/agentforce-generate/references/legacy-nga-regression-eval.md +547 -0
- package/skills/agentforce-generate/references/upgrade-legacy-agent-to-agentscript.md +577 -0
- package/skills/agentforce-generate/scripts/upgrade-legacy-nga-analyze.py +404 -0
- package/skills/agentforce-generate/scripts/upgrade-legacy-nga-run-trials.sh +58 -0
- package/skills/agentforce-persona-generate/SKILL.md +505 -0
- package/skills/agentforce-persona-generate/assets/checklist-template.md +100 -0
- package/skills/agentforce-persona-generate/assets/persona-encoding-template.md +252 -0
- package/skills/agentforce-persona-generate/assets/persona-template.md +229 -0
- package/skills/agentforce-persona-generate/assets/sample-dialog-template.md +50 -0
- package/skills/agentforce-persona-generate/assets/workshop-outline-template.md +97 -0
- package/skills/agentforce-persona-generate/examples/concierge-persona.md +189 -0
- package/skills/agentforce-persona-generate/examples/concierge-sample-dialog.md +70 -0
- package/skills/agentforce-persona-generate/examples/drover-persona.md +194 -0
- package/skills/agentforce-persona-generate/examples/drover-sample-dialog.md +62 -0
- package/skills/agentforce-persona-generate/examples/steady-hand-persona.md +188 -0
- package/skills/agentforce-persona-generate/examples/steady-hand-sample-dialog.md +68 -0
- package/skills/agentforce-persona-generate/examples/yt-persona.md +195 -0
- package/skills/agentforce-persona-generate/examples/yt-sample-dialog.md +66 -0
- package/skills/agentforce-persona-generate/references/attributions.md +36 -0
- package/skills/agentforce-persona-generate/references/interaction-design-notes.md +30 -0
- package/skills/agentforce-persona-generate/references/persona-encoding-guide.md +566 -0
- package/skills/agentforce-persona-generate/references/persona-framework.md +796 -0
- package/skills/agentforce-persona-generate/references/refinement-mappings.md +31 -0
- package/skills/agentforce-persona-generate/references/scoring-rubric.md +58 -0
- package/skills/agentforce-persona-generate/references/voice-catalog.json +2327 -0
- package/skills/agentforce-persona-generate/references/workshop-question-policy.md +90 -0
- package/skills/agentforce-persona-generate/references/workshop-scenario-seeds.md +119 -0
- package/skills/agentforce-persona-generate/scripts/parse_agent_yaml.py +223 -0
- package/skills/consumer-goods-accruals-datakit-deploy/SKILL.md +17 -27
- package/skills/consumer-goods-accruals-datakit-deploy/scripts/setup.js +7 -17
- package/skills/consumer-goods-accruals-datakit-deploy/scripts/steps/00-check-prerequisites.js +47 -63
- package/skills/consumer-goods-accruals-datakit-deploy/scripts/steps/01-download-static-resource.js +10 -13
- package/skills/consumer-goods-accruals-datakit-deploy/scripts/steps/02-replace-org-id.js +46 -46
- package/skills/consumer-goods-accruals-datakit-deploy/scripts/steps/03-deploy-metadata.js +4 -21
- package/skills/consumer-goods-accruals-datakit-deploy/scripts/steps/06-create-dataspace.js +58 -82
- package/skills/consumer-goods-accruals-datakit-deploy/scripts/steps/07-deploy-accruals-reports.js +16 -315
- package/skills/consumer-goods-accruals-datakit-deploy/scripts/steps/08-deploy-ui.js +9 -24
- package/skills/consumer-goods-accruals-datakit-deploy/scripts/steps/09-completion.js +44 -44
- package/skills/consumer-goods-accruals-datakit-deploy/scripts/steps/utils.js +11 -63
- package/skills/consumer-goods-rtr-datacloud-export-configure/SKILL.md +2 -1
- package/skills/consumer-goods-tpe-dashboard-configure/SKILL.md +2 -1
- package/skills/consumer-goods-tpe-dashboard-custom-kpi-configure/SKILL.md +2 -1
- package/skills/consumer-goods-tpe-datakit-deploy/SKILL.md +2 -1
- package/skills/data360-schema-get/SKILL.md +3 -3
- package/skills/design-systems-slds-validate/references/report-format.md +1 -1
- package/skills/dx-app-analytics-query/SKILL.md +8 -8
- package/skills/dx-org-manage/SKILL.md +1 -0
- package/skills/dx-org-shape-manage/SKILL.md +1 -0
- package/skills/dx-org-snapshot-manage/SKILL.md +172 -0
- package/skills/dx-org-snapshot-manage/examples/create_error_output.json +16 -0
- package/skills/dx-org-snapshot-manage/examples/create_success_output.json +19 -0
- package/skills/dx-org-snapshot-manage/examples/delete_output.json +9 -0
- package/skills/dx-org-snapshot-manage/examples/get_output.json +19 -0
- package/skills/dx-org-snapshot-manage/examples/list_output.json +36 -0
- package/skills/dx-org-snapshot-manage/references/cli_flags.md +179 -0
- package/skills/dx-org-snapshot-manage/references/snapshot_usage.md +55 -0
- package/skills/dx-org-trial-expiration-check/SKILL.md +1 -1
- package/skills/dx-org-trial-expiration-check/scripts/check_expiration.sh +2 -2
- package/skills/education-cloud-student-recruitment-agent-configure/SKILL.md +7 -5
- package/skills/education-cloud-student-recruitment-agent-configure/references/prerequisites.md +11 -11
- package/skills/experience-content-media-image-generate/SKILL.md +83 -0
- package/skills/experience-content-media-image-generate/scripts/download-image.sh +84 -0
- package/skills/experience-ui-bundle-app-coordinate/SKILL.md +12 -12
- package/skills/experience-ui-bundle-app-coordinate/references/phase-completion-validation.md +3 -3
- package/skills/experience-ui-bundle-app-coordinate/references/phase-execution-pattern.md +9 -7
- package/skills/experience-ui-bundle-app-coordinate/scripts/check-dangling-refs.mjs +132 -0
- package/skills/experience-ui-bundle-app-coordinate/scripts/check-hosting-target.mjs +62 -0
- package/skills/experience-ui-bundle-app-coordinate/scripts/check-phase-1-complete.mjs +71 -0
- package/skills/experience-ui-bundle-app-coordinate/scripts/check-phase-4-complete.mjs +95 -0
- package/skills/experience-ui-bundle-app-coordinate/scripts/check-phase-6-ready.mjs +78 -0
- package/skills/experience-ui-bundle-app-coordinate/scripts/check-prerequisites.mjs +21 -0
- package/skills/experience-ui-bundle-app-coordinate/scripts/check-sfdx-project.mjs +28 -0
- package/skills/experience-ui-bundle-custom-app-generate/SKILL.md +3 -1
- package/skills/experience-ui-bundle-custom-app-generate/scripts/resolve-uibundle-path.mjs +40 -0
- package/skills/experience-ui-bundle-frontend-generate/SKILL.md +7 -5
- package/skills/experience-ui-bundle-frontend-generate/scripts/check-preconditions.mjs +70 -0
- package/skills/experience-ui-bundle-frontend-generate/scripts/resolve-ui-bundle.mjs +76 -0
- package/skills/experience-ui-bundle-frontend-generate/scripts/verify-rules.mjs +115 -0
- package/skills/experience-ui-bundle-metadata-generate/SKILL.md +7 -3
- package/skills/experience-ui-bundle-metadata-generate/references/angular-metadata-generate.md +1 -1
- package/skills/experience-ui-bundle-metadata-generate/references/react-metadata-generate.md +1 -1
- package/skills/experience-ui-bundle-metadata-generate/scripts/check-api-version.mjs +43 -0
- package/skills/experience-ui-bundle-metadata-generate/scripts/detect-framework.mjs +131 -0
- package/skills/experience-ui-bundle-metadata-generate/scripts/verify-bundle-location.mjs +152 -0
- package/skills/experience-ui-bundle-mfa-configure/references/branding.md +10 -6
- package/skills/external-diagram-mermaid-generate/SKILL.md +12 -12
- package/skills/field-service-data-capture-migrate/references/component-mapping.md +1 -1
- package/skills/field-service-data-capture-migrate/references/fsm-dc-capability-catalog.md +1 -2
- package/skills/field-service-data-capture-migrate/references/known-deploy-errors.md +1 -0
- package/skills/field-service-data-capture-migrate/references/transformer-rules.md +1 -1
- package/skills/field-service-data-capture-migrate/scripts/transform_flow.py +12 -1
- package/skills/field-service-data-capture-migrate/scripts/vendor/build_flow.py +4 -1
- package/skills/field-service-setup-orchestrator-get/SKILL.md +0 -1
- package/skills/insurance-brokerage-agency-billing-configure/SKILL.md +233 -0
- package/skills/insurance-brokerage-agency-billing-configure/references/accounting-setup.md +117 -0
- package/skills/insurance-brokerage-agency-billing-configure/references/billing-rules-config.md +237 -0
- package/skills/insurance-brokerage-agency-billing-configure/references/billing-settings.md +271 -0
- package/skills/insurance-brokerage-agency-billing-configure/references/demo-policy-config.md +138 -0
- package/skills/insurance-brokerage-agency-billing-configure/references/org-defaults.md +64 -0
- package/skills/insurance-brokerage-agency-billing-configure/references/permissions-config.md +226 -0
- package/skills/insurance-brokerage-agency-billing-configure/references/prerequisites.md +142 -0
- package/skills/life-sciences-fieldsalesrep-coordinate/SKILL.md +3 -2
- package/skills/life-sciences-fieldsalesrep-coordinate/references/stage-5-visit-creation-execution-state-and-recovery.md +3 -3
- package/skills/life-sciences-fieldsalesrep-coordinate/references/stage-5-visit-creation-overview.md +68 -45
- package/skills/life-sciences-fieldsalesrep-coordinate/references/stage-5-visit-creation-visit-creation-data.md +17 -18
- package/skills/life-sciences-kam-coordinate/references/stage-5-data-and-plan-templates-overview.md +16 -3
- package/skills/life-sciences-kam-coordinate/references/stage-5-data-creation-data.md +16 -13
- package/skills/marketing-message-test/SKILL.md +194 -0
- package/skills/marketing-message-test/references/api-contract.md +333 -0
- package/skills/omnistudio-callable-apex-generate/SKILL.md +3 -3
- package/skills/omnistudio-datamapper-generate/SKILL.md +6 -6
- package/skills/omnistudio-datapacks-deploy/SKILL.md +11 -11
- package/skills/omnistudio-dependencies-analyze/SKILL.md +5 -5
- package/skills/omnistudio-epc-catalog-generate/SKILL.md +6 -6
- package/skills/omnistudio-flexcard-generate/SKILL.md +6 -6
- package/skills/omnistudio-integration-procedure-generate/SKILL.md +6 -6
- package/skills/omnistudio-omniscript-generate/SKILL.md +6 -5
- package/skills/platform-apex-logs-debug/SKILL.md +1 -0
- package/skills/platform-metadata-deploy/SKILL.md +1 -0
- package/skills/platform-models-api-configure/SKILL.md +5 -5
- package/skills/platform-soql-query/SKILL.md +1 -0
- package/skills/service-itsm-agentic-setup-cmdb-coordinate/SKILL.md +17 -6
- package/skills/service-itsm-agentic-setup-incident-sla-configure/SKILL.md +107 -192
- package/skills/service-itsm-agentic-setup-incident-sla-configure/assets/attach-milestone-action.json +6 -6
- package/skills/service-itsm-agentic-setup-incident-sla-configure/examples/milestone-patterns.md +49 -20
- package/skills/service-itsm-agentic-setup-incident-sla-configure/examples/output-templates.md +4 -4
- package/skills/service-itsm-agentic-setup-incident-sla-configure/references/mcp-invocation.md +224 -290
- package/skills/service-itsm-agentic-setup-incident-sla-configure/references/workflow.md +295 -0
- package/skills/service-itsm-incident-priority-configure/SKILL.md +1 -1
- package/skills/service-itsm-slack-itservice-configure/SKILL.md +2 -1
- package/skills/service-itsm-slack-itservice-configure/references/manage-slack-connection.md +2 -2
- package/skills/service-omni-channel-setup-coordinate/SKILL.md +20 -13
- package/skills/service-omni-channel-setup-coordinate/scripts/integration-driver.sh +5 -55
- package/skills/service-omni-channel-setup-coordinate/scripts/tests/test_omni_contracts.py +0 -38
- package/skills/service-omni-command-center-analyze/SKILL.md +2 -3
- package/skills/service-omni-command-center-analyze/scripts/analyze.sh +3 -3
- package/skills/tableau-next-asset-create/README.md +65 -0
- package/skills/tableau-next-asset-create/SKILL.md +409 -0
- package/skills/tableau-next-asset-create/references/admin-users.md +149 -0
- package/skills/tableau-next-asset-create/references/ai-readiness.md +355 -0
- package/skills/tableau-next-asset-create/references/alerts.md +111 -0
- package/skills/tableau-next-asset-create/references/build-workflow.md +819 -0
- package/skills/tableau-next-asset-create/references/dashboard-authoring.md +302 -0
- package/skills/tableau-next-asset-create/references/dashboard-design-principles.md +352 -0
- package/skills/tableau-next-asset-create/references/data-transform-gotchas.md +210 -0
- package/skills/tableau-next-asset-create/references/data-understanding.md +387 -0
- package/skills/tableau-next-asset-create/references/deep-reference-index.md +74 -0
- package/skills/tableau-next-asset-create/references/destructive-operations.md +62 -0
- package/skills/tableau-next-asset-create/references/edit-dashboard.md +273 -0
- package/skills/tableau-next-asset-create/references/edit-visualization.md +529 -0
- package/skills/tableau-next-asset-create/references/empty-source-handling.md +104 -0
- package/skills/tableau-next-asset-create/references/ingest-and-metric-gotchas.md +638 -0
- package/skills/tableau-next-asset-create/references/insight-bundle.md +69 -0
- package/skills/tableau-next-asset-create/references/large-flat-file-handling.md +331 -0
- package/skills/tableau-next-asset-create/references/schemas/edit-dashboard/_envelope.json +54 -0
- package/skills/tableau-next-asset-create/references/schemas/edit-dashboard/_shared-widget-fields.json +122 -0
- package/skills/tableau-next-asset-create/references/schemas/edit-dashboard/add_page.json +29 -0
- package/skills/tableau-next-asset-create/references/schemas/edit-dashboard/delete_page.json +27 -0
- package/skills/tableau-next-asset-create/references/schemas/edit-dashboard/discard_dashboard.json +11 -0
- package/skills/tableau-next-asset-create/references/schemas/edit-dashboard/move_widget.json +30 -0
- package/skills/tableau-next-asset-create/references/schemas/edit-dashboard/move_widget_to_page.json +30 -0
- package/skills/tableau-next-asset-create/references/schemas/edit-dashboard/place_widget_on_page.json +30 -0
- package/skills/tableau-next-asset-create/references/schemas/edit-dashboard/remove_widget_from_dashboard.json +16 -0
- package/skills/tableau-next-asset-create/references/schemas/edit-dashboard/remove_widget_from_page.json +26 -0
- package/skills/tableau-next-asset-create/references/schemas/edit-dashboard/rename_page.json +28 -0
- package/skills/tableau-next-asset-create/references/schemas/edit-dashboard/save_dashboard.json +18 -0
- package/skills/tableau-next-asset-create/references/schemas/edit-dashboard/undo.json +11 -0
- package/skills/tableau-next-asset-create/references/schemas/edit-dashboard/upsert_button_widget.json +69 -0
- package/skills/tableau-next-asset-create/references/schemas/edit-dashboard/upsert_container_widget.json +88 -0
- package/skills/tableau-next-asset-create/references/schemas/edit-dashboard/upsert_filter_widget.json +146 -0
- package/skills/tableau-next-asset-create/references/schemas/edit-dashboard/upsert_metric_widget.json +78 -0
- package/skills/tableau-next-asset-create/references/schemas/edit-dashboard/upsert_navigation_widget.json +80 -0
- package/skills/tableau-next-asset-create/references/schemas/edit-dashboard/upsert_parameter_widget.json +160 -0
- package/skills/tableau-next-asset-create/references/schemas/edit-dashboard/upsert_text_widget.json +103 -0
- package/skills/tableau-next-asset-create/references/schemas/edit-dashboard/upsert_visualization_widget.json +68 -0
- package/skills/tableau-next-asset-create/references/sdm-tool-reference.md +721 -0
- package/skills/tableau-next-asset-create/references/semantic-query-and-enrichment.md +355 -0
- package/skills/tableau-next-asset-create/references/shared-gates.md +322 -0
- package/skills/tableau-next-asset-create/references/sharing-and-promotion.md +306 -0
- package/skills/tableau-next-asset-create/references/tasks/ai-readiness-audit.md +51 -0
- package/skills/tableau-next-asset-create/references/tasks/analyze-data.md +48 -0
- package/skills/tableau-next-asset-create/references/tasks/build-dashboard.md +66 -0
- package/skills/tableau-next-asset-create/references/tasks/build-end-to-end.md +73 -0
- package/skills/tableau-next-asset-create/references/tasks/create-data-transform.md +51 -0
- package/skills/tableau-next-asset-create/references/tasks/create-viz.md +58 -0
- package/skills/tableau-next-asset-create/references/tasks/edit-dashboard.md +80 -0
- package/skills/tableau-next-asset-create/references/tasks/edit-sdm.md +106 -0
- package/skills/tableau-next-asset-create/references/tasks/edit-viz.md +40 -0
- package/skills/tableau-next-asset-create/references/tasks/enrich-model.md +68 -0
- package/skills/tableau-next-asset-create/references/tasks/ingest-flat-file.md +68 -0
- package/skills/tableau-next-asset-create/references/tasks/manage-alert.md +35 -0
- package/skills/tableau-next-asset-create/references/tasks/profile-dataset.md +47 -0
- package/skills/tableau-next-asset-create/references/tasks/promote-or-reuse.md +46 -0
- package/skills/tableau-next-asset-create/references/tasks/provision-user.md +39 -0
- package/skills/tableau-next-asset-create/references/tasks/query-model.md +92 -0
- package/skills/tableau-next-asset-create/references/tasks/review-verified-questions.md +42 -0
- package/skills/tableau-next-asset-create/references/tasks/share-asset.md +37 -0
- package/skills/tableau-next-asset-create/references/verified-questions.md +125 -0
- package/skills/tableau-next-asset-create/references/viz-authoring.md +992 -0
- package/skills/experience-ui-bundle-app-coordinate/scripts/check-dangling-refs.sh +0 -42
- package/skills/experience-ui-bundle-app-coordinate/scripts/check-hosting-target.sh +0 -26
- package/skills/experience-ui-bundle-app-coordinate/scripts/check-phase-1-complete.sh +0 -35
- package/skills/experience-ui-bundle-app-coordinate/scripts/check-phase-4-complete.sh +0 -47
- package/skills/experience-ui-bundle-app-coordinate/scripts/check-phase-6-ready.sh +0 -33
- package/skills/experience-ui-bundle-app-coordinate/scripts/check-prerequisites.sh +0 -20
- package/skills/experience-ui-bundle-app-coordinate/scripts/check-sfdx-project.sh +0 -15
- package/skills/experience-ui-bundle-custom-app-generate/scripts/resolve-uibundle-path.sh +0 -30
- package/skills/experience-ui-bundle-frontend-generate/scripts/check-preconditions.sh +0 -37
- package/skills/experience-ui-bundle-frontend-generate/scripts/resolve-ui-bundle.sh +0 -66
- package/skills/experience-ui-bundle-frontend-generate/scripts/verify-rules.sh +0 -58
- package/skills/experience-ui-bundle-metadata-generate/scripts/check-api-version.sh +0 -30
- package/skills/experience-ui-bundle-metadata-generate/scripts/detect-framework.sh +0 -73
- package/skills/experience-ui-bundle-metadata-generate/scripts/verify-bundle-location.sh +0 -118
- package/skills/service-itsm-agentic-setup-incident-sla-configure/assets/predefined-incident-policy.json +0 -102
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: marketing-message-test
|
|
3
|
+
description: "Salesforce Marketing Cloud / Engagement 360 message preview and test-send. Use this skill when the user wants to render a personalized or unpersonalized preview of an E360 message (Email, SMS, WhatsApp, Push, In-App, RCS) from a content key, or fire a test send, over the headless API — no app UI. TRIGGER when: user has a contentKey and wants to see how a message renders for a recipient, preview a message headlessly, or send a test message. DO NOT TRIGGER when: the task is authoring message content, building Data Cloud segments/DMOs (use data360-segment / data360-harmonize), or activating a segment (use data360-activate)."
|
|
4
|
+
metadata:
|
|
5
|
+
version: "1.0"
|
|
6
|
+
minApiVersion: "62.0"
|
|
7
|
+
accessCheck:
|
|
8
|
+
- type: "orgPerm"
|
|
9
|
+
value: "MarketingEngagement"
|
|
10
|
+
cliTools:
|
|
11
|
+
- tool:
|
|
12
|
+
- "sf"
|
|
13
|
+
semver: ">=2.0.0"
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
# marketing-message-test: E360 Message Preview & Test Send
|
|
17
|
+
|
|
18
|
+
Render a per-channel **preview** (or fire a **test send**) for a Marketing Cloud / Engagement 360 message, headlessly, starting from a single **`contentKey`**. Covers all six channels: Email, SMS, WhatsApp, Push, In-App, RCS.
|
|
19
|
+
|
|
20
|
+
Full endpoint tables, request bodies, response-field rules, and the version-floor matrix live in [references/api-contract.md](references/api-contract.md). This file is the operating procedure; consult the reference for exact payloads.
|
|
21
|
+
|
|
22
|
+
## When This Skill Owns the Task
|
|
23
|
+
|
|
24
|
+
Use `marketing-message-test` when the user wants to:
|
|
25
|
+
- render how an authored message looks for a real recipient (**personalized preview**)
|
|
26
|
+
- render content-only with no recipient (**unpersonalized preview**)
|
|
27
|
+
- send a **test message** to their own address / phone / individual id
|
|
28
|
+
|
|
29
|
+
Delegate elsewhere when the user is:
|
|
30
|
+
- building Data Cloud segments or calculated insights → [data360-segment](../data360-segment/SKILL.md)
|
|
31
|
+
- building DMOs, mappings, or identity resolution → [data360-harmonize](../data360-harmonize/SKILL.md)
|
|
32
|
+
- activating a segment downstream → [data360-activate](../data360-activate/SKILL.md)
|
|
33
|
+
|
|
34
|
+
## Required Context to Gather First
|
|
35
|
+
|
|
36
|
+
- **`contentKey`** — required, irreducible. The caller must supply it; it is not derivable.
|
|
37
|
+
- target org alias (for `sf org open` / access token)
|
|
38
|
+
- **channel** — Email, SMS, WhatsApp, Push, In-App, or RCS
|
|
39
|
+
- **mode** — personalized preview, unpersonalized preview, or test send
|
|
40
|
+
- for a **test send only**: the user's own destination(s) — `toAddresses` (Email), `toPhoneNumbers` (SMS/WhatsApp/RCS), or `toIndividualIds` (Push/In-App). Never derive these.
|
|
41
|
+
|
|
42
|
+
## Transports
|
|
43
|
+
|
|
44
|
+
| Purpose | Transport | Instance-relative path |
|
|
45
|
+
|---|---|---|
|
|
46
|
+
| Preview · test send · sender lookups | **LWR Apex** | `lwr/apex/v68.0/…` — the exact operation path is on each step's **Call** line |
|
|
47
|
+
| Managed content · data space · DMO · segment · profile | **Connect REST** | `services/data/vXX.0/…` (per-resource floors; v62.0+ covers all six channels) |
|
|
48
|
+
| WhatsApp template fetch (`whatsapp-template-fetch`) | **Headless dispatch** | `/headless/invoke/…` — a dispatch route, so invoke it through the `dispatch` tool, **not** `sf api request rest` (see the reference doc for details) |
|
|
49
|
+
|
|
50
|
+
**Versions:**
|
|
51
|
+
- **LWR-Apex** — not version-gated; pin `v68.0` (the path just needs a well-formed `vXX.0` segment).
|
|
52
|
+
- **Connect REST** — real per-resource floors; highest is data-spaces at **v62.0**, so **v62.0+ covers all six channels** (others lower — see the reference floor matrix).
|
|
53
|
+
|
|
54
|
+
**Always use `sf api request rest` — never `curl`.** It attaches the org's bearer token internally, so the credential never enters your context. **Never** extract a token (e.g. `sf org display --json`) or put one in an `Authorization` header — that leaks a live credential and is disallowed. Pass the **instance-relative path** (no host); the CLI prepends the instance URL and accepts both transports (LWR-Apex paths aren't under `services/data/`, but any instance-relative path works). **One step is the exception** — `whatsapp-template-fetch` is a headless `/headless/invoke` dispatch route, invoked through the `dispatch` tool rather than `sf api request rest`.
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
# GET (default method); path is instance-relative
|
|
58
|
+
sf api request rest 'services/data/v63.0/ssot/data-spaces' --target-org <org>
|
|
59
|
+
|
|
60
|
+
# POST with a flat JSON body from a file (content-type: application/json is sent by default)
|
|
61
|
+
# path = the target operation's **Call** line (e.g. the `preview-sms-unpersonalized` step)
|
|
62
|
+
sf api request rest '<lwr/apex Call path>' \
|
|
63
|
+
--target-org <org> --method POST --body @body.json
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
**Verb rule (do not violate — wrong verb is rejected):**
|
|
67
|
+
- Preview / test-send methods are **POST** (`--method POST`) with a **flat JSON body** whose keys are exactly the parameter names — no envelope, no wrapper object.
|
|
68
|
+
- Sender / permission lookups are **GET** (default method) with args packed into a single `methodParams` query param (URL-encoded JSON string) appended to the path; no-arg methods omit it.
|
|
69
|
+
|
|
70
|
+
## Core Operating Rules
|
|
71
|
+
|
|
72
|
+
- **Never fabricate** a `segmentId`, `profileId`, DMO name, or destination. Every value is either given by the user or derived from the org via the chain below.
|
|
73
|
+
- **Preview needs no sender** — skip sender lookups (Part 3 of the reference) unless test-sending.
|
|
74
|
+
- **Personalized vs unpersonalized**: unpersonalized needs only `contentKey`; personalized needs `segmentId` + `recipientDataModelObjectName` + `contentKey` + `profileId`, **and the `profileId` must be a member of that `segmentId`** (it comes from that segment's member list — see the chain).
|
|
75
|
+
- **Personalization is supported ONLY with a valid segment and a member of it.** The recipient (`profileId`) comes solely from the chosen segment's member list, and must be a member of the `segmentId` passed to the render. If the segment has no members — or no segment exists in the content's data space — the personalization render **cannot be performed**: report `cannot personalize — no valid segment member` and stop. The unpersonalized preview (`contentKey` only) is still available; offer it. Never source the recipient from anywhere else (e.g. by listing individuals from the DMO) — a non-member `profileId` is rejected by the render with an opaque error.
|
|
76
|
+
- A **test send is a real send** to the supplied destinations — confirm the user asked for it and has provided their own destinations before firing any test send (the `send-test-…` steps). If the user asked only to preview, never fire a test send.
|
|
77
|
+
- **Check send permission before every test send.** Before firing any `send-test-<channel>`, call that channel's permission check (step `perm-can-send-test-<channel>` — a no-arg GET returning a Boolean). If it returns **false**, surface a permission error and **stop** — do not attempt the send. Preview never needs this check.
|
|
78
|
+
- **`profileId` is a Data Cloud profile key** (e.g. `a1b2c3d4…`), NOT a CRM id (`003…`) or a segment id (`1sg…`).
|
|
79
|
+
- Run the derivation yourself end to end via `sf api request rest`; don't hand the user raw commands to run.
|
|
80
|
+
|
|
81
|
+
## Derivation Chain (personalized preview / test send, from `contentKey`)
|
|
82
|
+
|
|
83
|
+
Detailed payloads for every step: [references/api-contract.md](references/api-contract.md).
|
|
84
|
+
|
|
85
|
+
1. **Fetch content** — `GET /services/data/vXX.0/connect/cms/contents/{contentKey}` (v57+) → `managedContentId`, `contentBody`. Use the CMS **Authoring** API (keyed by `contentKey`), not the delivery API — it returns the draft the preview renders.
|
|
86
|
+
2. **Recipient DMO (from content)** → `recipientDataModelObjectName`. Parse `contentBody['lightning:dataProviders']` for `objectApiName` (that is the DMO) or `dataGraphApiName` — for the latter, `GET /ssot/data-graphs/{dataGraphApiName}` (v58+) and read `primaryObjectName` (its response also returns `dataspaceName`, usable directly in step 3). If the content declares no data provider, leave the DMO unresolved for now — it comes from the org fallback in step 3, which needs the data space first.
|
|
87
|
+
3. **Data space** → `dataSpaceName` (scopes every `/ssot/…` call below). `GET /ssot/data-spaces` (v62+).
|
|
88
|
+
- **DMO declared in step 2** — derive the data space from the DMO name: `ssot__…` prefix or an unrecognized name → `default`; a `<prefix>_` token → match against the `prefix` field and take that entry's `name`. `default` on single-space orgs.
|
|
89
|
+
- **No DMO declared** — there's no name to match, so choose the data space first: `default` on a single-space org, otherwise ask the user which space. Then resolve the DMO from the org via the org-fallback lookup (step `messaging-selected-uma-dmo`, body `{ dataSpaceName }`). A `null` result means "no personalized preview available for this org" — report that, do NOT retry.
|
|
90
|
+
4. **Segment** → `GET /ssot/segments?dataspace=<name>` (v55+). Keep the `apiName` (fetches members) and the `1sg…` `marketSegmentId` (the `segmentId`).
|
|
91
|
+
5. **profileId** — from the chosen segment's members, the only valid source:
|
|
92
|
+
- `GET /ssot/segments/{segmentApiName}/members?limit=10&dataspace=<name>` (v58+) → member `id`. That `id` **is** the `profileId`; because it's a member of the segment, the render accepts it.
|
|
93
|
+
- **If the member list is empty (or no segment exists in the data space), stop — personalization cannot be performed.** There is no valid recipient: report `cannot personalize — no valid segment member` and offer the unpersonalized preview instead. Do **not** source the recipient elsewhere (e.g. by listing individuals from the DMO) — a `profileId` that isn't a member of the passed `segmentId` is rejected by the render with an opaque error.
|
|
94
|
+
6. **Render** — call the channel's personalized-preview operation (step `preview-<channel>-personalized`, or the `…-by-locale` variant) with the flat body `{ segmentId, recipientDataModelObjectName, contentKey, profileId, … }`.
|
|
95
|
+
|
|
96
|
+
**Unpersonalized** short-circuits after step 1: call the channel's unpersonalized-preview operation (step `preview-<channel>-unpersonalized`) with `{ contentKey }` (add `locale` for Email's `…-by-locale` variant).
|
|
97
|
+
|
|
98
|
+
**Test send** = the channel's permission check (step `perm-can-send-test-<channel>`; stop if false), then steps 1–6, then a sender lookup (Part 3 of the reference) for `fromAddress`/`senderId`, then the channel's test-send operation (step `send-test-<channel>`) with the user's supplied destination array.
|
|
99
|
+
|
|
100
|
+
## Reading the Rendered Output
|
|
101
|
+
|
|
102
|
+
- **Email** — flat object of string fields. Rendered HTML is in `body` for personalized calls, `nonAggregateHtmlBody` for unpersonalized — **read `body` first, fall back to `nonAggregateHtmlBody`**. Also surface `subject` and `preheader`.
|
|
103
|
+
- **SMS** — rendered text is the `content` string; MMS also carries `mediaUrl`.
|
|
104
|
+
- **WhatsApp** — returns `{ content, metadata }` as JSON strings; reassemble `{{k}}` slots from the fetched template (see the reference — this is the fiddly one).
|
|
105
|
+
- **Push / In-App / RCS** — read the returned rendered fields per channel.
|
|
106
|
+
|
|
107
|
+
> **Fetch media from the rendered `<img src>`, not the content definition.** Rendered srcs are public-CDN URLs (`…salesforce-experience.com/_scs/cms/…`) that fetch unauthenticated. `contentBody` `/cms/media/…` refs are session-gated — unauthenticated they return an HTML login page (HTTP 200, no error), not image bytes.
|
|
108
|
+
|
|
109
|
+
## Content Variables
|
|
110
|
+
|
|
111
|
+
If the content declares content variables under `sfdc_cms:schema.properties`, they render empty unless supplied. **Ask the user for a value for each — never invent one** — and pass them via `recipientAttributesJson` (a JSON string), on Email/SMS/WhatsApp/RCS only.
|
|
112
|
+
|
|
113
|
+
> **Push and In-App personalized previews do not support content variables.** If any are declared in the content definition (`sfdc_cms:schema.properties` non-empty) for one of those channels, stop and inform the user it's not supported — do not troubleshoot.
|
|
114
|
+
|
|
115
|
+
## High-Signal Gotchas
|
|
116
|
+
|
|
117
|
+
- **Wrong verb is rejected** — preview/send = POST + flat body; sender lookups = GET + `methodParams`.
|
|
118
|
+
- **`contentKey` is irreducible** — every path bottoms out at it; the user must supply it.
|
|
119
|
+
- **Data space must match the content**, or segments/profiles won't personalize correctly.
|
|
120
|
+
- **DMO may need the org fallback**; the org-fallback DMO lookup (`messaging-selected-uma-dmo`) returning `null` = "no personalized preview available," not a retryable error.
|
|
121
|
+
- **Recipient must be a segment member**: the `profileId` comes only from the chosen segment's member list and must be a member of the `segmentId` passed to the render. No members (or no segment) → personalization cannot be performed; stop and offer unpersonalized. Never source the recipient from a DMO listing — a non-member `profileId` is rejected with an opaque error.
|
|
122
|
+
- **Profile-key field**: segment members return the profile key as `id` (a Data Cloud key, e.g. `a1b2c3d4…` — not a `1sg…` segment id or a `003…` CRM id); that `id` is the `profileId`.
|
|
123
|
+
- **Version floors are per-resource** — LWR-Apex is not version-gated (pin `v68.0`; the path segment just needs to be well-formed); the REST derivation resources have per-resource minimums. Highest REST floor is data-spaces at **v62.0**, so target **v62.0+** for full six-channel coverage (lower channels work below that).
|
|
124
|
+
|
|
125
|
+
## Output Format
|
|
126
|
+
|
|
127
|
+
```text
|
|
128
|
+
Message: <contentKey> (channel: <Email/SMS/WhatsApp/Push/In-App/RCS>)
|
|
129
|
+
Mode: <personalized preview / unpersonalized preview / test send>
|
|
130
|
+
Target org: <alias>
|
|
131
|
+
Derived inputs: dataSpace=<name> DMO=<…__dlm> segmentId=<1sg…> profileId=<profile key>
|
|
132
|
+
API calls: <method — verb — endpoint> (one line each)
|
|
133
|
+
Rendered output:
|
|
134
|
+
<subject / rendered text / HTML body, per channel>
|
|
135
|
+
Next step: <act / adjust inputs / follow-up>
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
## References
|
|
139
|
+
|
|
140
|
+
- [references/api-contract.md](references/api-contract.md) — full endpoint tables, request bodies, response-field rules, per-resource version floors, and the end-to-end recipe for all six channels.
|
|
141
|
+
|
|
142
|
+
<!-- skill-validate: ignore-start -->
|
|
143
|
+
<!-- codey:operations start -->
|
|
144
|
+
## Operations Reference
|
|
145
|
+
|
|
146
|
+
Operations this skill uses — routing and dependency reference.
|
|
147
|
+
|
|
148
|
+
| Operation | Purpose | Status | Call | Depends on |
|
|
149
|
+
|-----------|---------|--------|------|------------|
|
|
150
|
+
| `cms-content-fetch` | read | — | `GET /services/data/v63.0/connect/cms/contents/{contentKeyOrId}` | — |
|
|
151
|
+
| `messaging-selected-uma-dmo` | read | — | `POST lwr/apex/v68.0/interaction__MessagingController/getSelectedUnifiedIndividualDmoForUma` | `data-spaces-list` |
|
|
152
|
+
| `data-graph-primary-object` | read | — | `GET /services/data/v63.0/ssot/data-graphs/{dataGraphApiName}` | — |
|
|
153
|
+
| `data-spaces-list` | read | — | `GET /services/data/v63.0/ssot/data-spaces` | — |
|
|
154
|
+
| `dmo-describe` | read | — | `GET /services/data/v63.0/ssot/data-model-objects/{dmoName}` | — |
|
|
155
|
+
| `segments-list` | read | — | `GET /services/data/v63.0/ssot/segments` | `data-spaces-list` |
|
|
156
|
+
| `segment-members-list` | read | — | `GET /services/data/v63.0/ssot/segments/{segmentApiName}/members` | `segments-list` |
|
|
157
|
+
| `profile-fetch-by-id` | verify | — | `GET /services/data/v63.0/ssot/profile/{dmoName}/{profileId}` | — |
|
|
158
|
+
| `cms-spaces-list` | read | — | `GET /services/data/v63.0/connect/cms/spaces` | — |
|
|
159
|
+
| `preview-email-unpersonalized` | read | — | `POST lwr/apex/v68.0/interaction__JourneyController/getEmailUnpersonalizedPreviewContent` | `cms-content-fetch` |
|
|
160
|
+
| `preview-email-unpersonalized-by-locale` | read | — | `POST lwr/apex/v68.0/interaction__JourneyController/getEmailUnpersonalizedPreviewContentByLocale` | `cms-content-fetch` |
|
|
161
|
+
| `preview-email-personalized` | read | — | `POST lwr/apex/v68.0/interaction__JourneyController/getEmailPersonalizedPreviewContent` | `cms-content-fetch`, `segments-list` |
|
|
162
|
+
| `preview-email-personalized-by-locale` | read | — | `POST lwr/apex/v68.0/interaction__JourneyController/getEmailPersonalizedPreviewContentByLocale` | `cms-content-fetch`, `segments-list` |
|
|
163
|
+
| `preview-sms-unpersonalized` | read | — | `POST lwr/apex/v68.0/interaction__JourneyController/getSmsUnpersonalizedPreviewContent` | `cms-content-fetch` |
|
|
164
|
+
| `preview-sms-personalized` | read | — | `POST lwr/apex/v68.0/interaction__JourneyController/getSmsPersonalizedPreviewContent` | `cms-content-fetch`, `segments-list` |
|
|
165
|
+
| `preview-whatsapp-unpersonalized` | read | — | `POST lwr/apex/v68.0/interaction__JourneyController/getWhatsappUnpersonalizedPreviewContent` | `cms-content-fetch` |
|
|
166
|
+
| `preview-whatsapp-personalized` | read | — | `POST lwr/apex/v68.0/interaction__JourneyController/getWhatsappPersonalizedPreviewContent` | `cms-content-fetch`, `segments-list` |
|
|
167
|
+
| `preview-push-unpersonalized` | read | — | `POST lwr/apex/v68.0/interaction__JourneyController/getPushUnpersonalizedPreviewContent` | `cms-content-fetch` |
|
|
168
|
+
| `preview-push-personalized` | read | — | `POST lwr/apex/v68.0/interaction__JourneyController/getPushPersonalizedPreviewContent` | `cms-content-fetch`, `segments-list` |
|
|
169
|
+
| `preview-inapp-unpersonalized` | read | — | `POST lwr/apex/v68.0/interaction__JourneyController/getInAppUnpersonalizedPreviewContent` | `cms-content-fetch` |
|
|
170
|
+
| `preview-inapp-personalized` | read | — | `POST lwr/apex/v68.0/interaction__JourneyController/getInAppPersonalizedPreviewContent` | `cms-content-fetch`, `segments-list` |
|
|
171
|
+
| `preview-rcs-unpersonalized` | read | — | `POST lwr/apex/v68.0/interaction__JourneyController/getRcsUnpersonalizedPreviewContent` | `cms-content-fetch` |
|
|
172
|
+
| `preview-rcs-personalized` | read | — | `POST lwr/apex/v68.0/interaction__JourneyController/getRcsPersonalizedPreviewContent` | `cms-content-fetch`, `segments-list` |
|
|
173
|
+
| `whatsapp-template-fetch` | read | — | `GET /headless/invoke/platform/conversation-setup/whats-app-templates/get-by-id` | — |
|
|
174
|
+
| `send-test-email` | write | — | `POST lwr/apex/v68.0/interaction__JourneyController/sendTestEmail` | `cms-content-fetch`, `segments-list`, `sender-email-from-addresses`, `perm-can-send-test-email` |
|
|
175
|
+
| `send-test-email-by-locale` | write | — | `POST lwr/apex/v68.0/interaction__JourneyController/sendTestEmailByLocale` | `cms-content-fetch`, `segments-list`, `sender-email-from-addresses`, `perm-can-send-test-email` |
|
|
176
|
+
| `send-test-sms` | write | — | `POST lwr/apex/v68.0/interaction__JourneyController/sendTestSms` | `cms-content-fetch`, `segments-list`, `sender-sms-codes`, `perm-can-send-test-sms` |
|
|
177
|
+
| `send-test-whatsapp` | write | — | `POST lwr/apex/v68.0/interaction__JourneyController/sendTestWhatsapp` | `cms-content-fetch`, `segments-list`, `sender-whatsapp-numbers`, `perm-can-send-test-whatsapp` |
|
|
178
|
+
| `send-test-push` | write | — | `POST lwr/apex/v68.0/interaction__JourneyController/sendTestPush` | `cms-content-fetch`, `segments-list`, `perm-can-send-test-push` |
|
|
179
|
+
| `send-test-inapp` | write | — | `POST lwr/apex/v68.0/interaction__JourneyController/sendTestInApp` | `cms-content-fetch`, `segments-list`, `perm-can-send-test-inapp` |
|
|
180
|
+
| `send-test-rcs` | write | — | `POST lwr/apex/v68.0/interaction__JourneyController/sendTestRcs` | `cms-content-fetch`, `segments-list`, `sender-rcs-agents`, `perm-can-send-test-rcs` |
|
|
181
|
+
| `sender-email-from-addresses` | read | — | `GET lwr/apex/v68.0/interaction__JourneyController/getFromAddresses` | — |
|
|
182
|
+
| `sender-email-dkim-valid` | verify | — | `GET lwr/apex/v68.0/interaction__JourneyController/fromAddressHasValidDKIM` | `sender-email-from-addresses` |
|
|
183
|
+
| `sender-sms-codes` | read | — | `GET lwr/apex/v68.0/interaction__JourneyController/getSenderSmsCodes` | — |
|
|
184
|
+
| `sender-whatsapp-numbers` | read | — | `GET lwr/apex/v68.0/interaction__JourneyController/getSenderWhatsappNumbers` | — |
|
|
185
|
+
| `sender-whatsapp-waba-ids` | read | — | `GET lwr/apex/v68.0/interaction__JourneyController/getSenderWabaIdsAndNames` | — |
|
|
186
|
+
| `sender-rcs-agents` | read | — | `GET lwr/apex/v68.0/interaction__JourneyController/getSenderRcsAgents` | — |
|
|
187
|
+
| `perm-can-send-test-email` | verify | — | `GET lwr/apex/v68.0/interaction__JourneyController/canUserSendTestEmail` | — |
|
|
188
|
+
| `perm-can-send-test-sms` | verify | — | `GET lwr/apex/v68.0/interaction__JourneyController/canUserSendTestSms` | — |
|
|
189
|
+
| `perm-can-send-test-whatsapp` | verify | — | `GET lwr/apex/v68.0/interaction__JourneyController/canUserSendTestWhatsapp` | — |
|
|
190
|
+
| `perm-can-send-test-push` | verify | — | `GET lwr/apex/v68.0/interaction__JourneyController/canUserSendTestPush` | — |
|
|
191
|
+
| `perm-can-send-test-inapp` | verify | — | `GET lwr/apex/v68.0/interaction__JourneyController/canUserSendTestInApp` | — |
|
|
192
|
+
| `perm-can-send-test-rcs` | verify | — | `GET lwr/apex/v68.0/interaction__JourneyController/canUserSendTestRcs` | — |
|
|
193
|
+
<!-- codey:operations end -->
|
|
194
|
+
<!-- skill-validate: ignore-end -->
|
|
@@ -0,0 +1,333 @@
|
|
|
1
|
+
# E360 Message Preview & Test-Send — API Contract
|
|
2
|
+
|
|
3
|
+
Full operation tables, request bodies, response-field rules, per-resource version floors, and the end-to-end recipe for all six E360 channels (Email, SMS, WhatsApp, Push, In-App, RCS). This is the detailed reference behind [../SKILL.md](../SKILL.md).
|
|
4
|
+
|
|
5
|
+
**Operations are referenced by their step id** (e.g. `preview-email-personalized`, `send-test-sms`, `sender-email-dkim-valid`). The exact instance-relative path for each step — the LWR-Apex or Connect REST address you actually call — is on that step's **Call** line in the skill's Operations Reference. Read the path there; the tables below give you the step id, verb category, and body shape.
|
|
6
|
+
|
|
7
|
+
## Two transports
|
|
8
|
+
|
|
9
|
+
| Purpose | Transport | Instance-relative path |
|
|
10
|
+
|---|---|---|
|
|
11
|
+
| Render preview · test send · sender lookups | **LWR Apex** | `lwr/apex/v68.0/…` (exact path on each step's **Call** line) |
|
|
12
|
+
| Managed content · data space · DMO · segment · profile | **Connect REST** | `services/data/vXX.0/…` (per-resource minimums below; v62.0+ covers every REST-derivation resource) |
|
|
13
|
+
|
|
14
|
+
**Call everything through `sf api request rest`, never `curl`.** The CLI attaches the org's bearer token internally — do **not** extract the org's access token (e.g. via `sf org display --json`) or put a token in a header, because that emits a live credential into tool output and your context. Pass the **instance-relative path** (no host); the CLI prepends the org's instance URL, and it accepts both transports (the LWR-Apex paths are not under `services/data/`, but the CLI does not restrict the path).
|
|
15
|
+
|
|
16
|
+
**One step is the exception** — `whatsapp-template-fetch` (Part 1, WhatsApp) is a headless **dispatch** route (`/headless/invoke/…`), invoked through the `dispatch` tool rather than `sf api request rest`. Every other operation in this reference uses `sf api request rest`.
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
# GET (default method)
|
|
20
|
+
sf api request rest '<instance-relative path from the step's Call line>' --target-org <org>
|
|
21
|
+
|
|
22
|
+
# POST with a flat JSON body (content-type: application/json is sent by default)
|
|
23
|
+
sf api request rest '<instance-relative path from the step's Call line>' --target-org <org> --method POST --body @body.json
|
|
24
|
+
# --body @file.json → read the body from a file (recommended for the flat payloads below)
|
|
25
|
+
# --body '{"contentKey":"…"}' → inline body, also fine for short payloads
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
**LWR Apex verb rule**: an operation's caching flag fixes its verb. Preview and test-send operations are **POST** (`--method POST`) with a flat JSON body whose keys are exactly the parameter names (no envelope). Sender/permission lookups are **GET** (default) with args packed into a single `methodParams` query param as a URL-encoded JSON string appended to the path; no-arg lookups omit it.
|
|
29
|
+
|
|
30
|
+
**Versions:**
|
|
31
|
+
- **LWR-Apex** — not version-gated (resolves down to ~v20.0); pin `v68.0` so the path carries a well-formed `vXX.0` segment (the examples use it consistently).
|
|
32
|
+
- **Connect REST** — real per-resource floors (noted at each call, v51–v62). Highest is `ssot/data-spaces` at **v62.0**, so **v62.0+** covers every REST-derivation resource; the rest are lower.
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
## Part 1 — Render a preview
|
|
37
|
+
|
|
38
|
+
LWR-Apex, all **POST**, body keys = parameter names. Read each operation's path from its **Call** line.
|
|
39
|
+
|
|
40
|
+
- **Unpersonalized** — content only, keyed by `contentKey` alone (plus `locale` for Email's locale variant).
|
|
41
|
+
- **Personalized** — rendered against one real recipient; needs `segmentId`, `recipientDataModelObjectName`, `contentKey`, `profileId`.
|
|
42
|
+
|
|
43
|
+
| Channel | Operation (step) | Body |
|
|
44
|
+
|---|---|---|
|
|
45
|
+
| Email | `preview-email-unpersonalized` | `{ contentKey }` |
|
|
46
|
+
| Email | `preview-email-unpersonalized-by-locale` | `{ contentKey, locale }` |
|
|
47
|
+
| Email | `preview-email-personalized` | `{ segmentId, recipientDataModelObjectName, contentKey, profileId, isContentBlock, recipientAttributesJson }` |
|
|
48
|
+
| Email | `preview-email-personalized-by-locale` | `{ segmentId, recipientDataModelObjectName, contentKey, profileId, isContentBlock, locale, recipientAttributesJson }` |
|
|
49
|
+
| SMS | `preview-sms-unpersonalized` | `{ contentKey }` |
|
|
50
|
+
| SMS | `preview-sms-personalized` | `{ segmentId, recipientDataModelObjectName, contentKey, profileId, recipientAttributesJson }` |
|
|
51
|
+
| WhatsApp | `preview-whatsapp-unpersonalized` | `{ contentKey }` |
|
|
52
|
+
| WhatsApp | `preview-whatsapp-personalized` | `{ segmentId, recipientDataModelObjectName, contentKey, profileId, recipientAttributesJson }` |
|
|
53
|
+
| Push | `preview-push-unpersonalized` | `{ contentKey }` |
|
|
54
|
+
| Push | `preview-push-personalized` | `{ segmentId, recipientDataModelObjectName, contentKey, profileId }` |
|
|
55
|
+
| In-App | `preview-inapp-unpersonalized` | `{ contentKey }` |
|
|
56
|
+
| In-App | `preview-inapp-personalized` | `{ segmentId, recipientDataModelObjectName, contentKey, profileId }` |
|
|
57
|
+
| RCS | `preview-rcs-unpersonalized` | `{ contentKey }` |
|
|
58
|
+
| RCS | `preview-rcs-personalized` | `{ segmentId, recipientDataModelObjectName, contentKey, profileId, recipientAttributesJson }` |
|
|
59
|
+
|
|
60
|
+
Only Email has locale-variant operations (the `…-by-locale` steps) and carries the extra `isContentBlock` field.
|
|
61
|
+
|
|
62
|
+
**Example — Email personalized** (write the flat body to a file, then POST it against the `preview-email-personalized-by-locale` step's Call path):
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
cat > body.json <<'JSON'
|
|
66
|
+
{
|
|
67
|
+
"segmentId": "1sgSG000000EXAMPLE",
|
|
68
|
+
"recipientDataModelObjectName": "UnifiedIndividual__dlm",
|
|
69
|
+
"contentKey": "MCKEXAMPLECONTENTKEY00000000",
|
|
70
|
+
"profileId": "00000000000000000000000000000000",
|
|
71
|
+
"isContentBlock": false,
|
|
72
|
+
"locale": null,
|
|
73
|
+
"recipientAttributesJson": null
|
|
74
|
+
}
|
|
75
|
+
JSON
|
|
76
|
+
|
|
77
|
+
sf api request rest '<preview-email-personalized-by-locale Call path>' \
|
|
78
|
+
--target-org <org> --method POST --body @body.json
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
**Example — SMS unpersonalized (minimal, inline body, against the `preview-sms-unpersonalized` step's Call path):**
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
sf api request rest '<preview-sms-unpersonalized Call path>' \
|
|
85
|
+
--target-org <org> --method POST --body '{ "contentKey": "MCKEXAMPLECONTENTKEY00000000" }'
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### Reading rendered output per channel
|
|
89
|
+
|
|
90
|
+
- **Email** — flat JSON object of string fields (`subject`, `preheader`, `body`, `nonAggregateHtmlBody`, `textBody`, …). Rendered HTML is in `body` for personalized calls, `nonAggregateHtmlBody` for unpersonalized — **read `body` first, fall back to `nonAggregateHtmlBody`**.
|
|
91
|
+
- **SMS** — rendered message is the plain **`content`** string; MMS also carries **`mediaUrl`** and **`isLinkShorteningEnabled`**.
|
|
92
|
+
- **WhatsApp** — returns `{ content, metadata }` where **both are JSON strings**. `content` is an ordered, positional list of parameter values per component. The template (with `{{1}} {{2}}` slots) is NOT in the preview response — fetch it (below) and reassemble.
|
|
93
|
+
- **Push / In-App / RCS** — read the returned rendered fields.
|
|
94
|
+
|
|
95
|
+
**Fetch media from the rendered `<img src>`, not the content definition.** Rendered srcs are public-CDN URLs (`…salesforce-experience.com/_scs/cms/<orgId>/<spaceId>/<fileHash>/<file>`) that fetch unauthenticated. The `contentBody` refs from §4.2 (`/cms/media/<mediaKey>?fileName=…&fileHash=…`) are session-gated — unauthenticated they return an HTML login page (HTTP 200, no error), not image bytes.
|
|
96
|
+
|
|
97
|
+
### WhatsApp — reconstructing the visible message text
|
|
98
|
+
|
|
99
|
+
Fetch the template via the **`whatsapp-template-fetch`** step. Unlike every other operation in this reference, this is **not** an `sf api request rest` call — it's a headless **dispatch** route (`/headless/invoke/…`, **GET**; inputs `templateId` + `wabaId`), so invoke it through the `dispatch` tool with the step's Call path and `templateId` + `wabaId` as query params. Both values come from the content body in §4.2 — content-body fields `wabaId` / `wabaTemplateId`, or parse `sfdc_cms:template.definition` = `@meta/{wabaId}/{lang}/{templateId}`; pass the `wabaTemplateId` value as the `templateId` input. Read the exact Call path from the Operations Reference:
|
|
100
|
+
|
|
101
|
+
```text
|
|
102
|
+
# whatsapp-template-fetch — a headless dispatch route (/headless/invoke/…), GET.
|
|
103
|
+
# NOT an `sf api request rest` call: /headless/invoke paths resolve to an invoke
|
|
104
|
+
# envelope on the platform, so route them through the dispatch tool, not the REST CLI.
|
|
105
|
+
#
|
|
106
|
+
# dispatch method=GET path=<whatsapp-template-fetch Call path>
|
|
107
|
+
# query params: { templateId, wabaId }
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
The **`json` field is HTML-entity-escaped** (`"`) — unescape, then parse; it holds the Meta template definition. **Reassemble**: for each component, `{{k}}` is **1-indexed** into that same component's `parameters[]` from the preview `content`. Replace `{{k}}` with `parameters[k-1].text`. Match components by `type` (BODY↔body, HEADER↔header). A component with no placeholders (e.g. a static HEADER) is omitted from `content` — use its template `text` verbatim. Personalized preview yields final text; unpersonalized leaves mapping expressions in the slots.
|
|
111
|
+
|
|
112
|
+
---
|
|
113
|
+
|
|
114
|
+
## Part 2 — Send a test message
|
|
115
|
+
|
|
116
|
+
**Permission gate — check first, every time.** Before firing a test send, call the channel's permission check. LWR-Apex, all **GET**, no args, returns `Boolean`. If it returns `false`, surface a permission error and **stop** — do not attempt the send. Read each operation's path from its **Call** line.
|
|
117
|
+
|
|
118
|
+
| Channel | Operation (step) | Params | Returns |
|
|
119
|
+
|---|---|---|---|
|
|
120
|
+
| Email | `perm-can-send-test-email` | *(none)* | `Boolean` — `canUserSendTestEmail` |
|
|
121
|
+
| SMS | `perm-can-send-test-sms` | *(none)* | `Boolean` — `canUserSendTestSms` |
|
|
122
|
+
| Push | `perm-can-send-test-push` | *(none)* | `Boolean` — `canUserSendTestPush` |
|
|
123
|
+
| In-App | `perm-can-send-test-inapp` | *(none)* | `Boolean` — `canUserSendTestInApp` |
|
|
124
|
+
| RCS | `perm-can-send-test-rcs` | *(none)* | `Boolean` — `canUserSendTestRcs` |
|
|
125
|
+
|
|
126
|
+
Then the send itself — LWR-Apex, all **POST**. Email returns a `Map`; others return a `String` result id. Read each operation's path from its **Call** line.
|
|
127
|
+
|
|
128
|
+
| Channel | Operation (step) | Body |
|
|
129
|
+
|---|---|---|
|
|
130
|
+
| Email | `send-test-email` | `{ segmentId, recipientDataModelObjectName, contentKey, profileId, fromAddress, toAddresses }` |
|
|
131
|
+
| Email | `send-test-email-by-locale` | `{ segmentId, recipientDataModelObjectName, contentKey, profileId, fromAddress, toAddresses, locale, recipientAttributesJson }` |
|
|
132
|
+
| SMS | `send-test-sms` | `{ segmentId, recipientDataModelObjectName, contentKey, profileId, senderId, toPhoneNumbers, recipientAttributesJson }` |
|
|
133
|
+
| WhatsApp | `send-test-whatsapp` | `{ segmentId, recipientDataModelObjectName, contentKey, profileId, senderId, toPhoneNumbers, recipientAttributesJson }` |
|
|
134
|
+
| Push | `send-test-push` | `{ segmentId, recipientDataModelObjectName, contentKey, profileId, senderId, toIndividualIds }` |
|
|
135
|
+
| In-App | `send-test-inapp` | `{ segmentId, recipientDataModelObjectName, contentKey, profileId, senderId, toIndividualIds }` |
|
|
136
|
+
| RCS | `send-test-rcs` | `{ segmentId, recipientDataModelObjectName, contentKey, profileId, senderId, toPhoneNumbers, recipientAttributesJson }` |
|
|
137
|
+
|
|
138
|
+
- **Destination field differs by channel**: Email → `toAddresses`, SMS/WhatsApp/RCS → `toPhoneNumbers`, Push/In-App → `toIndividualIds`. All are JSON string arrays — the tester's own destinations, supplied by the user, never derived.
|
|
139
|
+
- **`fromAddress` (Email) / `senderId` (everyone else)** identify the sending identity — derive via Part 3.
|
|
140
|
+
- Core message inputs (`segmentId`, `recipientDataModelObjectName`, `contentKey`, `profileId`) are identical to the personalized-preview inputs — derive once, reuse.
|
|
141
|
+
- **A test send is a real send.** Only call these when the user explicitly asked to test-send and supplied their own destinations.
|
|
142
|
+
|
|
143
|
+
---
|
|
144
|
+
|
|
145
|
+
## Part 3 — Sender / from-address inputs (test send only)
|
|
146
|
+
|
|
147
|
+
LWR-Apex, all **GET** — args via `methodParams`, or omit for no-arg. Read each operation's path from its **Call** line.
|
|
148
|
+
|
|
149
|
+
| Channel | Operation (step) | Params | Returns |
|
|
150
|
+
|---|---|---|---|
|
|
151
|
+
| Email | `sender-email-from-addresses` | *(none)* | available from-addresses → pick one for `fromAddress` |
|
|
152
|
+
| Email | `sender-email-dkim-valid` | `{ fromAddress }` | `Boolean` — validate before sending |
|
|
153
|
+
| SMS | `sender-sms-codes` | *(none)* | sender codes → pick `senderId` |
|
|
154
|
+
| RCS | `sender-rcs-agents` | *(none)* | RCS agents → pick `senderId` |
|
|
155
|
+
| WhatsApp | `sender-whatsapp-numbers` | *(none)* | WhatsApp numbers → pick `senderId` |
|
|
156
|
+
| WhatsApp | `sender-whatsapp-waba-ids` | *(none)* | WABA ids/names |
|
|
157
|
+
|
|
158
|
+
```bash
|
|
159
|
+
# list SMS sender codes (no-arg → no methodParams) — against the sender-sms-codes step's Call path
|
|
160
|
+
sf api request rest '<sender-sms-codes Call path>' --target-org <org>
|
|
161
|
+
|
|
162
|
+
# validate an Email from-address (step sender-email-dkim-valid) — methodParams is a URL-encoded
|
|
163
|
+
# JSON string appended to the path as ?methodParams=… (there is no --data-urlencode; encode it
|
|
164
|
+
# into the query string). Here {"fromAddress":"noreply@example.com"} encodes to
|
|
165
|
+
# %7B%22fromAddress%22%3A%22noreply%40example.com%22%7D
|
|
166
|
+
sf api request rest '<sender-email-dkim-valid Call path>?methodParams=%7B%22fromAddress%22%3A%22noreply%40example.com%22%7D' \
|
|
167
|
+
--target-org <org>
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
Preview needs **no** sender — skip Part 3 unless test-sending. On Business-Unit-enabled orgs, sender lists are scoped by BU — use the Business-Unit-scoped variants of these lookups and pass `businessUnitId` (§4.7).
|
|
171
|
+
|
|
172
|
+
---
|
|
173
|
+
|
|
174
|
+
## Part 4 — Deriving the inputs
|
|
175
|
+
|
|
176
|
+
Everything above needs, at most, these values, all chained from the **`contentKey`**.
|
|
177
|
+
|
|
178
|
+
| Input | Required for | Where it comes from |
|
|
179
|
+
|---|---|---|
|
|
180
|
+
| `contentKey` | every call | given (the message you're previewing) |
|
|
181
|
+
| `locale` | Email `…-by-locale` | caller (`null` = default) |
|
|
182
|
+
| `recipientDataModelObjectName` (DMO) | personalized / send | parsed from the content (§4.3) |
|
|
183
|
+
| `segmentId` | personalized / send | segment list (§4.5) |
|
|
184
|
+
| `profileId` | personalized / send | segment member (§4.6) — must be a member of `segmentId` |
|
|
185
|
+
| `isContentBlock` | Email personalized | caller flag (`false` default) |
|
|
186
|
+
| `recipientAttributesJson` | Email, SMS, WhatsApp, RCS personalized / send | caller (`null` default); not Push/In-App |
|
|
187
|
+
|
|
188
|
+
### 4.1 `contentKey` — the seed
|
|
189
|
+
|
|
190
|
+
Identifies the authored message. Given up front; not derivable. Everything below flows from it.
|
|
191
|
+
|
|
192
|
+
### 4.2 Fetch the managed content
|
|
193
|
+
|
|
194
|
+
Use the CMS **Authoring** API — keyed directly by `contentKey`, returns drafts (what preview renders):
|
|
195
|
+
|
|
196
|
+
```bash
|
|
197
|
+
# GET /connect/cms/contents/{contentKeyOrId} — v57+ (step cms-content-fetch)
|
|
198
|
+
sf api request rest \
|
|
199
|
+
'services/data/vXX.0/connect/cms/contents/{contentKeyOrId}' \
|
|
200
|
+
--target-org <org>
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
Accepts either `contentKey` or the `20Y…` managed-content id. Optional query params `language`, `version`, `variantVersion`, `contentVersion`. Response carries `contentKey`, `managedContentId`, `contentBody`.
|
|
204
|
+
|
|
205
|
+
### 4.3 Determine the recipient DMO → `recipientDataModelObjectName`
|
|
206
|
+
|
|
207
|
+
Resolve the DMO **first** — the data space (§4.4) is derived from its name. Read it from `contentBody['lightning:dataProviders']` (from §4.2):
|
|
208
|
+
- a provider with `attributes.objectApiName` → that value **is** the DMO;
|
|
209
|
+
- a provider with `attributes.dataGraphApiName` → resolve the graph's primary object via
|
|
210
|
+
`GET /services/data/vXX.0/ssot/data-graphs/{dataGraphApiName}` (v58+, step `data-graph-primary-object`) — read
|
|
211
|
+
**`primaryObjectName`** (that is the DMO). The same response also carries
|
|
212
|
+
**`dataspaceName`**, which you can use directly for §4.4 instead of deriving the data
|
|
213
|
+
space from the DMO-name prefix. (The graph name goes in the **path**, not a query param —
|
|
214
|
+
`?dataGraphApiName=`/`?dataGraphName=` both error `"Empty Data Graph Name"`.)
|
|
215
|
+
|
|
216
|
+
**Org fallback — content declares no DMO:** there is no name to derive a data space from, so pick the data space first (§4.4 — explicitly, or `default` on a single-space org), then call the org-fallback lookup (step `messaging-selected-uma-dmo`), an LWR-Apex **POST** with a flat body:
|
|
217
|
+
|
|
218
|
+
```bash
|
|
219
|
+
sf api request rest '<messaging-selected-uma-dmo Call path>' \
|
|
220
|
+
--target-org <org> --method POST --body '{ "dataSpaceName": "<dataSpaceName>" }'
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
Returns the admin-configured Unified Individual DMO. Returns **`null`** if neither a Customer Engagement Data Graph nor an Identity Resolution ruleset is configured — treat as "no personalized preview available for this org," not a retryable error.
|
|
224
|
+
|
|
225
|
+
### 4.4 Identify the data space
|
|
226
|
+
|
|
227
|
+
```bash
|
|
228
|
+
# GET /ssot/data-spaces — v62+ (step data-spaces-list)
|
|
229
|
+
sf api request rest \
|
|
230
|
+
'services/data/vXX.0/ssot/data-spaces' \
|
|
231
|
+
--target-org <org>
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
Each entry has `name`, `label`, **`prefix`**. Use the matching entry's **`name`** as `dataspace`; `default` if the org has only one space. **Deterministic match from the DMO name** (§4.3):
|
|
235
|
+
|
|
236
|
+
- Begins with `ssot__` (e.g. `ssot__UnifiedIndividual__dlm`) → **`default`**, no lookup needed.
|
|
237
|
+
- Carries a recognized `<prefix>_` token (e.g. `EM1_UnifiedIndividual__dlm` → prefix `EM1`) — match against `/ssot/data-spaces`' `prefix` field and take the entry's `name`.
|
|
238
|
+
- No `ssot__` and no leading token matching any listed `prefix` (e.g. plain `UnifiedIndividual__dlm`) → **`default`** (the space with no `prefix`).
|
|
239
|
+
|
|
240
|
+
In the org-fallback case (§4.3, no DMO) there's no prefix to parse — pick the space explicitly, or `default` on a single-space org, **before** calling the fallback.
|
|
241
|
+
|
|
242
|
+
### 4.5 Pick a published segment → `segmentId`
|
|
243
|
+
|
|
244
|
+
```bash
|
|
245
|
+
# GET /ssot/segments — v55+ (step segments-list)
|
|
246
|
+
sf api request rest \
|
|
247
|
+
'services/data/vXX.0/ssot/segments?dataspace=<dataSpaceName>' \
|
|
248
|
+
--target-org <org>
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
Ask the user which segment to use and validate it has data. Keep the segment's **`apiName`** (fetches members, §4.6) and the `1sg…` **`marketSegmentId`** (the **`segmentId`** preview/send calls take).
|
|
252
|
+
|
|
253
|
+
### 4.6 Pick a recipient → `profileId`
|
|
254
|
+
|
|
255
|
+
Need one member of the chosen segment in the content's data space. **The recipient comes only from the segment's member list** — the `profileId` must be a member of the `segmentId` you pass to the render, or the render rejects it with an opaque error.
|
|
256
|
+
|
|
257
|
+
```bash
|
|
258
|
+
# segment members — GET /ssot/segments/{segmentApiName}/members — v58+ (step segment-members-list)
|
|
259
|
+
sf api request rest \
|
|
260
|
+
'services/data/vXX.0/ssot/segments/{segmentApiName}/members?limit=10&dataspace=<dataSpaceName>' \
|
|
261
|
+
--target-org <org>
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
- **The member `id` is your `profileId`.** Each row's profile key (e.g. `a1b2c3d4…` — **not** a `1sg…` segment id or a `003…` CRM id) is returned under **`id`**, and it is a member of the segment, so the render accepts it.
|
|
265
|
+
- **Empty member list → personalization cannot be performed.** An empty response (the segment has no members), or no segment in the content's data space, means there is no valid recipient: report `cannot personalize — no valid segment member` and stop. It is **not** a retryable error, and there is no fallback recipient source — do **not** list individuals from the DMO to manufacture a `profileId`; one that isn't a member of the passed `segmentId` is rejected by the render.
|
|
266
|
+
- The unpersonalized preview (`contentKey` only, §4.8/Part 5) does not need a recipient — offer it when personalization can't be performed.
|
|
267
|
+
|
|
268
|
+
*(To confirm a specific `profileId` exists (step `profile-fetch-by-id`):* `GET /services/data/vXX.0/ssot/profile/{dmoName}/{profileId}?dataspace=<dataSpaceName>` *— 200 = confirmed.)*
|
|
269
|
+
|
|
270
|
+
### 4.7 Get `businessUnitId` (BU-enabled orgs, test send only)
|
|
271
|
+
|
|
272
|
+
```bash
|
|
273
|
+
# GET /connect/cms/spaces — v53+ (step cms-spaces-list)
|
|
274
|
+
sf api request rest \
|
|
275
|
+
'services/data/vXX.0/connect/cms/spaces' \
|
|
276
|
+
--target-org <org>
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
Match the entry whose `id` equals the content's `contentSpace.id` (from §4.2) and read its **`businessUnit.id`** → `businessUnitId`. Preview never needs it.
|
|
280
|
+
|
|
281
|
+
### 4.8 The remaining flags
|
|
282
|
+
|
|
283
|
+
- **`locale`** — `null` for default; a locale code (e.g. `en_US`) only to force one. Email `…-by-locale` only.
|
|
284
|
+
- **`isContentBlock`** (Email) — `false` for a full message, `true` for a reusable content block. Default `false`.
|
|
285
|
+
- **`recipientAttributesJson`** (Email, SMS, WhatsApp, RCS) — `null` unless specifying content variables (§4.9), serialized as a JSON string. Not accepted by Push/In-App.
|
|
286
|
+
|
|
287
|
+
### 4.9 Content variables — you must supply values
|
|
288
|
+
|
|
289
|
+
Content variables (e.g. `{{$content.Input}}`) are author-left blanks with no data behind them — they render empty unless you pass a value. Find them under **`sfdc_cms:schema.properties`** in the content (§4.2); each key is one variable. Get a value for each **before** previewing (ask the user; don't invent one), and supply via `recipientAttributesJson` (Email, SMS, WhatsApp, RCS) as a JSON **string**: `"{\"$content\": { \"<variable>\": <value>, … }}"`.
|
|
290
|
+
|
|
291
|
+
**Push and In-App personalized previews do not support content variables.** If any are declared in the content definition for one of those channels, inform the user it's not supported — do not troubleshoot.
|
|
292
|
+
|
|
293
|
+
---
|
|
294
|
+
|
|
295
|
+
## Part 5 — End-to-end recipe
|
|
296
|
+
|
|
297
|
+
**Personalized preview, given only `contentKey`:**
|
|
298
|
+
|
|
299
|
+
1. `GET /connect/cms/contents/{contentKey}` (v57+, step `cms-content-fetch`) → `managedContentId`, `contentBody`.
|
|
300
|
+
2. Parse `contentBody` → **DMO** (`objectApiName` / `dataGraphApiName`, §4.3). If the content declares none, leave it for step 3's fallback.
|
|
301
|
+
3. **dataSpaceName** (§4.4) — scopes every `/ssot/…` call below. DMO declared: derive it from the DMO name via `GET /ssot/data-spaces` (step `data-spaces-list`). No DMO declared: pick the space explicitly (or `default` on a single-space org), then call the org-fallback lookup (step `messaging-selected-uma-dmo`) with `{ dataSpaceName }` → **DMO** (`null` → no personalized preview available for this org).
|
|
302
|
+
4. `GET /ssot/segments?dataspace={dataSpaceName}` (step `segments-list`) → pick a segment; keep `segmentApiName` and `1sg…` id (**segmentId**).
|
|
303
|
+
5. Get **profileId** from the segment's members (§4.6, the only valid source): `GET /ssot/segments/{segmentApiName}/members?limit=10&dataspace={dataSpaceName}` (step `segment-members-list`) → member `id`. If the member list is empty (or no segment exists in the data space), **stop** — report `cannot personalize — no valid segment member` and offer the unpersonalized preview; the `profileId` must be a member of the segment, so there is no fallback recipient source.
|
|
304
|
+
6. Call the channel's personalized-preview operation (step `preview-<channel>-personalized`, or the `…-by-locale` variant) with `{ segmentId, recipientDataModelObjectName, contentKey, profileId, … }`.
|
|
305
|
+
|
|
306
|
+
**Unpersonalized preview** short-circuits after step 1: call the channel's unpersonalized-preview operation (step `preview-<channel>-unpersonalized`) with `{ contentKey }` (add `locale` for Email's locale variant).
|
|
307
|
+
|
|
308
|
+
**Test send** = the channel's permission check (step `perm-can-send-test-<channel>`, Part 2; stop if `false`), then steps 1–6, then a Part 3 sender lookup for `fromAddress`/`senderId`, then the channel's test-send operation (step `send-test-<channel>`) with your supplied destination array.
|
|
309
|
+
|
|
310
|
+
---
|
|
311
|
+
|
|
312
|
+
## Field glossary
|
|
313
|
+
|
|
314
|
+
| Field | Type | Meaning |
|
|
315
|
+
|---|---|---|
|
|
316
|
+
| `contentKey` | String | Identifier of the authored message. Keys every preview/send call. |
|
|
317
|
+
| `managedContentId` | String | The content's record id (`20Y…`). Returned alongside `contentKey`. |
|
|
318
|
+
| `dataSpaceName` | String | Data Cloud data space name; the `dataspace` query param scoping the `/ssot/…` lookups. Must match the content. |
|
|
319
|
+
| `recipientDataModelObjectName` | String | The **table** — the DMO the recipient is looked up in, e.g. `UnifiedIndividual__dlm`. |
|
|
320
|
+
| `segmentId` | String | The segment **record** id (`1sg…`) passed to preview/send. |
|
|
321
|
+
| `segmentApiName` | String | The segment **developer** name used to fetch members over REST. |
|
|
322
|
+
| `profileId` | String | The **person** — a Data Cloud profile key, **not** a CRM id. |
|
|
323
|
+
| `isContentBlock` | Boolean | Email only — reusable content block vs. full message. |
|
|
324
|
+
| `locale` | String | Email `…-by-locale` only — locale override; `null` = default. |
|
|
325
|
+
| `recipientAttributesJson` | String | Email, SMS, WhatsApp, RCS — JSON string of content-variable overrides; `null` = none. Not Push/In-App. |
|
|
326
|
+
| `fromAddress` / `senderId` | String | Sending identity for a test send (Email vs. all other channels). |
|
|
327
|
+
| `toAddresses` / `toPhoneNumbers` / `toIndividualIds` | String[] | Your tester's own destinations for a test send (channel-dependent). |
|
|
328
|
+
|
|
329
|
+
**The identifier trio**: `segmentId` (`1sg…`) = *which audience*; `recipientDataModelObjectName` (`…__dlm`) = *which table the members live in*; `profileId` (profile key) = *which person*. DMO + `profileId` together identify one individual — neither alone suffices.
|
|
330
|
+
|
|
331
|
+
## Version floors (verified on a v69.0 org)
|
|
332
|
+
|
|
333
|
+
LWR-Apex not gated (works to v20; pin `v68.0` so the path segment is well-formed). REST derivation resources: `/connect/cms/spaces` v53, segments v55, contents v57, members v58, data-graphs v58, data-spaces v62; profile v51 (docs) but requires a `filters=[field=value]` param. Highest REST floor is data-spaces at v62 — target **v62.0+** for full six-channel coverage (this is why `minApiVersion` is `62.0`).
|
|
@@ -2,6 +2,9 @@
|
|
|
2
2
|
name: omnistudio-callable-apex-generate
|
|
3
3
|
description: "Salesforce Industries Common Core (OmniStudio/Vlocity) Apex callable generation and review skill with 120-point scoring. Use when creating, reviewing, or migrating Industries callable Apex implementations. TRIGGER when: user creates or reviews System.Callable classes, migrates VlocityOpenInterface or VlocityOpenInterface2, or builds Industries callable extensions used by OmniStudio, Integration Procedures, or DataRaptors. DO NOT TRIGGER when: generic Apex classes or triggers (use platform-apex-generate), building Integration Procedures (use omnistudio-integration-procedure-generate), authoring OmniScripts (use omnistudio-omniscript-generate), configuring Data Mappers (use omnistudio-datamapper-generate), or analyzing namespace/dependency issues (use omnistudio-dependencies-analyze)."
|
|
4
4
|
metadata:
|
|
5
|
+
version: "1.0"
|
|
6
|
+
domains: ["OmniStudio"]
|
|
7
|
+
minApiVersion: "60.0"
|
|
5
8
|
relatedSkills:
|
|
6
9
|
- "external-diagram-mermaid-generate"
|
|
7
10
|
- "omnistudio-datamapper-generate"
|
|
@@ -15,9 +18,6 @@ metadata:
|
|
|
15
18
|
- "platform-data-manage"
|
|
16
19
|
- "platform-metadata-deploy"
|
|
17
20
|
- "platform-soql-query"
|
|
18
|
-
version: "1.0"
|
|
19
|
-
domains: ["OmniStudio"]
|
|
20
|
-
minApiVersion: "60.0"
|
|
21
21
|
---
|
|
22
22
|
|
|
23
23
|
# omnistudio-callable-apex-generate: Callable Apex for Salesforce Industries Common Core
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
name: omnistudio-datamapper-generate
|
|
3
3
|
description: "OmniStudio Data Mapper (formerly DataRaptor) creation and validation with 100-point scoring. Use when building Extract, Transform, Load, or Turbo Extract Data Mappers, mapping Salesforce object fields, or reviewing existing Data Mapper configurations. TRIGGER when: user creates Data Mappers, configures field mappings, works with OmniDataTransform metadata, or asks about DataRaptor/Data Mapper patterns. DO NOT TRIGGER when: building Integration Procedures (use omnistudio-integration-procedure-generate), authoring OmniScripts (use omnistudio-omniscript-generate), or analyzing cross-component dependencies (use omnistudio-dependencies-analyze)."
|
|
4
4
|
metadata:
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
version: "1.0"
|
|
6
|
+
domains: ["OmniStudio"]
|
|
7
|
+
minApiVersion: "60.0"
|
|
8
8
|
relatedSkills:
|
|
9
9
|
- "omnistudio-dependencies-analyze"
|
|
10
10
|
- "omnistudio-flexcard-generate"
|
|
@@ -14,9 +14,9 @@ metadata:
|
|
|
14
14
|
- "platform-custom-object-generate"
|
|
15
15
|
- "platform-metadata-deploy"
|
|
16
16
|
- "platform-soql-query"
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
17
|
+
cliTools:
|
|
18
|
+
- tool: ["sf"]
|
|
19
|
+
semver: ">=2.0.0"
|
|
20
20
|
---
|
|
21
21
|
|
|
22
22
|
# omnistudio-datamapper-generate: OmniStudio Data Mapper Creation and Validation
|
|
@@ -2,15 +2,8 @@
|
|
|
2
2
|
name: omnistudio-datapacks-deploy
|
|
3
3
|
description: "Salesforce Industries DataPack deployment automation using Vlocity Build. TRIGGER when: user deploys or validates OmniStudio/Vlocity DataPacks with vlocity commands (packDeploy/packRetry/packExport/packGetDiffs), sets up DataPack CI/CD pipelines, or troubleshoots DataPack migration errors. DO NOT TRIGGER when: deploying Salesforce metadata with sf project deploy (use platform-metadata-deploy), authoring OmniStudio artifacts (use omnistudio-*-build), or writing Apex/LWC business logic (use platform-apex-generate/experience-lwc-generate)."
|
|
4
4
|
metadata:
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
semver: ">=9.0.0"
|
|
8
|
-
- tool: ["npx"]
|
|
9
|
-
semver: ">=9.0.0"
|
|
10
|
-
- tool: ["sf"]
|
|
11
|
-
semver: ">=2.0.0"
|
|
12
|
-
- tool: ["vlocity"]
|
|
13
|
-
semver: ">=1.16.0"
|
|
5
|
+
version: "1.0"
|
|
6
|
+
domains: ["OmniStudio"]
|
|
14
7
|
relatedSkills:
|
|
15
8
|
- "experience-lwc-generate"
|
|
16
9
|
- "omnistudio-epc-catalog-generate"
|
|
@@ -20,8 +13,15 @@ metadata:
|
|
|
20
13
|
- "platform-apex-generate"
|
|
21
14
|
- "platform-apex-logs-debug"
|
|
22
15
|
- "platform-metadata-deploy"
|
|
23
|
-
|
|
24
|
-
|
|
16
|
+
cliTools:
|
|
17
|
+
- tool: ["npm"]
|
|
18
|
+
semver: ">=9.0.0"
|
|
19
|
+
- tool: ["npx"]
|
|
20
|
+
semver: ">=9.0.0"
|
|
21
|
+
- tool: ["sf"]
|
|
22
|
+
semver: ">=2.0.0"
|
|
23
|
+
- tool: ["vlocity"]
|
|
24
|
+
semver: ">=1.16.0"
|
|
25
25
|
---
|
|
26
26
|
|
|
27
27
|
# omnistudio-datapacks-deploy: Vlocity Build DataPack Deployment
|