@salesforce/afv-skills 1.65.0 → 1.65.1
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/field-service-data-capture-form-deployer-configure/SKILL.md +2 -23
- package/skills/field-service-data-capture-form-designer-configure/SKILL.md +3 -13
- package/skills/field-service-mobile-branding-configure/SKILL.md +3 -17
- package/skills/field-service-objective-designer-configure/SKILL.md +379 -72
- package/skills/field-service-prework-brief-deployer-configure/SKILL.md +537 -10
- package/skills/field-service-scheduling-policy-designer-query/SKILL.md +1093 -65
- package/skills/field-service-sobject-create-configure/SKILL.md +213 -13
- package/skills/field-service-voice-to-form-configure/SKILL.md +11 -40
- package/skills/field-service-work-rule-designer-configure/SKILL.md +95 -121
- package/skills/agentforce-gpt-email-generation-configure/SKILL.md +0 -312
- package/skills/agentforce-wizard-ui-forecasting-analytics-components-configure/SKILL.md +0 -64
- package/skills/agentforce-wizard-ui-sales-einstein-components-configure/SKILL.md +0 -46
- package/skills/automation-company-profile-info-query/SKILL.md +0 -51
- package/skills/automation-digital-wallet-configure/SKILL.md +0 -689
- package/skills/automation-flow-coordinate/SKILL.md +0 -95
- package/skills/automation-flow-coordinate/references/elements/action-call/action-call.md +0 -1569
- package/skills/automation-flow-coordinate/references/elements/action-call/conversation-messaging.md +0 -96
- package/skills/automation-flow-coordinate/references/elements/action-call/examples/send-sms-message.json +0 -23
- package/skills/automation-flow-coordinate/references/elements/action-call/examples/send-to-journey-no-fields.json +0 -31
- package/skills/automation-flow-coordinate/references/elements/action-call/send-to-journey.md +0 -179
- package/skills/automation-flow-coordinate/references/elements/exit-rule/examples/event-email-link-click.json +0 -13
- package/skills/automation-flow-coordinate/references/elements/exit-rule/exit-rule.md +0 -83
- package/skills/automation-flow-coordinate/references/elements/forward-to-bot-or-agent/examples/forward-to-bot-or-agent.json +0 -69
- package/skills/automation-flow-coordinate/references/elements/forward-to-bot-or-agent/forward-to-bot-or-agent.md +0 -274
- package/skills/automation-flow-coordinate/references/elements/start/audience-common.md +0 -192
- package/skills/automation-flow-coordinate/references/elements/start/automation-event-triggered.md +0 -130
- package/skills/automation-flow-coordinate/references/elements/start/data-cloud-data-change-triggered.md +0 -92
- package/skills/automation-flow-coordinate/references/elements/start/form-submission-triggered.md +0 -88
- package/skills/automation-flow-coordinate/references/elements/start/segment-triggered.md +0 -152
- package/skills/automation-flow-coordinate/references/elements/start/start.md +0 -539
- package/skills/automation-flow-coordinate/references/elements/subflow/subflow.md +0 -152
- package/skills/automation-flow-coordinate/references/elements/wait/wait.md +0 -497
- package/skills/automation-flow-coordinate/references/recipes/author/author.md +0 -868
- package/skills/automation-flow-coordinate/references/recipes/summarize/element-generic.md +0 -300
- package/skills/automation-flow-coordinate/references/recipes/summarize/reference-resolution.md +0 -292
- package/skills/automation-flow-coordinate/references/recipes/summarize/summarize.md +0 -323
- package/skills/automation-flow-coordinate/references/recipes/testing/examples/debug-output-template.md +0 -109
- package/skills/automation-flow-coordinate/references/recipes/testing/shape.md +0 -219
- package/skills/automation-flow-coordinate/references/recipes/testing/shared-stages/intent-analyzer.md +0 -180
- package/skills/automation-flow-coordinate/references/recipes/testing/workflows/debug.md +0 -175
- package/skills/automation-flow-coordinate/references/recipes/testing/workflows/promote.md +0 -255
- package/skills/automation-flow-coordinate/references/recipes/testing/workflows/save-debug.md +0 -212
- package/skills/automation-flow-coordinate/references/resources/variable/variable.md +0 -171
- package/skills/automation-flow-coordinate/references/shared/anti-patterns.md +0 -786
- package/skills/automation-flow-coordinate/references/shared/end/end.md +0 -267
- package/skills/automation-flow-coordinate/references/shared/flow-type-resolver/eval/README.md +0 -69
- package/skills/automation-flow-coordinate/references/shared/flow-type-resolver/eval/predictions.jsonl +0 -80
- package/skills/automation-flow-coordinate/references/shared/flow-type-resolver/eval/prompts.jsonl +0 -116
- package/skills/automation-flow-coordinate/references/shared/flow-type-resolver/flow-type-resolver.md +0 -321
- package/skills/automation-flow-coordinate/references/shared/flow-type-resolver/taxonomy.json +0 -320
- package/skills/automation-flow-coordinate/references/shared/server-functions.md +0 -597
- package/skills/automotive-cloud-appraisal-management-settings-configure/SKILL.md +0 -69
- package/skills/automotive-cloud-dealer-essentials-configure/SKILL.md +0 -78
- package/skills/automotive-cloud-ground-agent-data-pipelines-configure/SKILL.md +0 -373
- package/skills/automotive-cloud-ground-mfg-agent-data-pipelines-configure/SKILL.md +0 -273
- package/skills/automotive-cloud-mfg-agent-data-pipelines-configure/SKILL.md +0 -259
- package/skills/automotive-cloud-mfg-sales-concierge-agent-create/SKILL.md +0 -369
- package/skills/automotive-cloud-mfg-sales-concierge-foundation-configure/SKILL.md +0 -542
- package/skills/automotive-cloud-mfg-sales-concierge-foundation-coordinate/SKILL.md +0 -159
- package/skills/automotive-cloud-mfg-sales-concierge-orchestrator-agent-create/SKILL.md +0 -349
- package/skills/automotive-cloud-mfg-sales-concierge-orchestrator-configure/SKILL.md +0 -505
- package/skills/automotive-cloud-sales-concierge-agent-create/SKILL.md +0 -380
- package/skills/automotive-cloud-sales-concierge-foundation-configure/SKILL.md +0 -567
- package/skills/automotive-cloud-sales-concierge-foundation-coordinate/SKILL.md +0 -159
- package/skills/automotive-cloud-sales-concierge-orchestrator-agent-create/SKILL.md +0 -360
- package/skills/automotive-cloud-sales-concierge-orchestrator-configure/SKILL.md +0 -539
- package/skills/automotive-cloud-sales-concierge-search-grounding-configure/SKILL.md +0 -358
- package/skills/commerce-b2b-merchant-quote-configure/SKILL.md +0 -602
- package/skills/commerce-b2b-store-configure/SKILL.md +0 -251
- package/skills/commerce-credit-memo-create/SKILL.md +0 -139
- package/skills/commerce-delivery-business-hours-configure/SKILL.md +0 -277
- package/skills/commerce-delivery-estimation-apply/SKILL.md +0 -155
- package/skills/commerce-delivery-estimation-configure/SKILL.md +0 -377
- package/skills/commerce-delivery-routing-specs-integrate/SKILL.md +0 -174
- package/skills/commerce-estimate-bopis-query/SKILL.md +0 -279
- package/skills/commerce-estimate-delivery-date-query/SKILL.md +0 -349
- package/skills/commerce-fees-apply/SKILL.md +0 -227
- package/skills/commerce-fulfillment-routing-analyze/SKILL.md +0 -200
- package/skills/commerce-guest-buyer-create/SKILL.md +0 -173
- package/skills/commerce-location-bopis-configure/SKILL.md +0 -378
- package/skills/commerce-location-business-hours-configure/SKILL.md +0 -235
- package/skills/commerce-location-delivery-processing-time-configure/SKILL.md +0 -309
- package/skills/commerce-location-graph-integrate/SKILL.md +0 -131
- package/skills/commerce-location-shipping-carrier-method-configure/SKILL.md +0 -755
- package/skills/commerce-location-temporary-operating-hours-configure/SKILL.md +0 -331
- package/skills/commerce-merchant-buyer-groups-configure/SKILL.md +0 -579
- package/skills/commerce-merchant-buyer-user-onboarding-create/SKILL.md +0 -626
- package/skills/commerce-merchant-catalog-configure/SKILL.md +0 -614
- package/skills/commerce-merchant-extension-provider-configure/SKILL.md +0 -368
- package/skills/commerce-merchant-insights-account-health-churn-analyze/SKILL.md +0 -118
- package/skills/commerce-merchant-insights-inventory-returns-analyze/SKILL.md +0 -65
- package/skills/commerce-merchant-insights-order-shopper-get/SKILL.md +0 -90
- package/skills/commerce-merchant-insights-product-performance-analyze/SKILL.md +0 -72
- package/skills/commerce-merchant-insights-query/SKILL.md +0 -279
- package/skills/commerce-merchant-storefront-guest-access-configure/SKILL.md +0 -656
- package/skills/commerce-order-summary-change-apply/SKILL.md +0 -375
- package/skills/commerce-product-details-get/SKILL.md +0 -363
- package/skills/commerce-product-search/SKILL.md +0 -563
- package/skills/commerce-react-storefront-create/SKILL.md +0 -350
- package/skills/commerce-return-order-summary-create/SKILL.md +0 -513
- package/skills/commerce-search-relevance-analyze/SKILL.md +0 -757
- package/skills/commerce-temporary-processing-time-override-create/SKILL.md +0 -274
- package/skills/communications-initial-setup-configure/SKILL.md +0 -630
- package/skills/communications-multisite-configure/SKILL.md +0 -571
- package/skills/communications-revenue-cloud-settings-configure/SKILL.md +0 -74
- package/skills/communications-smb-fiber-catalog-create/SKILL.md +0 -413
- package/skills/communications-tmf-integrate/SKILL.md +0 -1368
- package/skills/consumer-goods-visit-activity-act4-questions-assign/SKILL.md +0 -448
- package/skills/consumer-goods-visit-activity-act5-standard-create/SKILL.md +0 -269
- package/skills/consumer-goods-visit-activity-act6-assortment-configure/SKILL.md +0 -271
- package/skills/consumer-goods-visit-activity-act7-account-scoping-create/SKILL.md +0 -382
- package/skills/consumer-goods-visit-activity-act8-plan-attach-create/SKILL.md +0 -373
- package/skills/consumer-goods-visit-activity-act9-proof-validate/SKILL.md +0 -389
- package/skills/consumer-goods-visit-and-activity-act1-specification-create/SKILL.md +0 -338
- package/skills/consumer-goods-visit-and-activity-act2-template-create/SKILL.md +0 -547
- package/skills/consumer-goods-visit-and-activity-act3-definition-create/SKILL.md +0 -346
- package/skills/consumer-goods-visit-and-activity-configure/SKILL.md +0 -1110
- package/skills/crm-analytics-adoption-insights-configure/SKILL.md +0 -224
- package/skills/crm-analytics-custom-report-type-lightning-configure/SKILL.md +0 -418
- package/skills/crm-analytics-dashboards-configure/SKILL.md +0 -731
- package/skills/crm-analytics-operational-analytics-metadata-bridge-migrate/SKILL.md +0 -233
- package/skills/crm-analytics-report-notifications-ui-configure/SKILL.md +0 -184
- package/skills/crm-analytics-sharing-inheritance-coverage-analyze/SKILL.md +0 -167
- package/skills/crm-analytics-sonic-getting-started-configure/SKILL.md +0 -55
- package/skills/crm-analytics-tableau-next-app-deploy/SKILL.md +0 -1350
- package/skills/crm-analytics-tableau-next-c360-basemodel-validate/SKILL.md +0 -1862
- package/skills/crm-analytics-tableau-next-datacloud-validate/SKILL.md +0 -83
- package/skills/crm-analytics-tableau-next-provisioning-validate/SKILL.md +0 -81
- package/skills/data360-activation-create/SKILL.md +0 -104
- package/skills/data360-activation-external-platform-get/SKILL.md +0 -49
- package/skills/data360-activation-target-create/SKILL.md +0 -93
- package/skills/data360-activation-v2-create/SKILL.md +0 -456
- package/skills/data360-audience-dmo-get/SKILL.md +0 -38
- package/skills/data360-calculated-affinity-create/SKILL.md +0 -82
- package/skills/data360-calculated-insight-create/SKILL.md +0 -148
- package/skills/data360-catalog-metadata-create/SKILL.md +0 -183
- package/skills/data360-code-extension-create/SKILL.md +0 -115
- package/skills/data360-communication-capping-create/SKILL.md +0 -227
- package/skills/data360-connection-create/SKILL.md +0 -491
- package/skills/data360-content-lens-create/SKILL.md +0 -181
- package/skills/data360-data-action-create/SKILL.md +0 -126
- package/skills/data360-data-action-target-create/SKILL.md +0 -181
- package/skills/data360-data-clean-room-create/SKILL.md +0 -238
- package/skills/data360-data-governance-create/SKILL.md +0 -746
- package/skills/data360-data-graph-create/SKILL.md +0 -82
- package/skills/data360-data-harmonized-model-object-reference-create/SKILL.md +0 -38
- package/skills/data360-data-lake-object-create/SKILL.md +0 -207
- package/skills/data360-data-model-object-catalog-get/SKILL.md +0 -49
- package/skills/data360-data-model-object-create/SKILL.md +0 -128
- package/skills/data360-data-model-object-mapping-create/SKILL.md +0 -106
- package/skills/data360-data-space-create/SKILL.md +0 -161
- package/skills/data360-data-streams-create/SKILL.md +0 -324
- package/skills/data360-engagement-signal-get/SKILL.md +0 -38
- package/skills/data360-experiment-create/SKILL.md +0 -82
- package/skills/data360-goal-based-campaign-create/SKILL.md +0 -192
- package/skills/data360-harmonization-process-history-get/SKILL.md +0 -38
- package/skills/data360-harmonized-unstructured-dmo-create/SKILL.md +0 -84
- package/skills/data360-identity-resolution-create/SKILL.md +0 -115
- package/skills/data360-intelligent-document-processing-create/SKILL.md +0 -148
- package/skills/data360-knowledge-graph-construction-create/SKILL.md +0 -93
- package/skills/data360-knowledge-graph-create/SKILL.md +0 -216
- package/skills/data360-knowledge-space-mcp-configure/SKILL.md +0 -475
- package/skills/data360-machine-learning-mcp-configure/SKILL.md +0 -697
- package/skills/data360-multi-org-mcp-configure/SKILL.md +0 -117
- package/skills/data360-secondary-index-mcp-configure/SKILL.md +0 -126
- package/skills/data360-segment-mcp-configure/SKILL.md +0 -159
- package/skills/data360-semantic-calculated-dimension-mcp-configure/SKILL.md +0 -93
- package/skills/data360-semantic-calculated-measurement-mcp-configure/SKILL.md +0 -93
- package/skills/data360-semantic-data-object-mcp-configure/SKILL.md +0 -93
- package/skills/data360-semantic-dimension-mcp-configure/SKILL.md +0 -38
- package/skills/data360-semantic-engine-mcp-configure/SKILL.md +0 -62
- package/skills/data360-semantic-measurement-mcp-configure/SKILL.md +0 -38
- package/skills/data360-semantic-metric-mcp-configure/SKILL.md +0 -93
- package/skills/data360-semantic-model-mcp-configure/SKILL.md +0 -115
- package/skills/data360-standard-mapping-mcp-configure/SKILL.md +0 -38
- package/skills/data360-tenant-lifecycle-mcp-configure/SKILL.md +0 -73
- package/skills/experience-afv-query/SKILL.md +0 -234
- package/skills/experience-agentforce-vibes-in-react-configure/SKILL.md +0 -63
- package/skills/experience-apex-components-configure/SKILL.md +0 -69
- package/skills/experience-apex-pages-configure/SKILL.md +0 -107
- package/skills/experience-app-home-configure/SKILL.md +0 -76
- package/skills/experience-aura-lightning-out-access-configure/SKILL.md +0 -58
- package/skills/experience-briefcase-configure/SKILL.md +0 -287
- package/skills/experience-community-flexi-page-list-create/SKILL.md +0 -74
- package/skills/experience-community-template-definition-list-query/SKILL.md +0 -48
- package/skills/experience-community-theme-definition-list-query/SKILL.md +0 -38
- package/skills/experience-content-assets-configure/SKILL.md +0 -86
- package/skills/experience-custom-domain-create/SKILL.md +0 -727
- package/skills/experience-defer-rendering-workspace-page-setup-configure/SKILL.md +0 -41
- package/skills/experience-field-service-app-builder-configure/SKILL.md +0 -187
- package/skills/experience-flow-category-configure/SKILL.md +0 -117
- package/skills/experience-formula-configure/SKILL.md +0 -358
- package/skills/experience-global-actions-configure/SKILL.md +0 -69
- package/skills/experience-global-publisher-layouts-configure/SKILL.md +0 -79
- package/skills/experience-instrumentation-configure/SKILL.md +0 -64
- package/skills/experience-lex-engagement-configure/SKILL.md +0 -50
- package/skills/experience-lightning-bolt-open/SKILL.md +0 -12
- package/skills/experience-lightning-out-configure/SKILL.md +0 -129
- package/skills/experience-lightning-preview-configure/SKILL.md +0 -67
- package/skills/experience-lightning-types-query/SKILL.md +0 -98
- package/skills/experience-malware-scan-configure/SKILL.md +0 -71
- package/skills/experience-my-salesforce-configure/SKILL.md +0 -126
- package/skills/experience-navigation-menus-configure/SKILL.md +0 -235
- package/skills/experience-notification-types-configure/SKILL.md +0 -206
- package/skills/experience-notifications-configure/SKILL.md +0 -75
- package/skills/experience-record-discovery-query/SKILL.md +0 -227
- package/skills/experience-regenerate-previews-open/SKILL.md +0 -94
- package/skills/experience-sales-cloud-mab-configure/SKILL.md +0 -254
- package/skills/experience-schema-builder-open/SKILL.md +0 -38
- package/skills/experience-simple-record-home-configure/SKILL.md +0 -110
- package/skills/experience-static-resources-configure/SKILL.md +0 -74
- package/skills/field-service-setup-coordinate/SKILL.md +0 -62
- package/skills/field-service-work-plan-configure/SKILL.md +0 -253
- package/skills/fsc-actionable-segmentation-settings-configure/SKILL.md +0 -180
- package/skills/fsc-digital-origination-bre-decision-matrix-foundation-create/SKILL.md +0 -196
- package/skills/fsc-digital-origination-bre-disclosures-consent-configure/SKILL.md +0 -106
- package/skills/fsc-digital-origination-bre-document-upload-configure/SKILL.md +0 -96
- package/skills/fsc-digital-origination-bre-permissions-assign/SKILL.md +0 -111
- package/skills/fsc-digital-origination-bre-setup-coordinate/SKILL.md +0 -250
- package/skills/fsc-digital-origination-bre-stp-eligibility-configure/SKILL.md +0 -122
- package/skills/fsc-digital-origination-coordinate/SKILL.md +0 -653
- package/skills/fsc-digital-origination-demo-run/SKILL.md +0 -225
- package/skills/fsc-digital-origination-execution-guardrails-validate/SKILL.md +0 -112
- package/skills/fsc-digital-origination-initial-setup-configure/SKILL.md +0 -396
- package/skills/fsc-digital-origination-pricing-setup-coordinate/SKILL.md +0 -336
- package/skills/fsc-digital-origination-pricing-setup-data-foundation-create/SKILL.md +0 -208
- package/skills/fsc-digital-origination-pricing-setup-procedure-create/SKILL.md +0 -375
- package/skills/fsc-digital-origination-product-setup-act1-permissions-assign/SKILL.md +0 -83
- package/skills/fsc-digital-origination-product-setup-coordinate/SKILL.md +0 -248
- package/skills/fsc-digital-origination-sample-data-create/SKILL.md +0 -206
- package/skills/fsc-document-checklist-settings-configure/SKILL.md +0 -57
- package/skills/fsc-flexible-hierarchy-configure/SKILL.md +0 -148
- package/skills/fsc-flexible-hierarchy-foundation-configure/SKILL.md +0 -1430
- package/skills/fsc-flexible-hierarchy-graph-config-create/SKILL.md +0 -471
- package/skills/fsc-flexible-hierarchy-rule-based-graph-deploy/SKILL.md +0 -429
- package/skills/fsc-pricing-product-configurator-configure/SKILL.md +0 -150
- package/skills/fsc-pricing-salesforce-omnistudio-switch/SKILL.md +0 -123
- package/skills/fsc-product-act2-catalog-categories-create/SKILL.md +0 -82
- package/skills/fsc-product-act3-attributes-create/SKILL.md +0 -249
- package/skills/fsc-product-act4-classification-assignment-create/SKILL.md +0 -196
- package/skills/fsc-product-act5-considerations-get/SKILL.md +0 -44
- package/skills/fsc-stage-management-apex-flow-deploy/SKILL.md +0 -384
- package/skills/fsc-stage-management-compliant-data-sharing-configure/SKILL.md +0 -144
- package/skills/fsc-stage-management-decision-matrices-create/SKILL.md +0 -107
- package/skills/fsc-stage-management-definition-assignments-create/SKILL.md +0 -189
- package/skills/fsc-stage-management-definition-create/SKILL.md +0 -108
- package/skills/fsc-stage-management-permissions-assign/SKILL.md +0 -143
- package/skills/fsc-stage-management-transitions-configure/SKILL.md +0 -139
- package/skills/health-cloud-appt-booking-config-configure/SKILL.md +0 -135
- package/skills/health-cloud-appt-booking-url-config-configure/SKILL.md +0 -134
- package/skills/health-cloud-care-provider-affl-role-config-configure/SKILL.md +0 -136
- package/skills/health-cloud-care-provider-search-config-configure/SKILL.md +0 -134
- package/skills/health-cloud-care-requests-create/SKILL.md +0 -178
- package/skills/health-cloud-initial-configure/SKILL.md +0 -511
- package/skills/health-cloud-patient-appointment-scheduling-configure/SKILL.md +0 -1374
- package/skills/health-cloud-provider-search-settings-configure/SKILL.md +0 -924
- package/skills/health-cloud-referral-management-coordinate/SKILL.md +0 -513
- package/skills/health-cloud-timeline-configure/SKILL.md +0 -622
- package/skills/health-cloud-virtual-visit-config-configure/SKILL.md +0 -135
- package/skills/industries-account-score-settings-query/SKILL.md +0 -78
- package/skills/industries-actionable-list-data-sources-dmo-configure/SKILL.md +0 -177
- package/skills/industries-ad-product-availability-search/SKILL.md +0 -399
- package/skills/industries-advanced-account-forecast-settings-configure/SKILL.md +0 -628
- package/skills/industries-advanced-therapy-management-settings-configure/SKILL.md +0 -73
- package/skills/industries-atm-settings-starter-configure/SKILL.md +0 -76
- package/skills/industries-batch-document-ai-configure/SKILL.md +0 -196
- package/skills/industries-behavioral-health-app-settings-configure/SKILL.md +0 -71
- package/skills/industries-branch-management-settings-configure/SKILL.md +0 -89
- package/skills/industries-bre-decision-table-access-configure/SKILL.md +0 -367
- package/skills/industries-brokerage-settings-configure/SKILL.md +0 -41
- package/skills/industries-calendar-sync-settings-configure/SKILL.md +0 -89
- package/skills/industries-care-request-settings-configure/SKILL.md +0 -218
- package/skills/industries-case-management-intelligence-settings-configure/SKILL.md +0 -54
- package/skills/industries-catalog-process-attributes-products-configure/SKILL.md +0 -380
- package/skills/industries-catalog-process-fulfillment-configure/SKILL.md +0 -216
- package/skills/industries-catalog-process-intake-configure/SKILL.md +0 -219
- package/skills/industries-catalog-process-knowledge-configure/SKILL.md +0 -153
- package/skills/industries-catalog-process-preprocessor-configure/SKILL.md +0 -168
- package/skills/industries-cds-general-settings-configure/SKILL.md +0 -69
- package/skills/industries-claim-financial-settings-configure/SKILL.md +0 -169
- package/skills/industries-clinical-data-model-settings-configure/SKILL.md +0 -136
- package/skills/industries-clinical-data-model-settings-starter-configure/SKILL.md +0 -105
- package/skills/industries-collection-plan-settings-configure/SKILL.md +0 -132
- package/skills/industries-comms-service-console-settings-configure/SKILL.md +0 -159
- package/skills/industries-compliance-configure/SKILL.md +0 -102
- package/skills/industries-compliance-document-extraction-setup-configure/SKILL.md +0 -76
- package/skills/industries-contact-center-app-layout-configure/SKILL.md +0 -88
- package/skills/industries-contact-center-components-configure/SKILL.md +0 -96
- package/skills/industries-contact-center-path-knowledge-configure/SKILL.md +0 -95
- package/skills/industries-contact-center-user-access-assign/SKILL.md +0 -96
- package/skills/industries-course-waitlist-config-configure/SKILL.md +0 -162
- package/skills/industries-crisis-center-settings-configure/SKILL.md +0 -84
- package/skills/industries-custom-object-settings-configure/SKILL.md +0 -94
- package/skills/industries-data-cloud-integration-configure/SKILL.md +0 -88
- package/skills/industries-data-space-feature-mappings-configure/SKILL.md +0 -245
- package/skills/industries-decision-matrix-builder-configure/SKILL.md +0 -78
- package/skills/industries-decision-table-hbase-configure/SKILL.md +0 -87
- package/skills/industries-decision-table-version-configure/SKILL.md +0 -74
- package/skills/industries-decision-tables-builder-configure/SKILL.md +0 -253
- package/skills/industries-decision-tables-configure/SKILL.md +0 -439
- package/skills/industries-energy-utilities-configure/SKILL.md +0 -251
- package/skills/industries-eu-cloud-multisite-configure/SKILL.md +0 -1008
- package/skills/industries-eu-new-connections-configure/SKILL.md +0 -30
- package/skills/industries-explainability-msg-template-configure/SKILL.md +0 -135
- package/skills/industries-expression-set-message-token-configure/SKILL.md +0 -135
- package/skills/industries-field-service-settings-configure/SKILL.md +0 -82
- package/skills/industries-form-framework-settings-configure/SKILL.md +0 -30
- package/skills/industries-fsc-ai-settings-configure/SKILL.md +0 -57
- package/skills/industries-fsc-association-engine-settings-configure/SKILL.md +0 -172
- package/skills/industries-fsc-b2b-settings-configure/SKILL.md +0 -61
- package/skills/industries-fsc-insurance-settings-configure/SKILL.md +0 -58
- package/skills/industries-fsc-visa-fulfillment-setup-configure/SKILL.md +0 -103
- package/skills/industries-fsc-wealth-agent-settings-configure/SKILL.md +0 -117
- package/skills/industries-fsc-wealth-settings-configure/SKILL.md +0 -99
- package/skills/industries-fundraising-gift-entry-settings-configure/SKILL.md +0 -120
- package/skills/industries-fundraising-rfm-configure/SKILL.md +0 -128
- package/skills/industries-fundraising-settings-configure/SKILL.md +0 -145
- package/skills/industries-fundraising-source-code-gen-configure/SKILL.md +0 -299
- package/skills/industries-google-maps-api-key-settings-configure/SKILL.md +0 -87
- package/skills/industries-grantmaking-intelligence-settings-open/SKILL.md +0 -58
- package/skills/industries-hc-score-category-settings-configure/SKILL.md +0 -167
- package/skills/industries-health-engagement-settings-configure/SKILL.md +0 -218
- package/skills/industries-home-health-agentforce-setup-configure/SKILL.md +0 -131
- package/skills/industries-home-health-bundling-policy-create/SKILL.md +0 -50
- package/skills/industries-home-health-entity-labels-configure/SKILL.md +0 -29
- package/skills/industries-home-health-fsl-package-deploy/SKILL.md +0 -71
- package/skills/industries-home-health-fsl-settings-validate/SKILL.md +0 -27
- package/skills/industries-home-health-guided-setup-care-and-skill-get/SKILL.md +0 -80
- package/skills/industries-home-health-guided-setup-configure/SKILL.md +0 -836
- package/skills/industries-home-health-guided-setup-enable-org-fsl-get/SKILL.md +0 -55
- package/skills/industries-home-health-guided-setup-get-org-ready-get/SKILL.md +0 -61
- package/skills/industries-home-health-licenses-assign/SKILL.md +0 -27
- package/skills/industries-home-health-operating-hours-create/SKILL.md +0 -40
- package/skills/industries-home-health-scheduling-policy-create/SKILL.md +0 -41
- package/skills/industries-home-health-service-objective-create/SKILL.md +0 -22
- package/skills/industries-home-health-skills-create/SKILL.md +0 -31
- package/skills/industries-home-health-users-create/SKILL.md +0 -29
- package/skills/industries-icm-act3-toggles-configure/SKILL.md +0 -198
- package/skills/industries-icm-act5-genai-suggested-assessments-configure/SKILL.md +0 -361
- package/skills/industries-icm-act6-mcg-integration-configure/SKILL.md +0 -550
- package/skills/industries-integrated-care-management-configure/SKILL.md +0 -168
- package/skills/industries-object-enablement-configure/SKILL.md +0 -86
- package/skills/industries-tpm-system-processing-service-configure/SKILL.md +0 -64
- package/skills/integration-apex-settings-configure/SKILL.md +0 -61
- package/skills/marketing-e360-email-archiving-configure/SKILL.md +0 -73
- package/skills/platform-custom-permissions-configure/SKILL.md +0 -687
- package/skills/platform-label-workbench-import-create/SKILL.md +0 -67
- package/skills/platform-privacy-agent-settings-configure/SKILL.md +0 -752
|
@@ -1,1368 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: communications-tmf-integrate
|
|
3
|
-
description: "One-stop, zero-code-search reference for calling and extending Comms Cloud's TMF621 (Trouble Ticket Management) and TMF629 (Customer Management) TM Forum Open APIs — /connect/comms/troubleticket and /connect/comms/customermanagement. Trigger this skill for ANY of: calling or listing/creating/updating/deleting trouble tickets or customers via these APIs; asking what endpoints, params, request/response fields, or sub-resources (note, attachment, channel, relatedParty, engagedParty, agreement, account, etc.) exist; hitting the route directly against /connect/comms/troubleticket/v5/troubleticket or /connect/comms/customermanagement/v4/customer; questions about TMF/Comms TMF API access (CommsCloud / CommsCloudTMFAPI org permission); and — for extensibility scenarios only — writing or reviewing an Apex class that implements comms_apex_ext.ICommsGET/POST/PATCH/DELETE or the entity-specific ITroubleTicketManagementGET/POST/PATCH/DELETE / ICustomerManagementGET/POST/ PATCH/DELETE interfaces, or any of their hooks (transformRequest, configureDefaultValidations, applyCustomValidations, customiseGraphQLQuery, customiseMutationPayload, handlePostOperation), custom sub-resource registration, or deploying that Apex to an org (Setup UI, or the Metadata REST API / Tooling API). Gives exact endpoint tables, payload shapes, hook signatures, validation defaults, and a worked example — plus a built-in policy that only triggers Apex-writing/deployment when the user has explicitly asked for an extensibility scenario, always surfacing the generated class for user confirmation, always asking explicitly before deploying, and always checking for/confirming override of any existing implementor class before deploying. Never proposes or makes a schema change (new fields/objects/etc.) for TMF621/TMF629 work — always prefers extensibility when a customization is possible, explicitly tells the customer whether their request is achievable via extensibility, and says so plainly when it is not achievable within this scope. Use for keyword matches like \"TMF621\", \"TMF629\", \"trouble ticket API\", \"customer management API\", \"Comms TMF API\", or any comms_apex_ext.* interface/hook name, even if the user doesn't name the skill directly. Owned by: Comms Cloud Arches"
|
|
4
|
-
metadata:
|
|
5
|
-
version: "1.0"
|
|
6
|
-
cliTools:
|
|
7
|
-
- tool:
|
|
8
|
-
- "sf"
|
|
9
|
-
semver: ">=2.0.0"
|
|
10
|
-
---
|
|
11
|
-
|
|
12
|
-
# TMF621 (Trouble Ticket) & TMF629 (Customer Management) — Complete API + Extensibility Guide
|
|
13
|
-
|
|
14
|
-
This skill is organized into parts:
|
|
15
|
-
|
|
16
|
-
- **Part 1 — Prerequisites** (org access, auth, API version) — read first, applies to everything.
|
|
17
|
-
- **Part 2 — Concepts common to both APIs** (extensible pipeline, pagination, filtering/sorting mechanism).
|
|
18
|
-
- **Part 3 — Extensibility framework** (common to both APIs) — only for extensibility scenarios.
|
|
19
|
-
- **Part 4 — TMF621 Trouble Ticket** (API-specific: endpoints, payloads, fields).
|
|
20
|
-
- **Part 5 — TMF629 Customer Management** (API-specific: endpoints, payloads, fields).
|
|
21
|
-
- **Part 6 — End-to-end execution checklist.**
|
|
22
|
-
|
|
23
|
-
| TMF API | Backing SObject |
|
|
24
|
-
|---|---|
|
|
25
|
-
| TMF621 Trouble Ticket Management | `Case` (+ `CaseTroubleTicket` extension fields for severity) |
|
|
26
|
-
| TMF629 Customer Management | `Account` (+ `Contact`, `Contract`) |
|
|
27
|
-
|
|
28
|
-
---
|
|
29
|
-
|
|
30
|
-
## Mandatory verification gate — read this before writing any Apex
|
|
31
|
-
|
|
32
|
-
**Never write or deploy an Apex extensibility class unless the user has clearly
|
|
33
|
-
asked for extensibility.** Plain "call this API" / "list trouble tickets" /
|
|
34
|
-
"create a customer" requests should be served entirely with Parts 4/5 (endpoint
|
|
35
|
-
routes) — no Apex, no deployment, nothing to confirm.
|
|
36
|
-
|
|
37
|
-
> **MUST — API version prerequisite for ALL extensibility scenarios (v67+):**
|
|
38
|
-
> Extensibility is only supported on orgs whose latest supported Salesforce API
|
|
39
|
-
> version is **`67.0` or above**. **Before running any extensibility scenario**
|
|
40
|
-
> (writing, deploying, or reasoning about an Apex extensibility class, or any of
|
|
41
|
-
> the hooks in Part 3), you **must** first discover the org's latest supported
|
|
42
|
-
> API version per §1.3 (`GET .../services/data/`). If the highest version the
|
|
43
|
-
> org reports is **below `67.0`, extensibility will not work** — stop
|
|
44
|
-
> immediately, tell the user their org's API version is below the required
|
|
45
|
-
> minimum (`67.0`), and do **not** write or deploy any Apex extensibility class.
|
|
46
|
-
> This check is mandatory and applies on top of every other step in this gate.
|
|
47
|
-
> (Plain, non-extensibility API calls in Parts 4/5 are not subject to this floor
|
|
48
|
-
> — they use the org's own latest version per §1.3.)
|
|
49
|
-
|
|
50
|
-
Follow this exact sequence whenever a request could involve extensibility:
|
|
51
|
-
|
|
52
|
-
1. **Determine intent first.** Only treat a request as an extensibility
|
|
53
|
-
scenario if the user explicitly says so — e.g. "extend", "customize",
|
|
54
|
-
"add a field to the response", "validate X before create", "override the
|
|
55
|
-
response", "add a custom sub-resource", "write an Apex class for
|
|
56
|
-
TMF621/TMF629", or similar. If the request is ambiguous (could be answered
|
|
57
|
-
with the plain default endpoint, or you're not sure whether they want
|
|
58
|
-
default behavior vs. custom behavior), **stop and ask the user directly**
|
|
59
|
-
— e.g. "Do you want the default API behavior, or should I write an
|
|
60
|
-
extensibility Apex class to customize this?" Do not guess, and do not
|
|
61
|
-
default to writing Apex just because it's possible.
|
|
62
|
-
2. **Never make a schema change — ask the user to make it themselves.** Do not
|
|
63
|
-
create/modify custom fields, objects, record types, page layouts, or any
|
|
64
|
-
other metadata schema element to satisfy a TMF621/TMF629 request — Apex
|
|
65
|
-
extensibility (Part 3) is the only sanctioned customization mechanism for
|
|
66
|
-
this scope. If a request needs new schema (e.g. "store this extra value
|
|
67
|
-
somewhere," "add a field to track X," or an extensibility class that
|
|
68
|
-
references a field/object that doesn't exist yet), **do not create it
|
|
69
|
-
yourself.** Tell the user exactly what schema they need to add (the object,
|
|
70
|
-
field name, type), and ask them to make that schema change on their own.
|
|
71
|
-
Make clear that **once they have added the schema, the request can then be
|
|
72
|
-
supported via extensibility** — and only proceed with the Apex once the
|
|
73
|
-
schema exists. Do not make any org changes on your own.
|
|
74
|
-
3. **Within TMF scope, always prefer extensibility when a customization is
|
|
75
|
-
needed, and explicitly tell the customer whether their ask is achievable
|
|
76
|
-
via extensibility.** For any request that isn't satisfied by the plain
|
|
77
|
-
default endpoint, check whether one of the 6 hooks (§3.2) — or a custom
|
|
78
|
-
sub-resource registration (§3.7) — can achieve it using fields/objects that
|
|
79
|
-
already exist. If yes, say so explicitly and propose the extensibility
|
|
80
|
-
approach. If the request truly cannot be done via extensibility alone,
|
|
81
|
-
**tell the customer plainly that it is out of scope for extensibility**
|
|
82
|
-
rather than improvising a workaround — do not silently fall back to a
|
|
83
|
-
schema change or an out-of-scope mechanism. Two distinct cases to state
|
|
84
|
-
explicitly to the user:
|
|
85
|
-
- **Needs a schema change:** if the only thing blocking it is missing schema
|
|
86
|
-
(a field/object that doesn't exist), say so, and per rule 2 ask the user
|
|
87
|
-
to add that schema themselves — then it becomes supportable via
|
|
88
|
-
extensibility. Do not add the schema yourself.
|
|
89
|
-
- **Genuinely out of scope:** if it needs data or behavior outside what the
|
|
90
|
-
6 Apex hooks can reach (even with schema in place), tell the user plainly
|
|
91
|
-
that it is not possible within this skill's scope, and do not attempt a
|
|
92
|
-
workaround.
|
|
93
|
-
4. **Write the Apex class.** Once — and only once — the user confirms they
|
|
94
|
-
want an extensibility scenario, write the Apex class following Part 3
|
|
95
|
-
(correct interface from §3.1, correct hook signatures from §3.2, no-op the
|
|
96
|
-
hooks you don't need). Show the full class to the user.
|
|
97
|
-
5. **After posting the Apex, explicitly prompt the user to correct anything
|
|
98
|
-
before deploying.** Right after you show the class, ask a direct question
|
|
99
|
-
like: "Here's the class — do you want to correct anything before I deploy
|
|
100
|
-
it? Tell me what to change and I'll update it." Make clear the user can hand
|
|
101
|
-
back edits or corrections, and that you will apply them **before** any
|
|
102
|
-
deployment. Do not deploy on the same turn you first show the code. Wait for
|
|
103
|
-
explicit confirmation ("yes / looks good / deploy it") before proceeding. If
|
|
104
|
-
the user gives corrections, apply them, show the revised class, and ask
|
|
105
|
-
again — repeat until the user is satisfied.
|
|
106
|
-
6. **Always explicitly ask the user whether they want you to deploy it** —
|
|
107
|
-
even after they've confirmed the class is correct, deployment is a separate
|
|
108
|
-
decision from correctness. Do not deploy just because the code was
|
|
109
|
-
approved; ask something like "Should I deploy this to the org now?" and
|
|
110
|
-
wait for a clear yes.
|
|
111
|
-
7. **Check for an existing implementor before deploying, and confirm any
|
|
112
|
-
override.** Per §3.9, only one concrete class may implement a given
|
|
113
|
-
`comms_apex_ext.*` interface at a time — deploying a second one causes
|
|
114
|
-
every call for that verb+entity to fail with a discovery error.
|
|
115
|
-
Before deploying, check (or ask the user to check) whether a class already
|
|
116
|
-
implements the target interface (e.g. via Setup → Apex Classes, or a
|
|
117
|
-
Tooling API query against `ApexTypeImplementor`:
|
|
118
|
-
`GET /services/data/vXX.0/tooling/query/?q=SELECT+ClassName+FROM+ApexTypeImplementor+WHERE+InterfaceName='<Interface>'`).
|
|
119
|
-
If one exists, tell the user its name
|
|
120
|
-
and **explicitly confirm they want to replace/deactivate it** before
|
|
121
|
-
proceeding — do not silently overwrite or leave both active.
|
|
122
|
-
8. **Deploy only after both confirmations (step 6 and step 7)**, using §3.11.
|
|
123
|
-
9. After deployment, re-hit the relevant route from §4.4/§5.4 (or ask the
|
|
124
|
-
user to) to confirm the customized behavior actually shows up in the live
|
|
125
|
-
response.
|
|
126
|
-
10. **Never create test data in the org on your own.** Testing an extensibility
|
|
127
|
-
class often needs sample records (a `Case`/trouble ticket, an
|
|
128
|
-
`Account`/customer, related `Contact`/`Contract`/`Asset`, attachments,
|
|
129
|
-
etc.). **Do not create, insert, POST, or otherwise write any data to the
|
|
130
|
-
org to test the Apex** — no `POST` create calls, no `sf data create`, no
|
|
131
|
-
anonymous-Apex `insert`, nothing. First **ask the user** whether they want
|
|
132
|
-
you to create the data needed to exercise the class, tell them exactly what
|
|
133
|
-
you would create, and **wait for explicit confirmation**. Prefer testing
|
|
134
|
-
against records the user already has (ask for an existing `{id}`). Only
|
|
135
|
-
create records if the user clearly says to, and only the specific records
|
|
136
|
-
they approved.
|
|
137
|
-
|
|
138
|
-
---
|
|
139
|
-
|
|
140
|
-
# Part 1 — Prerequisites (both APIs)
|
|
141
|
-
|
|
142
|
-
Org access, authentication, and API-version discovery. No code changes required.
|
|
143
|
-
|
|
144
|
-
## 1.1 Access check & required permissions
|
|
145
|
-
|
|
146
|
-
Both API families are gated by a single access check that either org permission
|
|
147
|
-
satisfies — having `CommsCloud` or `CommsCloudTMFAPI` enabled is sufficient.
|
|
148
|
-
|
|
149
|
-
To call **any** endpoint in this skill, the calling user's org must have
|
|
150
|
-
`CommsCloud` or `CommsCloudTMFAPI` org permission enabled, and the calling user
|
|
151
|
-
needs standard CRUD/FLS access to the underlying object (`Case` for TMF621,
|
|
152
|
-
`Account`/`Contact`/`Contract` for TMF629) — this is a Connect API resource, so
|
|
153
|
-
ordinary Salesforce sharing and field-level security apply on top of the TMF
|
|
154
|
-
access check.
|
|
155
|
-
|
|
156
|
-
## 1.2 Authentication (External Client App + token)
|
|
157
|
-
|
|
158
|
-
Authentication is standard Salesforce session/OAuth: send a `Bearer`/session
|
|
159
|
-
token in the `Authorization` header, exactly like any other Connect (`/services/data/vXX.0/connect/...`) REST call.
|
|
160
|
-
|
|
161
|
-
**Before executing any endpoint below, the org needs an External Client App so
|
|
162
|
-
Claude can authenticate and call these APIs on the user's behalf** (External
|
|
163
|
-
Client Apps are Salesforce's current, recommended replacement for the legacy
|
|
164
|
-
Connected App framework).
|
|
165
|
-
|
|
166
|
-
**All External Client App details live in a dedicated reference — read it before
|
|
167
|
-
doing any auth/app work:** the bundled reference sample **external-client-app-setup**
|
|
168
|
-
in the skill's references bundle. It is the single source of truth for:
|
|
169
|
-
|
|
170
|
-
- listing/reusing an existing External Client App (Metadata API) and the
|
|
171
|
-
admin prerequisites — don't create a duplicate;
|
|
172
|
-
- the inputs & defaults for creating a new app (defaults applied automatically;
|
|
173
|
-
ask for all inputs only if the user wants to customize);
|
|
174
|
-
- the default OAuth scopes and policies (incl. the Client Credentials run-as
|
|
175
|
-
user requirement);
|
|
176
|
-
- revealing/storing the Consumer Key & Secret;
|
|
177
|
-
- obtaining an access token; and
|
|
178
|
-
- after setup, asking the user whether to use this app to run the TMF APIs and,
|
|
179
|
-
if so, doing everything needed to make the calls work through it (token →
|
|
180
|
-
access check → version discovery → smoke test → the real request).
|
|
181
|
-
|
|
182
|
-
In short: confirm you already hold a live token for the target org; if not,
|
|
183
|
-
follow that reference to reuse or create the app and obtain a token. **Do not
|
|
184
|
-
attempt any API call until both the External Client App exists and you hold a
|
|
185
|
-
live access token for it.**
|
|
186
|
-
|
|
187
|
-
## 1.3 Discover the org's latest supported API version
|
|
188
|
-
|
|
189
|
-
**Verify the APIs are reachable by discovering the org's latest supported
|
|
190
|
-
Salesforce API version, and use that same latest version in every call in this
|
|
191
|
-
skill.** Call `GET https://<your-instance>.my.salesforce.com/services/data/`
|
|
192
|
-
(no version segment, with the `Bearer` token). It returns the list of every
|
|
193
|
-
API version the org supports; take the **highest** `version` value from the
|
|
194
|
-
response (e.g. `"67.0"`) and use it as the `v<API_VERSION>.0` / `vXX.0` segment
|
|
195
|
-
in **every** method throughout this skill — the TMF endpoint calls (Parts 4/5),
|
|
196
|
-
the Tooling API and Metadata REST API deploys (§3.11), the `ApexTypeImplementor`
|
|
197
|
-
query, and any other REST call. Do not mix versions across calls. A `200` here
|
|
198
|
-
confirms the token and instance URL are valid and tells you the exact API
|
|
199
|
-
version to use; if this call fails, fix auth (§1.2) before going further. Always
|
|
200
|
-
use a version the org actually reports — never hard-code a version the org may
|
|
201
|
-
not have.
|
|
202
|
-
|
|
203
|
-
## 1.4 Base URL pattern
|
|
204
|
-
|
|
205
|
-
Every endpoint in this skill is called as:
|
|
206
|
-
|
|
207
|
-
```text
|
|
208
|
-
https://<your-instance>.my.salesforce.com/services/data/v<API_VERSION>.0<path-from-tables-below>
|
|
209
|
-
```
|
|
210
|
-
|
|
211
|
-
Example: for TMF621's list endpoint, `<path-from-tables-below>` is
|
|
212
|
-
`/connect/comms/troubleticket/v5/troubleticket`, so the full URL is:
|
|
213
|
-
|
|
214
|
-
```text
|
|
215
|
-
https://myorg.my.salesforce.com/services/data/v67.0/connect/comms/troubleticket/v5/troubleticket
|
|
216
|
-
```
|
|
217
|
-
|
|
218
|
-
The `v5` / `v4` segment in the path is the **TMF resource version** (a separate,
|
|
219
|
-
independent version token baked into the URL itself — not the same as the
|
|
220
|
-
Salesforce API version `v67.0` in the outer path, which comes from §1.3). Always
|
|
221
|
-
use the exact TMF version segment shown in the tables below; using the wrong one
|
|
222
|
-
silently 404s or routes to the legacy (non-extensible) handler.
|
|
223
|
-
|
|
224
|
-
---
|
|
225
|
-
|
|
226
|
-
# Part 2 — Concepts common to both APIs
|
|
227
|
-
|
|
228
|
-
## 2.1 The extensible pipeline is always on
|
|
229
|
-
|
|
230
|
-
Every endpoint in Parts 4/5 (except legacy fallbacks with no handler mapping)
|
|
231
|
-
runs through the **extensible** code path — meaning every request, even one with
|
|
232
|
-
zero customization, passes through the Apex extensibility pipeline described in
|
|
233
|
-
Part 3. There is nothing you need to configure to "turn on" extensibility; it is
|
|
234
|
-
always active, and there is no separate "legacy" endpoint you need to avoid — the
|
|
235
|
-
framework transparently prefers the extensible handler for the versions listed in
|
|
236
|
-
Parts 4/5. Apex customization is purely additive/optional (§3.9 explains
|
|
237
|
-
discovery: if no Apex class implements the interface, the framework just uses
|
|
238
|
-
defaults).
|
|
239
|
-
|
|
240
|
-
## 2.2 Pagination (bounds & per-API defaults)
|
|
241
|
-
|
|
242
|
-
Both list/GET endpoints accept `offset` (int), `pageLimit` (int), and `pageinfo`
|
|
243
|
-
(bool — return `totalPageSize`/`currentPage`). Bounds are enforced consistently
|
|
244
|
-
for **both APIs**:
|
|
245
|
-
|
|
246
|
-
- `pageLimit` max is **2000**; a larger value → HTTP 400 `"Page limit cannot exceed 2000"`.
|
|
247
|
-
- `offset + pageLimit` must be **≤ 100,000** (it's the *sum*, not the product); exceeding it → HTTP 400 `"Pagination is supported only for 100,000 records…"`.
|
|
248
|
-
- `offset < 0` is clamped to `0`; `pageLimit ≤ 0` falls back to the default.
|
|
249
|
-
- **Default `pageLimit` is per-API** (applied whenever the caller omits it — the API never returns "all records" unbounded): CustomerManagement = **10**, TroubleTicket = **1000**, base default = 100.
|
|
250
|
-
|
|
251
|
-
## 2.3 Filtering & sorting — how it works
|
|
252
|
-
|
|
253
|
-
The mechanism is identical for both APIs; only the named field mappings differ
|
|
254
|
-
(see §4.5 for TMF621, §5.5 for TMF629):
|
|
255
|
-
|
|
256
|
-
- **Filtering is not a fixed allow-list.** Filters are passed as dynamic query
|
|
257
|
-
params (e.g. `?Status=New`) straight into a GraphQL `where` clause — filtering
|
|
258
|
-
is allowed on any valid Salesforce field. Each API also has a small **named
|
|
259
|
-
TMF-field mapping** whose TMF aliases work for filtering, sorting, and
|
|
260
|
-
`fields=` selection; any other raw Salesforce field name on the backing object
|
|
261
|
-
also works.
|
|
262
|
-
- **`sort=` query param** is available at minVersion 264. Besides the flat
|
|
263
|
-
named/raw fields, a short whitelist of nested (dotted) 1:1-relationship sort
|
|
264
|
-
paths is allowed per API.
|
|
265
|
-
- **Multi-record/child connections are not sortable** via the parent list
|
|
266
|
-
(e.g. notes, attachments, status history, child accounts, contracts) — they
|
|
267
|
-
are GraphQL connections, not scalar columns.
|
|
268
|
-
- The Workbench artifact param `t` is explicitly stripped, and any filter with a
|
|
269
|
-
`null` field name or `null` value is silently dropped.
|
|
270
|
-
- **A bad filter field fails silently as an empty result — not an error.** The
|
|
271
|
-
raw field name is dropped **untranslated** into the GraphQL `where` clause, so
|
|
272
|
-
it must be a valid, GraphQL-queryable field on the backing object. If you pass
|
|
273
|
-
a field that doesn't exist (or isn't queryable), the GraphQL layer errors and
|
|
274
|
-
the API **returns an empty result set rather than a 4xx**. So an empty list can
|
|
275
|
-
mean "no matching records" **or** "you filtered on a field name that doesn't
|
|
276
|
-
exist" — warn the user of this when a filter unexpectedly returns nothing.
|
|
277
|
-
|
|
278
|
-
### 2.3.1 When a user wants to filter by a field that isn't an out-of-the-box named filter
|
|
279
|
-
|
|
280
|
-
If a user asks to filter by something not in the named filter/mapping table
|
|
281
|
-
(§4.5/§5.5), **ask them which exact field they mean**, then follow this decision
|
|
282
|
-
flow — do not guess:
|
|
283
|
-
|
|
284
|
-
1. **Is it a field that exists directly on the backing object** (`Case` for
|
|
285
|
-
TMF621, `Account` for TMF629)? Confirm the field is really present on that
|
|
286
|
-
object (ask the user, or check the org schema — do not assume). If yes:
|
|
287
|
-
- **No extensibility needed.** Tell the user they can filter by the raw
|
|
288
|
-
Salesforce field name directly as a query param — e.g.
|
|
289
|
-
`?Origin=Phone` (TMF621) or `?Industry=Telecom` (TMF629). It works out of
|
|
290
|
-
the box (verified: unmapped field names pass straight into the `where`
|
|
291
|
-
clause). Only offer extensibility if they *also* want to expose it under a
|
|
292
|
-
different TMF-facing name (see step 2).
|
|
293
|
-
2. **Do they want to filter under a custom/renamed TMF name, or the field is on
|
|
294
|
-
a related/child object** (not a scalar column on the backing object)? Then it
|
|
295
|
-
needs **extensibility** (`customiseGraphQLQuery` — add a filter to the right
|
|
296
|
-
node, or map the incoming name). If feasible:
|
|
297
|
-
- Confirm feasibility, then **ask the customer which Salesforce field they
|
|
298
|
-
want that TMF filter name mapped to**, and write the extensibility class
|
|
299
|
-
using that mapping (per the mandatory gate + §3.4). Substitute their real
|
|
300
|
-
field/relationship API names.
|
|
301
|
-
3. **Is the field NOT present on the entity at all** (no such field on the
|
|
302
|
-
object, and not reachable via a relationship the hooks can query)? Then
|
|
303
|
-
**plainly tell the user it cannot be done because the field itself does not
|
|
304
|
-
exist on that entity** — do not invent a workaround, and (per rule 2) do not
|
|
305
|
-
create the field yourself. If they want it, they must add the schema first
|
|
306
|
-
(then it becomes filterable per step 1).
|
|
307
|
-
|
|
308
|
-
---
|
|
309
|
-
|
|
310
|
-
# Part 3 — Extensibility framework (common to both APIs)
|
|
311
|
-
|
|
312
|
-
This is the **only** mechanism intended for customization: an Apex class
|
|
313
|
-
implementing a well-known interface, deployed to the org. There is no Java code
|
|
314
|
-
change, no config file, no registry entry needed — the framework discovers your
|
|
315
|
-
Apex class by its **interface name** at request time. Only enter this part for
|
|
316
|
-
an extensibility scenario, and only after the mandatory gate at the top of this
|
|
317
|
-
skill.
|
|
318
|
-
|
|
319
|
-
## 3.1 The interface family tree
|
|
320
|
-
|
|
321
|
-
```text
|
|
322
|
-
comms_apex_ext.ICommsExtensible (base — declares transformRequest, configureDefaultValidations,
|
|
323
|
-
applyCustomValidations, customiseGraphQLQuery, handlePostOperation
|
|
324
|
-
— ALL 5 methods, inherited by every verb below, GET included)
|
|
325
|
-
├── comms_apex_ext.ICommsGET extends ICommsExtensible (no extra methods)
|
|
326
|
-
│ ├── comms_apex_ext.ITroubleTicketManagementGET extends ICommsGET ← implement for TMF621 GET
|
|
327
|
-
│ └── comms_apex_ext.ICustomerManagementGET extends ICommsGET ← implement for TMF629 GET
|
|
328
|
-
├── comms_apex_ext.ICommsPOST extends ICommsExtensible (+ customiseMutationPayload)
|
|
329
|
-
│ ├── comms_apex_ext.ITroubleTicketManagementPOST extends ICommsPOST ← implement for TMF621 POST
|
|
330
|
-
│ └── comms_apex_ext.ICustomerManagementPOST extends ICommsPOST ← implement for TMF629 POST
|
|
331
|
-
├── comms_apex_ext.ICommsPATCH extends ICommsExtensible (+ customiseMutationPayload)
|
|
332
|
-
│ ├── comms_apex_ext.ITroubleTicketManagementPATCH extends ICommsPATCH ← implement for TMF621 PATCH
|
|
333
|
-
│ └── comms_apex_ext.ICustomerManagementPATCH extends ICommsPATCH ← implement for TMF629 PATCH
|
|
334
|
-
└── comms_apex_ext.ICommsDELETE extends ICommsExtensible (+ customiseMutationPayload)
|
|
335
|
-
├── comms_apex_ext.ITroubleTicketManagementDELETE extends ICommsDELETE ← implement for TMF621 DELETE
|
|
336
|
-
└── comms_apex_ext.ICustomerManagementDELETE extends ICommsDELETE ← implement for TMF629 DELETE
|
|
337
|
-
```
|
|
338
|
-
|
|
339
|
-
**Important — `customiseGraphQLQuery` is declared on the base `ICommsExtensible`
|
|
340
|
-
interface, not added by `ICommsGET`.** That means it is inherited by every
|
|
341
|
-
verb's interface, including POST/PATCH/DELETE. Apex requires implementing
|
|
342
|
-
every method an interface declares or inherits, so a POST/PATCH/DELETE Apex
|
|
343
|
-
class **must** also implement `customiseGraphQLQuery` (no-op it by returning
|
|
344
|
-
`null` — see §3.2) or the class will fail to compile. In practice it only has
|
|
345
|
-
real effect on GET, since POST/PATCH/DELETE don't run a query — but it still
|
|
346
|
-
must be present in the class body for any verb.
|
|
347
|
-
|
|
348
|
-
**Rule of thumb: pick exactly one interface per HTTP verb you want to customize**,
|
|
349
|
-
implement it in a single Apex class (a class *can* implement more than one of
|
|
350
|
-
these interfaces at once, e.g. both GET and POST, if you want one class to
|
|
351
|
-
handle multiple verbs — see the "combined pattern" example in §3.8). **All 5
|
|
352
|
-
methods declared on `ICommsExtensible` must be implemented for every verb**
|
|
353
|
-
(plus `customiseMutationPayload` for POST/PATCH/DELETE), even if you just want
|
|
354
|
-
to no-op them — return the "do nothing" value shown per hook below.
|
|
355
|
-
|
|
356
|
-
There is **no sub-resource-specific interface** — sub-resource requests
|
|
357
|
-
(`GET .../{id}/{subResource}`) are routed through the *same* `ICommsGET`
|
|
358
|
-
implementation as the plain single-entity GET; you distinguish sub-resource
|
|
359
|
-
requests inside your hooks by checking `context.get("subResourceName")` /
|
|
360
|
-
registering custom sub-resource mappings (§3.7).
|
|
361
|
-
|
|
362
|
-
## 3.2 Every hook method, in call order
|
|
363
|
-
|
|
364
|
-
The framework calls your hooks in this fixed pipeline order for every request.
|
|
365
|
-
**If you don't implement a behavior for a hook, return the pass-through/no-op
|
|
366
|
-
value shown — do not return `null` unless explicitly allowed, as some hooks
|
|
367
|
-
treat `null` as "no data to merge" rather than "no-op".**
|
|
368
|
-
|
|
369
|
-
| Order | Hook | Verbs | Signature | Purpose | No-op return |
|
|
370
|
-
|---|---|---|---|---|---|
|
|
371
|
-
| 1 | `transformRequest` | GET/POST/PATCH/DELETE | `Map<String,Object> transformRequest(Map<String,Object> context)` | First hook called. Mutate the request context before anything else runs — e.g. resolve an external ID to a Salesforce Id, inject custom flags/params used by later hooks. | `return context;` |
|
|
372
|
-
| 2 | `configureDefaultValidations` | GET/POST/PATCH/DELETE | `Map<String,Boolean> configureDefaultValidations(Map<String,Boolean> defaultValidationConfiguration, Map<String,Object> context)` | Turn built-in field validators on/off per request (§3.6). | `return defaultValidationConfiguration;` (or `new Map<String,Boolean>()` to accept framework defaults unchanged) |
|
|
373
|
-
| 3 | `applyCustomValidations` | GET/POST/PATCH/DELETE | `Map<String,Object> applyCustomValidations(Map<String,Object> context)` | Run your own validation logic. To **fail** the request, return a map shaped like the error example below; the framework throws and the HTTP call gets a 400. | `return null;` |
|
|
374
|
-
| 4a | `customiseGraphQLQuery` | GET/POST/PATCH/DELETE (declared on base `ICommsExtensible`; only has functional effect on GET, but must still be implemented for every verb) | `Map<String,Object> customiseGraphQLQuery(Map<String,Object> graphQLAsMap, Map<String,Object> context)` | Add/remove fields, add/merge filters, set sort order on the query the framework is about to run. | `return null;` |
|
|
375
|
-
| 4b | `customiseMutationPayload` | POST/PATCH/DELETE only | `Map<String,Object> customiseMutationPayload(Map<String,Object> mutationGraphQLPayload, Map<String,Object> context)` | Add extra fields/values to the create/update/delete mutation before it executes. | `return null;` |
|
|
376
|
-
| 5 | (framework executes the GraphQL query/mutation — not customizable) | — | — | — | — |
|
|
377
|
-
| 6 | `handlePostOperation` | GET/POST/PATCH/DELETE (called on every verb, but the returned payload override is only applied on GET — see §3.3) | `Map<String,Object> handlePostOperation(Map<String,Object> graphQLQueryResultAsMap, Map<String,Object> constructedTMFResponse, Map<String,Object> context)` | Last hook. Inspect the raw GraphQL result and/or the TMF-shaped response the framework built, and on GET optionally **replace it entirely**. | `return null;` |
|
|
378
|
-
|
|
379
|
-
Note `applyCustomValidations` and `handlePostOperation` share the same name
|
|
380
|
-
across GET/POST/PATCH/DELETE (defined once on the base `ICommsExtensible`), so
|
|
381
|
-
implementing a POST class means implementing them for the POST flow, etc. — the
|
|
382
|
-
framework calls whichever concrete class is currently active for that verb.
|
|
383
|
-
|
|
384
|
-
Hook methods may be declared **either `global static` or as instance
|
|
385
|
-
(`global`/`public`) methods** — the framework instantiates your class and then
|
|
386
|
-
invokes the method, so both styles compile and run. The examples
|
|
387
|
-
below use `global static`; instance methods work identically.
|
|
388
|
-
|
|
389
|
-
Quick "which hook do I use" index:
|
|
390
|
-
|
|
391
|
-
| Goal | Hook(s) |
|
|
392
|
-
|---|---|
|
|
393
|
-
| Resolve an external id (CaseNumber, AccountNumber) to a Salesforce Id | `transformRequest` |
|
|
394
|
-
| Enforce a custom business rule / access check before running | `applyCustomValidations` |
|
|
395
|
-
| Role-based data filtering (block, then trim what's returned) | `applyCustomValidations` + `handlePostOperation` |
|
|
396
|
-
| Add fields / server-side filter / sort to a GET query | `customiseGraphQLQuery` |
|
|
397
|
-
| Add fields to a create/update mutation | `customiseMutationPayload` |
|
|
398
|
-
| Enrich or restructure the response (calculated fields, GET-only full override) | `handlePostOperation` |
|
|
399
|
-
|
|
400
|
-
`transformRequest` receives (and must return) the same `context` map passed to
|
|
401
|
-
every later hook. The framework reads two keys back out of it after the call:
|
|
402
|
-
`context.get('id')` (a `String`) overwrites the path id used for the rest of
|
|
403
|
-
the request, and `context.get('requestBody')` (a `Map`) overwrites the request
|
|
404
|
-
body — this is how you resolve an alternate identifier (e.g. an external
|
|
405
|
-
account/order number) to a Salesforce Id before any query or mutation runs:
|
|
406
|
-
|
|
407
|
-
```java
|
|
408
|
-
global static Map<String, Object> transformRequest(Map<String, Object> context) {
|
|
409
|
-
String rawId = (String) context.get('id');
|
|
410
|
-
if (rawId != null && !rawId.startsWith('001')) { // not already a Salesforce Account Id
|
|
411
|
-
List<Account> matches = [SELECT Id FROM Account WHERE AccountNumber = :rawId LIMIT 1];
|
|
412
|
-
if (!matches.isEmpty()) {
|
|
413
|
-
context.put('id', matches[0].Id);
|
|
414
|
-
}
|
|
415
|
-
}
|
|
416
|
-
return context;
|
|
417
|
-
}
|
|
418
|
-
```
|
|
419
|
-
|
|
420
|
-
## 3.3 `handlePostOperation` — the two response-shaping outcomes
|
|
421
|
-
|
|
422
|
-
`handlePostOperation` is the most commonly used hook. It always receives:
|
|
423
|
-
|
|
424
|
-
- `graphQLQueryResultAsMap` — the raw GraphQL response (`{"data": {"uiapi": {"query": {...}}}}` shape for GET, or `{"data": {"uiapi": {<alias>: {...}}}}` for mutations).
|
|
425
|
-
- `constructedTMFResponse` — the TMF-shaped payload the framework already built (e.g. `{"id": "...", "name": "...", "href": "..."}` for single-record GET, or `{"recordList": [...]}` for list GET).
|
|
426
|
-
- `context` — the (possibly already transformed) request context.
|
|
427
|
-
|
|
428
|
-
Return one of:
|
|
429
|
-
|
|
430
|
-
**A. No change** — return `null`. The framework's `constructedTMFResponse` is used as-is.
|
|
431
|
-
|
|
432
|
-
**B. Full override** — return:
|
|
433
|
-
```java
|
|
434
|
-
new Map<String, Object>{
|
|
435
|
-
'payloadOverwritten' => true,
|
|
436
|
-
'updatedPayload' => myModifiedResponseMap // must be a complete replacement, not a diff
|
|
437
|
-
}
|
|
438
|
-
```
|
|
439
|
-
When `payloadOverwritten=true`, the framework serializes exactly `updatedPayload`
|
|
440
|
-
back to the caller as the response body (surfaced as the `updatedPayload` field
|
|
441
|
-
on the output representation — see §4.2/§5.2). This is how the reference example
|
|
442
|
-
in §3.8 renames `id`→`salesforce_id` and injects an extra field.
|
|
443
|
-
|
|
444
|
-
**This override only works on GET.** `handlePostOperation`'s return value is
|
|
445
|
-
only read back and applied on the GET path. On POST, PATCH,
|
|
446
|
-
and DELETE the framework still *calls* your `handlePostOperation` (so
|
|
447
|
-
side-effecting logic — logging, firing a platform event, calling out to another
|
|
448
|
-
system — still runs), but the map you return is discarded; there is no
|
|
449
|
-
supported way to overwrite the POST/PATCH/DELETE response body from this hook.
|
|
450
|
-
If you need to change what a mutation returns, do it via `customiseMutationPayload`
|
|
451
|
-
(§3.5) before the mutation runs, not via `handlePostOperation` after.
|
|
452
|
-
|
|
453
|
-
## 3.4 `customiseGraphQLQuery` — instruction map shape (GET)
|
|
454
|
-
|
|
455
|
-
Return a map with a `nodes` list; each entry targets one GraphQL query node by
|
|
456
|
-
its `path` alias (`troubleTicket` for TMF621, `troubleTicket`/`customerAccount`
|
|
457
|
-
depending on handler — check the raw query in `graphQLAsMap.get("query")` to
|
|
458
|
-
find the exact alias for the entity you're customizing):
|
|
459
|
-
|
|
460
|
-
```java
|
|
461
|
-
global static Map<String, Object> customiseGraphQLQuery(Map<String,Object> querySpec, Map<String,Object> context) {
|
|
462
|
-
return new Map<String, Object>{
|
|
463
|
-
'nodes' => new List<Object>{
|
|
464
|
-
new Map<String, Object>{
|
|
465
|
-
'path' => 'troubleTicket', // GraphQL alias to target
|
|
466
|
-
'addFields' => new List<String>{ 'IsClosed { value }' }, // extra fields to select
|
|
467
|
-
'addFilters' => new Map<String, Object>{
|
|
468
|
-
'clearExistingFilters' => false, // false = merge with existing filters
|
|
469
|
-
'filterGraphQlSnippet' => '{ IsClosed: { eq: true } }'
|
|
470
|
-
},
|
|
471
|
-
'orderBy' => new Map<String, Object>{
|
|
472
|
-
'clearExistingOrderBy' => true, // true = replace any client-requested sort
|
|
473
|
-
'orderGraphQlSnippet' => '{ Subject: { order: ASC } }'
|
|
474
|
-
}
|
|
475
|
-
}
|
|
476
|
-
}
|
|
477
|
-
};
|
|
478
|
-
}
|
|
479
|
-
```
|
|
480
|
-
|
|
481
|
-
`addFields` entries are raw GraphQL field-selection snippets appended under the
|
|
482
|
-
targeted node — use `{ value }` suffix for scalar fields per UI API convention
|
|
483
|
-
(e.g. `'IsClosed { value }'`, not just `'IsClosed'`).
|
|
484
|
-
|
|
485
|
-
## 3.5 `customiseMutationPayload` — instruction map shape (POST/PATCH/DELETE)
|
|
486
|
-
|
|
487
|
-
```java
|
|
488
|
-
global static Map<String, Object> customiseMutationPayload(Map<String,Object> mutationGraphQLPayload, Map<String,Object> context) {
|
|
489
|
-
return new Map<String, Object>{
|
|
490
|
-
'nodes' => new List<Object>{
|
|
491
|
-
new Map<String, Object>{
|
|
492
|
-
'path' => 'customerAccount', // mutation alias to target, e.g. AccountCreate/AccountUpdate/AccountDelete
|
|
493
|
-
'addFields' => new Map<String, Object>{ // for mutations, addFields is a map of field->value, not a list
|
|
494
|
-
'Industry' => 'Technology',
|
|
495
|
-
'Revenue' => 5000000,
|
|
496
|
-
'Status' => 'Active'
|
|
497
|
-
}
|
|
498
|
-
}
|
|
499
|
-
}
|
|
500
|
-
};
|
|
501
|
-
}
|
|
502
|
-
```
|
|
503
|
-
|
|
504
|
-
A mutation node supports these keys (all optional except `path`):
|
|
505
|
-
|
|
506
|
-
| Key | Shape | Effect |
|
|
507
|
-
|---|---|---|
|
|
508
|
-
| `addFields` | `Map<String,Object>` (field→value) | Adds brand-new fields/values to the mutation input for that node. |
|
|
509
|
-
| `modifyInput` | `Map` with `inputModifications` / `addInputFields` / `removeInputFields` | Rewrite fields already in the input. `inputModifications` (field→new value) overwrites values the caller sent — e.g. `{'Name' => 'Updated ' + originalName}`; `removeInputFields` is a `List<String>` of fields to drop. |
|
|
510
|
-
| `insertGraphQlSnippet` | `String` (raw GraphQL) | Inject an extra mutation node — e.g. create a related custom-object record. Use `@{alias}` to reference the id of another node created in the same mutation (e.g. `Account__c: "@{customerAccount}"`). |
|
|
511
|
-
| `updateGraphQlSnippet` | `String` (raw GraphQL) | Same, for an update sub-mutation. |
|
|
512
|
-
|
|
513
|
-
Example — overwrite the caller-supplied `Name` and create a related record in one call:
|
|
514
|
-
```java
|
|
515
|
-
global static Map<String, Object> customiseMutationPayload(Map<String,Object> request, Map<String,Object> context) {
|
|
516
|
-
Map<String,Object> body = (Map<String,Object>) context.get('requestBody');
|
|
517
|
-
String name = body == null ? null : (String) body.get('name');
|
|
518
|
-
if (String.isBlank(name)) { return new Map<String, Object>(); } // no-op → return empty map, not null
|
|
519
|
-
return new Map<String, Object>{
|
|
520
|
-
'nodes' => new List<Object>{
|
|
521
|
-
new Map<String, Object>{
|
|
522
|
-
'path' => 'customerAccount',
|
|
523
|
-
'modifyInput' => new Map<String, Object>{
|
|
524
|
-
'inputModifications' => new Map<String, Object>{ 'Name' => 'Updated ' + name }
|
|
525
|
-
}
|
|
526
|
-
},
|
|
527
|
-
new Map<String, Object>{
|
|
528
|
-
'path' => 'customerAccount.extCustomer',
|
|
529
|
-
'insertGraphQlSnippet' => 'extCustomer: ExtCustomer__cCreate(input: { ExtCustomer__c: { Name: "'
|
|
530
|
-
+ name.replace('\\', '\\\\').replace('"', '\\"')
|
|
531
|
-
+ '", Account__c: "@{customerAccount}" } }) { Record { Id } }'
|
|
532
|
-
}
|
|
533
|
-
}
|
|
534
|
-
};
|
|
535
|
-
}
|
|
536
|
-
```
|
|
537
|
-
|
|
538
|
-
## 3.6 Built-in field validators you can toggle with `configureDefaultValidations`
|
|
539
|
-
|
|
540
|
-
Each API has its own set of named boolean validators; pass a map with the names
|
|
541
|
-
you want to flip. Any name you omit keeps the framework's default for that verb
|
|
542
|
-
(shown below — POST defaults to all `true`, PATCH defaults to all `false`).
|
|
543
|
-
|
|
544
|
-
**`configureDefaultValidations` only has an effect on POST/PATCH/DELETE.** On
|
|
545
|
-
GET the hook is still invoked (so it must be implemented), but the map you
|
|
546
|
-
return is ignored — GET ships an empty default validation spec and never runs
|
|
547
|
-
these named validators. Use `applyCustomValidations` (§3.2) if you need to
|
|
548
|
-
reject a GET request.
|
|
549
|
-
|
|
550
|
-
**TMF621 (TroubleTicket)** — validator names: `mandatoryFieldsValidation`
|
|
551
|
-
(requires `description`, `severity`, `ticketType`), `relatedPartyValidation`
|
|
552
|
-
(each `relatedParty` entry needs non-blank `id` and `referredType` ∈
|
|
553
|
-
{`Account`,`Contact`}), `relatedEntityValidation` (each `relatedEntity` entry
|
|
554
|
-
needs non-blank `id` and `referredType` == `Asset`).
|
|
555
|
-
- POST default: `{mandatoryFieldsValidation: true, relatedPartyValidation: true, relatedEntityValidation: true}`
|
|
556
|
-
- PATCH default: `{mandatoryFieldsValidation: false, relatedPartyValidation: false, relatedEntityValidation: false}`
|
|
557
|
-
|
|
558
|
-
**TMF629 (Customer)** — validator names: `mandatoryFieldsValidation`,
|
|
559
|
-
`engagedPartyValidation`, `contactMediumValidation`, `accountValidation`.
|
|
560
|
-
- POST default: `{mandatoryFieldsValidation: true, engagedPartyValidation: true, contactMediumValidation: true, accountValidation: true}`
|
|
561
|
-
- PATCH default: `{mandatoryFieldsValidation: false, engagedPartyValidation: false, contactMediumValidation: false, accountValidation: false}`
|
|
562
|
-
|
|
563
|
-
Example — disable the mandatory-fields check on TMF621 POST:
|
|
564
|
-
```java
|
|
565
|
-
global static Map<String, Boolean> configureDefaultValidations(
|
|
566
|
-
Map<String, Boolean> defaultValidationConfiguration, Map<String, Object> context) {
|
|
567
|
-
Map<String, Boolean> updated = new Map<String, Boolean>(defaultValidationConfiguration);
|
|
568
|
-
updated.put('mandatoryFieldsValidation', false);
|
|
569
|
-
return updated;
|
|
570
|
-
}
|
|
571
|
-
```
|
|
572
|
-
|
|
573
|
-
To **fail** a request from `applyCustomValidations` instead, return
|
|
574
|
-
`validationStatus`/`validationMessage`/`validationDetails` as **top-level**
|
|
575
|
-
keys (no extra wrapper) — this is exactly what the framework reads back when it
|
|
576
|
-
invokes `applyCustomValidations`:
|
|
577
|
-
```java
|
|
578
|
-
global static Map<String, Object> applyCustomValidations(Map<String, Object> context) {
|
|
579
|
-
Boolean isBad = /* your check */ false;
|
|
580
|
-
if (isBad) {
|
|
581
|
-
return new Map<String, Object>{
|
|
582
|
-
'validationStatus' => 'fail',
|
|
583
|
-
'validationMessage' => 'Custom validation failure',
|
|
584
|
-
'validationDetails' => new Map<String, Object>{
|
|
585
|
-
'statusCode' => 'BAD_REQUEST',
|
|
586
|
-
'errorCode' => 'BAD_REQUEST'
|
|
587
|
-
}
|
|
588
|
-
};
|
|
589
|
-
}
|
|
590
|
-
return null;
|
|
591
|
-
}
|
|
592
|
-
```
|
|
593
|
-
`validationStatus` is checked case-insensitively against `"fail"`; on a match
|
|
594
|
-
the framework throws and the call gets a 400 with `validationMessage` (default
|
|
595
|
-
`"Validation failed"`) and `validationDetails` in the error body.
|
|
596
|
-
|
|
597
|
-
## 3.7 Registering a brand-new custom sub-resource (no Java change)
|
|
598
|
-
|
|
599
|
-
Do this entirely from `transformRequest` on your `*GET` implementation: put a
|
|
600
|
-
`customSubResourceMappings` entry into the context, keyed by the sub-resource
|
|
601
|
-
name you want exposed in the URL, describing the SOQL-level relationship:
|
|
602
|
-
|
|
603
|
-
```java
|
|
604
|
-
global static Map<String, Object> transformRequest(Map<String, Object> context) {
|
|
605
|
-
context.put('customSubResourceMappings', new Map<String, Object>{
|
|
606
|
-
'opportunities' => new Map<String, Object>{
|
|
607
|
-
'sfChildObjectName' => 'Opportunity',
|
|
608
|
-
'sfParentLookupField' => 'AccountId',
|
|
609
|
-
'sfRelationshipName' => 'Opportunities'
|
|
610
|
-
}
|
|
611
|
-
});
|
|
612
|
-
return context;
|
|
613
|
-
}
|
|
614
|
-
```
|
|
615
|
-
|
|
616
|
-
Then in `customiseGraphQLQuery`, inject the raw GraphQL connection snippet for
|
|
617
|
-
that relationship (`insertGraphQlSnippet` instruction), and in
|
|
618
|
-
`handlePostOperation`, read `context.get("isCustomSubResource")` /
|
|
619
|
-
`context.get("customSubResourceRawRecords")` and build the TMF JSON yourself
|
|
620
|
-
(the framework defers all shaping of custom sub-resources to your Apex — it
|
|
621
|
-
only knows how to shape the built-in ones listed in §4.3/§5.3).
|
|
622
|
-
|
|
623
|
-
## 3.8 Worked examples & pattern sketches — adapt, don't copy verbatim
|
|
624
|
-
|
|
625
|
-
> **⚠️ Read before using anything in §3.8.x.** The Apex classes in §3.8, §3.8.1,
|
|
626
|
-
> and §3.8.2 are **illustrative samples to learn the mechanics from — they are
|
|
627
|
-
> NOT the source of truth and NOT copy-paste-ready.** They encode field names,
|
|
628
|
-
> object names, validation rules, and business logic that were invented for the
|
|
629
|
-
> example, not derived from the user's org. **Do not deploy any of them as-is.**
|
|
630
|
-
>
|
|
631
|
-
> When a user asks for an extensibility class:
|
|
632
|
-
> 1. **First understand what the user actually wants** — which verb (GET/POST/
|
|
633
|
-
> PATCH/DELETE), which entity (TMF621 vs TMF629), which hooks, what fields/
|
|
634
|
-
> objects/rules in *their* org, and what the desired behavior is. Ask if it's
|
|
635
|
-
> ambiguous (per the mandatory verification gate at the top of this skill).
|
|
636
|
-
> 2. **Then write a fresh class tailored to that request**, using these samples
|
|
637
|
-
> only as a reference for the correct interface (§3.1), hook signatures
|
|
638
|
-
> (§3.2), return-value contracts (§3.3–§3.6), and the `'nodes'`/`addFields`/
|
|
639
|
-
> `insertGraphQlSnippet`/`@{alias}` mechanics. Substitute the user's real
|
|
640
|
-
> field/object API names — never keep the sample placeholders.
|
|
641
|
-
> 3. **Verify and deploy** per the §3.11 workflow, then re-hit the endpoint to
|
|
642
|
-
> confirm the behavior.
|
|
643
|
-
>
|
|
644
|
-
> The source of truth is always the framework code and the user's org schema —
|
|
645
|
-
> not these snippets.
|
|
646
|
-
|
|
647
|
-
### 3.8.0 Full worked example — combine multiple patterns in one class
|
|
648
|
-
|
|
649
|
-
This is a complete, deployable-shaped Apex class for **TMF621 GET** that (1) adds
|
|
650
|
-
an extra field to the response, (2) filters server-side, (3) sorts, and (4)
|
|
651
|
-
renames a response field — demonstrating that all four extensibility axes can be
|
|
652
|
-
combined freely in one class. **Adapt the field names and logic to the user's
|
|
653
|
-
org before deploying (see the §3.8 banner).**
|
|
654
|
-
|
|
655
|
-
**Full source:** the bundled reference sample **TroubleTicketCombinedPattern**
|
|
656
|
-
— read that file in the skill's references/apex-samples bundle for the complete class. It implements
|
|
657
|
-
`comms_apex_ext.ITroubleTicketManagementGET`, targets the `troubleTicket` query
|
|
658
|
-
node in `customiseGraphQLQuery` (adds `IsClosed { value }`, a
|
|
659
|
-
`clearExistingFilters=false` filter, and an `orderBy`), and in
|
|
660
|
-
`handlePostOperation` unwraps the `data → uiapi → query → troubleTicket → edges`
|
|
661
|
-
shape to rename `id` → `salesforce_id` and copy `IsClosed` onto each record via a
|
|
662
|
-
`payloadOverwritten`/`updatedPayload` override.
|
|
663
|
-
|
|
664
|
-
Deploy this class to your org (Setup → Apex Classes, or via the Metadata REST
|
|
665
|
-
API / Tooling API — see §3.11), then simply call the TMF621 GET/list endpoints
|
|
666
|
-
as shown in §4.4 — no additional registration step. The framework finds it
|
|
667
|
-
automatically (see §3.9).
|
|
668
|
-
|
|
669
|
-
### 3.8.1 Pattern sketch — advanced TMF629 GET (external-key resolution + supplementary SOQL + custom sub-resources)
|
|
670
|
-
|
|
671
|
-
> **⚠️ Pattern sketch, not a verified drop-in.** Every construct below was
|
|
672
|
-
> checked against the framework contract (hook signatures, the `'nodes'` /
|
|
673
|
-
> `clearExistingFilters` / `filterGraphQlSnippet` keys, the alias-based `path`,
|
|
674
|
-
> the `data → uiapi → query → customerAccount → edges` shape, the
|
|
675
|
-
> `payloadOverwritten`/`updatedPayload` contract, the filter fields
|
|
676
|
-
> `fieldName`/`value`, and the case-insensitive `"fail"` check).
|
|
677
|
-
> **It has NOT been compiled or deployed to an org**, so treat it as an
|
|
678
|
-
> illustrative composition, not copy-paste-ready code. Before using it, follow
|
|
679
|
-
> the §3.11 workflow: deploy it, hit `GET /connect/comms/customermanagement/v4/customer/{id}`,
|
|
680
|
-
> and confirm the enrichment actually appears — then fix whatever the live run
|
|
681
|
-
> surfaces. Field/relationship API names (`AccountNumber`, `Opportunities`,
|
|
682
|
-
> `Contract.ContractNumber`) are placeholders; substitute your org's real ones.
|
|
683
|
-
|
|
684
|
-
This sketch composes three patterns the earlier examples only show in isolation:
|
|
685
|
-
|
|
686
|
-
1. **`transformRequest`** — accept a business key (`AccountNumber`) in the
|
|
687
|
-
`{id}`/filter slot and rewrite the filter's `value` to the real `Account` Id
|
|
688
|
-
(the framework maps a path `{id}` into a filter whose `fieldName` is `Id`).
|
|
689
|
-
2. **`customiseGraphQLQuery`** — add scalar fields plus a related child
|
|
690
|
-
connection (`Opportunities`) to the `customerAccount` node.
|
|
691
|
-
3. **`handlePostOperation`** — run supplementary SOQL the GraphQL query can't
|
|
692
|
-
express (latest `ContractNumber` per account), then inject a brand-new
|
|
693
|
-
`relatedOpportunities` sub-resource and drop an OOTB field — handling **both**
|
|
694
|
-
the list (`recordList`) and single-record (`id`) response shapes.
|
|
695
|
-
|
|
696
|
-
**Full source:** the bundled reference sample **CustomerManagementAdvancedGet**
|
|
697
|
-
— read that file in the skill's references/apex-samples bundle for the complete class, including the private `enrichRecord` /
|
|
698
|
-
`extractOpportunities` / `graphQLValue` helpers.
|
|
699
|
-
|
|
700
|
-
**Two things this sketch deliberately does NOT do** (both were present in a
|
|
701
|
-
source doc but are wrong against the code, so don't reintroduce them):
|
|
702
|
-
`customiseGraphQLQuery` must return `'nodes'` (a `'spec'` key is silently
|
|
703
|
-
ignored); and a transformation `path` must be a GraphQL **alias**
|
|
704
|
-
(`customerAccount`), never a dotted `uiapi.query.Account` — structural fields
|
|
705
|
-
(`uiapi`, `query`, `edges`, `node`, `pageInfo`) are stripped during path
|
|
706
|
-
resolution. The filter object provided to `transformRequest` also has **only**
|
|
707
|
-
the keys `fieldName`, `operator`, `value`, and `dataType` — there is no
|
|
708
|
-
`soqlcondition`/`rawValue` sub-map to mutate.
|
|
709
|
-
|
|
710
|
-
### 3.8.2 Pattern sketch — advanced TMF629 POST (custom validations + related-record mutation + side-effect DML)
|
|
711
|
-
|
|
712
|
-
> **⚠️ Pattern sketch, not a verified drop-in** (see the §3.8 banner — adapt to
|
|
713
|
-
> the user's request/org, don't copy verbatim). Every construct below was
|
|
714
|
-
> checked against the framework contract (the `customiseMutationPayload`
|
|
715
|
-
> `'nodes'` shape with **`addFields` as a `Map`**; per-node
|
|
716
|
-
> `insertGraphQlSnippet`; the `@{customerAccount}` back-reference; the
|
|
717
|
-
> `validationStatus: "fail"` case-insensitive reject; and the POST
|
|
718
|
-
> post-processing flow). **It has NOT been compiled or deployed.**
|
|
719
|
-
> Field/relationship API names
|
|
720
|
-
> (`NumberOfEmployees`, `Website`, `MyChild__c`, etc.) are placeholders —
|
|
721
|
-
> substitute the user's real ones. Deploy and hit
|
|
722
|
-
> `POST /connect/comms/customermanagement/v4/customer` per §3.11 before trusting it.
|
|
723
|
-
|
|
724
|
-
**Two POST-specific gotchas this sketch exists to teach — both differ from GET:**
|
|
725
|
-
|
|
726
|
-
- **`handlePostOperation`'s return value is IGNORED for POST/PATCH/DELETE.**
|
|
727
|
-
The framework calls the hook but discards its result — there is **no
|
|
728
|
-
`payloadOverwritten`/`updatedPayload` response-override for mutations** (that
|
|
729
|
-
only works on GET, §3.3). On a mutation, `handlePostOperation` is only useful
|
|
730
|
-
for **side effects** (extra DML). Anything you `return` vanishes.
|
|
731
|
-
- **The hook's 2nd parameter is the REQUEST BODY on a mutation, not the TMF
|
|
732
|
-
response.** For GET it's the constructed TMF response; for POST/PATCH/DELETE
|
|
733
|
-
the framework passes the request body map as the 2nd parameter. Name it
|
|
734
|
-
accordingly.
|
|
735
|
-
|
|
736
|
-
Also note: for a **mutation**, `addFields` is a **`Map`** (field → value); for a
|
|
737
|
-
**query** (`customiseGraphQLQuery`, §3.4) `addFields` is a **`List`** of field
|
|
738
|
-
strings. Same key name, different shape per hook.
|
|
739
|
-
|
|
740
|
-
**Full source:** the bundled reference sample **CustomerManagementAdvancedPost**
|
|
741
|
-
— read that file in the skill's references/apex-samples bundle for the complete class, including the `customiseMutationPayload`
|
|
742
|
-
node list (extra `Account` fields + a `MyChild__cCreate` snippet back-referencing
|
|
743
|
-
`@{customerAccount}`), the side-effect `insert Opportunity` in
|
|
744
|
-
`handlePostOperation`, and the `escape` helper.
|
|
745
|
-
|
|
746
|
-
> **Governor-limit caution.** `applyCustomValidations` runs SOQL and
|
|
747
|
-
> `handlePostOperation` runs DML on **every** POST. Keep these minimal and
|
|
748
|
-
> bulk-safe; a heavy hook multiplies per request and can blow limits under load.
|
|
749
|
-
|
|
750
|
-
## 3.9 How your Apex class gets discovered — no registry to update
|
|
751
|
-
|
|
752
|
-
There is **no file, XML, or metadata entry to register your Apex class**. At
|
|
753
|
-
request time the framework:
|
|
754
|
-
|
|
755
|
-
1. Takes the interface name for the current verb+entity (e.g.
|
|
756
|
-
`comms_apex_ext.ITroubleTicketManagementGET`).
|
|
757
|
-
2. Queries the org's compiled Apex metadata (`ApexTypeImplementor`) for
|
|
758
|
-
**concrete classes that implement that interface**.
|
|
759
|
-
3. If exactly one is found → uses it.
|
|
760
|
-
4. If none is found → skips all Apex hooks; the endpoint behaves with pure
|
|
761
|
-
framework defaults (this is why every endpoint in Parts 4/5 works even with
|
|
762
|
-
zero Apex deployed).
|
|
763
|
-
5. If more than one concrete class implements the same interface → the request
|
|
764
|
-
**fails** with a discovery error. Only ever have one active
|
|
765
|
-
implementor per interface. If you need to swap implementations, delete/deactivate
|
|
766
|
-
the old one before deploying the new one.
|
|
767
|
-
|
|
768
|
-
This means: to extend behavior, you only ever need to **write and deploy one
|
|
769
|
-
Apex class per verb you want to customize** — nothing else in the platform
|
|
770
|
-
needs to change.
|
|
771
|
-
|
|
772
|
-
## 3.10 Permissions on your Apex extension classes
|
|
773
|
-
|
|
774
|
-
Every `comms_apex_ext.*` interface is guarded so that it is only invocable in
|
|
775
|
-
orgs that already pass the base TMF access check from §1.1 (i.e. have the
|
|
776
|
-
`CommsCloud` or `CommsCloudTMFAPI` org permission), and has a minimum API
|
|
777
|
-
version of `260` (`262` for the TroubleTicket family). This means you do not
|
|
778
|
-
need to grant any additional permission specifically for the extensibility
|
|
779
|
-
classes themselves.
|
|
780
|
-
|
|
781
|
-
## 3.11 Deploying your extensibility Apex class to the org
|
|
782
|
-
|
|
783
|
-
**Before deploying, confirm both:** (a) the user explicitly wants you to
|
|
784
|
-
deploy now (not just that the code looks correct), and (b) whether an existing
|
|
785
|
-
class already implements the target interface — if so, get explicit
|
|
786
|
-
confirmation to override/deactivate it. See the mandatory gate steps 6 and 7 at
|
|
787
|
-
the top of this skill.
|
|
788
|
-
|
|
789
|
-
**Also re-confirm the org meets the v67+ prerequisite** from the mandatory gate
|
|
790
|
-
before deploying — if the org's latest supported API version (§1.3) is below
|
|
791
|
-
`67.0`, extensibility will not work; stop and tell the user rather than
|
|
792
|
-
deploying.
|
|
793
|
-
|
|
794
|
-
**API version floor for extensibility Apex: `67.0` minimum.** Every
|
|
795
|
-
extensibility class's `apiVersion` (in its `.cls-meta.xml`, or in any
|
|
796
|
-
Metadata/Tooling API call used to deploy it) must be set to **`67.0` or
|
|
797
|
-
higher** — never lower. This applies only to the Apex class's own API version;
|
|
798
|
-
it does not change the TMF resource version segments (`v5`/`v4`) or the
|
|
799
|
-
outer Connect API version used when *calling* the endpoints in Parts 4/5.
|
|
800
|
-
|
|
801
|
-
Your extensibility class is deployed **straight into the target Salesforce org**
|
|
802
|
-
— it is ordinary customer-facing Apex, not part of this Bazel repo, and it does
|
|
803
|
-
not go through any Bazel build/CI pipeline. **Prefer the API-based deploys
|
|
804
|
-
(Option A, then Option B); fall back to the Setup UI (Option C) only if neither
|
|
805
|
-
API deploy is available or both fail.** Use the org's authenticated `Bearer`
|
|
806
|
-
token (Part 1) on every REST call below, and substitute `vXX.0` with the org's
|
|
807
|
-
**latest** supported API version discovered in §1.3 (the same version used for
|
|
808
|
-
every other call in this skill):
|
|
809
|
-
|
|
810
|
-
**Option A (preferred) — Tooling API, for a scripted single-class create/update:** POST the class to the Tooling API's `ApexClass` sobject endpoint. The `Body` is the full class source and `ApiVersion` must be `67.0` or higher (per the floor above):
|
|
811
|
-
|
|
812
|
-
```text
|
|
813
|
-
POST https://<MyDomainName>.my.salesforce.com/services/data/vXX.0/tooling/sobjects/ApexClass
|
|
814
|
-
Authorization: Bearer <access_token>
|
|
815
|
-
Content-Type: application/json
|
|
816
|
-
|
|
817
|
-
{ "Body": "<full Apex class source>", "ApiVersion": 67.0, "Status": "Active" }
|
|
818
|
-
```
|
|
819
|
-
|
|
820
|
-
To **replace** an existing class, you cannot directly `PATCH` an `ApexClass` in production-like orgs — instead use the Tooling API `MetadataContainer` + `ApexClassMember` + `ContainerAsyncRequest` deploy sequence, or use Option B. A `200`/`201` returning the new record `Id` means the compile succeeded; a compile error comes back as a `400` with the error body — report it and offer to fix.
|
|
821
|
-
|
|
822
|
-
**Option B — Metadata REST API deploy, for a scripted multi-component or replace-in-place deploy (CI, admin scripts):** package the class + its `.cls-meta.xml` (with `<apiVersion>67.0</apiVersion>` or higher) and a `package.xml` into a base64-encoded zip and POST it to the Metadata REST `deployRequest` endpoint:
|
|
823
|
-
|
|
824
|
-
```text
|
|
825
|
-
POST https://<MyDomainName>.my.salesforce.com/services/data/vXX.0/metadata/deployRequest
|
|
826
|
-
Authorization: Bearer <access_token>
|
|
827
|
-
Content-Type: application/json
|
|
828
|
-
|
|
829
|
-
{ "deployOptions": { "singlePackage": true }, "file": "<base64-encoded zip>" }
|
|
830
|
-
```
|
|
831
|
-
|
|
832
|
-
Poll `GET /services/data/vXX.0/metadata/deployRequest/<id>?includeDetails=true` until `deployResult.status` is `Succeeded` (or `Failed`, with component errors in the details). The `.cls-meta.xml` sets the class's own `apiVersion` (must be `67.0`+):
|
|
833
|
-
```xml
|
|
834
|
-
<?xml version="1.0" encoding="UTF-8"?>
|
|
835
|
-
<ApexClass xmlns="http://soap.sforce.com/2006/04/metadata">
|
|
836
|
-
<apiVersion>67.0</apiVersion>
|
|
837
|
-
<status>Active</status>
|
|
838
|
-
</ApexClass>
|
|
839
|
-
```
|
|
840
|
-
|
|
841
|
-
**Option C (last resort) — Setup UI, only when no API-based deploy is available (no scripted/token access) or both API options above have failed:**
|
|
842
|
-
|
|
843
|
-
1. In the target org, go to **Setup → (Quick Find) Apex Classes**.
|
|
844
|
-
2. Click **New**.
|
|
845
|
-
3. Paste the full class body (the exact code shown to and confirmed by the user in step 2/3 of the workflow above).
|
|
846
|
-
4. Click **Save**. Any compile errors are shown inline — report them back to the user and offer to fix before retrying.
|
|
847
|
-
5. The class is active immediately; no separate activation step, and no Java/Bazel-side change is needed for it to take effect — the framework discovers it automatically (§3.9) on the very next API call.
|
|
848
|
-
|
|
849
|
-
After any of these, always confirm the deployment actually changed behavior by re-calling the relevant endpoint from §4.4/§5.4 and comparing the response to what was expected from the new Apex logic — a successful deploy does not by itself prove the customization is wired correctly (e.g. wrong interface name, or more than one class implementing the same interface per §3.9 rule 5, would deploy cleanly but fail or no-op at request time).
|
|
850
|
-
|
|
851
|
-
---
|
|
852
|
-
|
|
853
|
-
# Part 4 — TMF621 Trouble Ticket Management (API-specific)
|
|
854
|
-
|
|
855
|
-
## 4.1 Endpoint reference (complete)
|
|
856
|
-
|
|
857
|
-
TMF resource version segment: **`v5`** (this is the only version wired to a live handler; earlier `v4`/legacy paths have no handler mapping and will error).
|
|
858
|
-
|
|
859
|
-
| # | Method | Path | Purpose | Query / body params |
|
|
860
|
-
|---|---|---|---|---|
|
|
861
|
-
| 1 | POST | `/connect/comms/troubleticket/v5/troubleticket` | Create a new trouble ticket | Body = TroubleTicket JSON (§4.2) |
|
|
862
|
-
| 2 | GET | `/connect/comms/troubleticket/v5/troubleticket` | List trouble tickets (paginated) | `offset` (int), `pageLimit` (int), `fields` (comma list), `sort` (string, e.g. `name`, `-name`), `pageinfo` (bool — return `totalPageSize`/`currentPage`), plus any dynamic filter query params. Pagination bounds/defaults: §2.2. |
|
|
863
|
-
| 3 | GET | `/connect/comms/troubleticket/v5/troubleticket/{id}` | Retrieve a single trouble ticket | `fields` (comma list to limit returned fields) |
|
|
864
|
-
| 4 | PATCH | `/connect/comms/troubleticket/v5/troubleticket/{id}` | Partially update a trouble ticket | Body = partial TroubleTicket JSON — only fields present are updated |
|
|
865
|
-
| 5 | DELETE | `/connect/comms/troubleticket/v5/troubleticket/{id}` | Delete a trouble ticket | none |
|
|
866
|
-
| 6 | GET | `/connect/comms/troubleticket/v5/troubleticket/{id}/{subResource}` | Paginate a child collection of one ticket (TMF621 §4.6 nested-resource pattern) | `offset`, `pageLimit`, `pageinfo`; `{subResource}` = one of the 8 values in §4.3 |
|
|
867
|
-
|
|
868
|
-
**`{id}` is the `CaseNumber`, not the raw Salesforce `Case` Id.** For endpoints
|
|
869
|
-
3–6 the path parameter is the human-readable ticket number (e.g. `00001002`),
|
|
870
|
-
which the GET/PATCH/DELETE handlers resolve to the internal Salesforce Id via a
|
|
871
|
-
`CaseNumber` lookup. Passing a raw `500…` `Case` Id in the URL will not match.
|
|
872
|
-
|
|
873
|
-
(Every request always runs through the extensible pipeline — see §2.1.)
|
|
874
|
-
|
|
875
|
-
## 4.2 Request/response payload shape (TroubleTicket)
|
|
876
|
-
|
|
877
|
-
**Request body fields (all optional unless required by validators — see §3.6):**
|
|
878
|
-
|
|
879
|
-
| Field | Type | Notes |
|
|
880
|
-
|---|---|---|
|
|
881
|
-
| `name` | string | Ticket subject/name |
|
|
882
|
-
| `description` | string | Free text |
|
|
883
|
-
| `status` | string | e.g. `New`, `InProgress`, `Resolved`, `Closed` — maps to Case Status |
|
|
884
|
-
| `ticketType` | string | TMF ticket type |
|
|
885
|
-
| `priority` | string | e.g. `High`/`Medium`/`Low` |
|
|
886
|
-
| `severity` | string | Comes from `CaseTroubleTicket.Severity` extension field, not `Case` directly. On POST, the `CaseTroubleTicket` extension record (which backs `severity`, `externalIdentifier`, `requestedResolutionDate`, `expectedResolutionDate`) is created **only if `severity` is set**; if `severity` is omitted, those other extension fields are dropped even when supplied |
|
|
887
|
-
| `channel` | object | On create, only `channel.name` is read and written to `Case.Origin`; any `channel.id`/`referredType` sent in the body is ignored |
|
|
888
|
-
| `expectedResolutionDate` | ISO date string | |
|
|
889
|
-
| `requestedResolutionDate` | ISO date string | |
|
|
890
|
-
| `relatedParty` | wrapper: `{ "list": [ { "partyOrPartyRole": { "id": "...", "referredType": "Account"\|"Contact" } } ] }` | Related Account/Contact references — but `Case` has only one `AccountId` and one `ContactId`, so at most one Account and one Contact persist |
|
|
891
|
-
| `relatedEntity` | wrapper: `{ "list": [ { "entity": { "id": "...", "referredType": "Asset" } } ] }` | Related Asset references — `Case` has only one `AssetId`, so at most one Asset persists |
|
|
892
|
-
| `note` | wrapper: `{ "list": [ { "text": "..." } ] }` | Notes to attach — each becomes a `CaseComment` (`text` → `CommentBody`) |
|
|
893
|
-
| `attachment` | wrapper: `{ "list": [ { "url": "...", "name": "...", "description": "..." } ] }` | Files to attach — each creates a `ContentVersion` + `ContentDocumentLink` |
|
|
894
|
-
| `troubleTicketRelationship` | wrapper: `{ "list": [ { "id": "..." } ] }` | Parent-ticket link — **only the first list entry** is used (its `id` → `Case.ParentId`) |
|
|
895
|
-
| `externalIdentifier` | wrapper: `{ "list": [ { "id": "..." } ] }` | External system ID — **only the first list entry** is used (its `id` → `CaseTroubleTicket.ExternalId`) |
|
|
896
|
-
|
|
897
|
-
**Example POST body:**
|
|
898
|
-
|
|
899
|
-
```json
|
|
900
|
-
{
|
|
901
|
-
"name": "VoIP call drops",
|
|
902
|
-
"description": "Customer reports repeated dropped calls on VoIP line",
|
|
903
|
-
"status": "New",
|
|
904
|
-
"ticketType": "Service Issue",
|
|
905
|
-
"priority": "High",
|
|
906
|
-
"severity": "Critical",
|
|
907
|
-
"relatedParty": {
|
|
908
|
-
"list": [
|
|
909
|
-
{ "partyOrPartyRole": { "id": "001xx000003GYrsAAG", "referredType": "Account" } }
|
|
910
|
-
]
|
|
911
|
-
},
|
|
912
|
-
"relatedEntity": {
|
|
913
|
-
"list": [
|
|
914
|
-
{ "entity": { "id": "02ixx0000004CvzAAE", "referredType": "Asset" } }
|
|
915
|
-
]
|
|
916
|
-
}
|
|
917
|
-
}
|
|
918
|
-
```
|
|
919
|
-
|
|
920
|
-
**Response body fields** — superset of the
|
|
921
|
-
request fields, plus: `id`, `href`, `creationDate`, `lastUpdate`,
|
|
922
|
-
`statusChangeDate`, `resolutionDate`, `statusChangeHistory` (list),
|
|
923
|
-
`updatedPayload` (only present if Apex extensibility overwrote the response —
|
|
924
|
-
see §3.3). List endpoints wrap results as
|
|
925
|
-
`{ "recordList": [ ... ], "totalPageSize": N, "currentPage": N }`.
|
|
926
|
-
|
|
927
|
-
**Response quirks to be aware of:**
|
|
928
|
-
- `id`, `@type`, and `href` are **always** returned, even when a `fields=`
|
|
929
|
-
filter is supplied that omits them — they are hard-coded as mandatory.
|
|
930
|
-
- `channel.id` is a **hard-coded literal `"1"`** in every response — it is not a
|
|
931
|
-
real Salesforce Id. Only `channel.name` (from `Case.Origin`) carries real data.
|
|
932
|
-
- Note `author` is the raw Salesforce **`CreatedById`** (a user Id), not a
|
|
933
|
-
display name.
|
|
934
|
-
- Attachment `mimeType` is a **hard-coded literal string `"MimeType"`**, not the
|
|
935
|
-
real file MIME type — do not rely on it.
|
|
936
|
-
- `statusChangeHistory` is **read-only**: it is derived from `Case.Histories`
|
|
937
|
-
filtered to `Field == 'Status'`, each entry has `@type == "StatusChange"`, and
|
|
938
|
-
it cannot be set via POST/PATCH.
|
|
939
|
-
|
|
940
|
-
## 4.3 Sub-resource pagination (endpoint #6)
|
|
941
|
-
|
|
942
|
-
`GET /connect/comms/troubleticket/v5/troubleticket/{id}/{subResource}` implements
|
|
943
|
-
TMF621 §4.6's nested-collection pattern. Supported built-in `{subResource}` values
|
|
944
|
-
(case-insensitive in the URL, matched lowercase internally):
|
|
945
|
-
|
|
946
|
-
| `{subResource}` value | Backing relationship | Maps to |
|
|
947
|
-
|---|---|---|
|
|
948
|
-
| `note` | `Case.CaseComments` | `CaseComment` |
|
|
949
|
-
| `attachment` | `Case.ContentDocumentLinks` | `ContentDocumentLink` |
|
|
950
|
-
| `statuschangehistory` | `Case.Histories` | `CaseHistory` |
|
|
951
|
-
| `relatedentity` | `Asset` reference | `Asset` |
|
|
952
|
-
| `troubleticketrelationship` | `Case.Parent` | Parent `Case` |
|
|
953
|
-
| `relatedparty` | Combined Account + Contact references | (special-cased, not a plain relationship) |
|
|
954
|
-
| `channel` | `Case.Origin` | (special-cased scalar field; `channel.id` is always the literal `"1"`, `channel.name` = `Origin`) |
|
|
955
|
-
| `externalidentifier` | `CaseTroubleTicket` | (requires an auxiliary query) |
|
|
956
|
-
|
|
957
|
-
Response shape matches the list endpoint: `{ "recordList": [...], "totalPageSize": N, "currentPage": N }`.
|
|
958
|
-
Apex extensibility (via `transformRequest`, see Part 3) can register **additional,
|
|
959
|
-
completely custom sub-resource names** at runtime that aren't in this table —
|
|
960
|
-
see §3.7.
|
|
961
|
-
|
|
962
|
-
## 4.4 API routes — TMF621, zero customization
|
|
963
|
-
|
|
964
|
-
Call these directly against `https://<your-instance>.my.salesforce.com/services/data/v<API_VERSION>.0<path>` per Part 1. No Apex required for any of these.
|
|
965
|
-
|
|
966
|
-
| Purpose | Method | Path | Body |
|
|
967
|
-
|---|---|---|---|
|
|
968
|
-
| List (first page, 10 per page) | GET | `/connect/comms/troubleticket/v5/troubleticket?offset=0&pageLimit=10&pageinfo=true` | — |
|
|
969
|
-
| Create | POST | `/connect/comms/troubleticket/v5/troubleticket` | `{"name":"VoIP call drops","description":"Repeated drops","status":"New","priority":"High"}` |
|
|
970
|
-
| Retrieve by id | GET | `/connect/comms/troubleticket/v5/troubleticket/00001002` | — |
|
|
971
|
-
| Partial update | PATCH | `/connect/comms/troubleticket/v5/troubleticket/00001002` | `{"status":"Resolved"}` |
|
|
972
|
-
| Delete | DELETE | `/connect/comms/troubleticket/v5/troubleticket/00001002` | — |
|
|
973
|
-
| Sub-resource: paginate notes on a ticket | GET | `/connect/comms/troubleticket/v5/troubleticket/00001002/note?offset=0&pageLimit=5` | — |
|
|
974
|
-
|
|
975
|
-
(`{id}` in these routes is the `CaseNumber`, e.g. `00001002` — see §4.1.)
|
|
976
|
-
|
|
977
|
-
**Troubleshooting a failing GET:** if a TMF621 GET (list, retrieve-by-id, or a
|
|
978
|
-
sub-resource page) fails, first **show the user the actual error text from the
|
|
979
|
-
response body verbatim** — do not paraphrase or guess at the cause. Then, if the
|
|
980
|
-
failure looks like an access/field error, ask the user to **enable FLS
|
|
981
|
-
read/edit on the calling user's profile or permission set for all `Case` fields**
|
|
982
|
-
(this API is a Connect resource, so ordinary field-level security applies on top
|
|
983
|
-
of the TMF access check in §1.1 — a field the caller can't read will break the
|
|
984
|
-
underlying query). Confirm the FLS change and re-run the same route before
|
|
985
|
-
investigating anything else.
|
|
986
|
-
|
|
987
|
-
## 4.5 Filtering and sorting fields — TMF621
|
|
988
|
-
|
|
989
|
-
See §2.3 for how filtering/sorting works generically. The named TMF-field
|
|
990
|
-
mapping below — these TMF names work for filtering, sorting, and `fields=`
|
|
991
|
-
selection; any other raw Salesforce `Case` field name (e.g. `Origin`,
|
|
992
|
-
`AccountId`, `ClosedDate`) also works for filtering/sorting even though it has no
|
|
993
|
-
TMF alias (filtering allows any valid Salesforce field, not just the aliases
|
|
994
|
-
below).
|
|
995
|
-
|
|
996
|
-
**If a user wants to filter by a field not in the table below, follow the
|
|
997
|
-
decision flow in §2.3.1** (confirm it's on `Case` → raw param, no extensibility;
|
|
998
|
-
custom name/related object → extensibility with a mapping; not on the entity →
|
|
999
|
-
say it can't be done). And note the empty-result gotcha from §2.3: a filter on a
|
|
1000
|
-
non-existent field returns an **empty list, not an error**.
|
|
1001
|
-
|
|
1002
|
-
**Supported filter fields (TMF name → Salesforce field):**
|
|
1003
|
-
|
|
1004
|
-
| TMF name | Salesforce field |
|
|
1005
|
-
|---|---|
|
|
1006
|
-
| `name` | `Subject` |
|
|
1007
|
-
| `id` | `CaseNumber` |
|
|
1008
|
-
| `description` | `Description` |
|
|
1009
|
-
| `status` | `Status` |
|
|
1010
|
-
| `tickettype` | `Type` |
|
|
1011
|
-
| `priority` | `Priority` |
|
|
1012
|
-
|
|
1013
|
-
Plus any raw Salesforce `Case` field name passed directly as a query param.
|
|
1014
|
-
|
|
1015
|
-
**Not supported for filtering:**
|
|
1016
|
-
- `t` — a Workbench artifact param, explicitly stripped.
|
|
1017
|
-
- Any filter with a `null` field name or `null` value is silently dropped.
|
|
1018
|
-
|
|
1019
|
-
**Supported sort fields (`sort=` query param, minVersion 264):**
|
|
1020
|
-
- The same flat mapping as filtering: `name`, `id`, `description`, `status`,
|
|
1021
|
-
`tickettype`, `priority`, plus any raw Salesforce `Case` field name.
|
|
1022
|
-
- Nested (dotted) 1:1-relationship sort paths, explicitly whitelisted:
|
|
1023
|
-
|
|
1024
|
-
| TMF dotted sort path | Salesforce path |
|
|
1025
|
-
|---|---|
|
|
1026
|
-
| `relatedEntity.name` | `Asset.Name` |
|
|
1027
|
-
| `troubleTicketRelationship.id` | `Parent.CaseNumber` |
|
|
1028
|
-
| `troubleTicketRelationship.name` | `Parent.Subject` |
|
|
1029
|
-
|
|
1030
|
-
**Not supported for sorting:** multi-record/child connections —
|
|
1031
|
-
`note`, `attachment`, `statusChangeHistory` — since these are not sortable via
|
|
1032
|
-
the parent list.
|
|
1033
|
-
|
|
1034
|
-
### Full TMF621 field mapping reference — use this when writing extensibility hooks
|
|
1035
|
-
|
|
1036
|
-
Primary backing SObject is `Case` (+ `CaseTroubleTicket` for `severity`). Use
|
|
1037
|
-
these mappings inside `transformRequest`/`customiseGraphQLQuery`/`handlePostOperation`
|
|
1038
|
-
when you need to translate between a TMF field/sub-resource name and the
|
|
1039
|
-
underlying Salesforce field, or vice versa.
|
|
1040
|
-
|
|
1041
|
-
**1. Flat TMF name → Salesforce field (filtering, sorting, `fields=`):**
|
|
1042
|
-
|
|
1043
|
-
| TMF field | Salesforce field |
|
|
1044
|
-
|---|---|
|
|
1045
|
-
| `name` | `Subject` |
|
|
1046
|
-
| `id` | `CaseNumber` |
|
|
1047
|
-
| `description` | `Description` |
|
|
1048
|
-
| `status` | `Status` |
|
|
1049
|
-
| `tickettype` | `Type` |
|
|
1050
|
-
| `priority` | `Priority` |
|
|
1051
|
-
|
|
1052
|
-
**2. `severity` — special case, not in the flat mapping table (table 1):**
|
|
1053
|
-
|
|
1054
|
-
| TMF field | Salesforce entity.field |
|
|
1055
|
-
|---|---|
|
|
1056
|
-
| `severity` | `CaseTroubleTicket.Severity` — fetched via an auxiliary GraphQL query, not from `Case` directly |
|
|
1057
|
-
|
|
1058
|
-
**3. TMF sub-resource name → identifier → backing relationship:**
|
|
1059
|
-
|
|
1060
|
-
| TMF sub-resource | Identifier | Backing relationship |
|
|
1061
|
-
|---|---|---|
|
|
1062
|
-
| `channel` | `channel` | `Case.Origin` (scalar) |
|
|
1063
|
-
| `attachment` | `attachment` | `Case.ContentDocumentLinks` |
|
|
1064
|
-
| `note` | `note` | `Case.CaseComments` |
|
|
1065
|
-
| `relatedEntity` | `relatedEntity` | `Asset` reference |
|
|
1066
|
-
| `relatedParty` | `relatedParty` | Account + Contact references (special-cased) |
|
|
1067
|
-
| `troubleTicketRelationship` | `troubleTicketRelationship` | `Case.Parent` |
|
|
1068
|
-
| `externalIdentifier` | `externalIdentifier` | `CaseTroubleTicket` (auxiliary query) |
|
|
1069
|
-
| `statusChangeHistory` | `statusChangeHistory` | `Case.Histories` |
|
|
1070
|
-
|
|
1071
|
-
**4. Dotted sort path → Salesforce relationship path:**
|
|
1072
|
-
|
|
1073
|
-
| TMF dotted path | Salesforce path |
|
|
1074
|
-
|---|---|
|
|
1075
|
-
| `relatedentity.name` | `Asset.Name` |
|
|
1076
|
-
| `troubleticketrelationship.id` | `Parent.CaseNumber` |
|
|
1077
|
-
| `troubleticketrelationship.name` | `Parent.Subject` |
|
|
1078
|
-
|
|
1079
|
-
**5. Salesforce fields returned when the caller omits `fields=`:**
|
|
1080
|
-
|
|
1081
|
-
`Subject`, `Id`, `Description`, `Status`, `Type`, `Priority`, `Origin`,
|
|
1082
|
-
`AccountId`, `ContactId`, `CaseNumber`, `CreatedDate`, `LastModifiedDate`,
|
|
1083
|
-
`ClosedDate`, `ParentId`, `AssetId`.
|
|
1084
|
-
|
|
1085
|
-
Any raw Salesforce `Case` field not listed in table 1 also works for
|
|
1086
|
-
filtering/sorting/`fields=` — these maps are TMF-friendly aliases, not a
|
|
1087
|
-
restriction (§2.3).
|
|
1088
|
-
|
|
1089
|
-
## 4.6 PATCH update semantics — TMF621
|
|
1090
|
-
|
|
1091
|
-
PATCH is partial: **a field omitted from the request body is left unchanged.**
|
|
1092
|
-
Beyond that, per-field behavior differs:
|
|
1093
|
-
|
|
1094
|
-
| TMF field | Salesforce target | PATCH behavior |
|
|
1095
|
-
|---|---|---|
|
|
1096
|
-
| `name`, `description`, `status`, `ticketType`, `priority` | `Case.Subject`/`Description`/`Status`/`Type`/`Priority` | Set to the new value if present. |
|
|
1097
|
-
| `channel` | `Case.Origin` | Set to `channel.name` if `channel` present and `name` non-empty. |
|
|
1098
|
-
| `relatedParty` | `Case.AccountId`, `Case.ContactId` | **Replace.** First Account in list → `AccountId`, first Contact → `ContactId`. Empty list `[]` → **clears both to null**. Omitted → no change. |
|
|
1099
|
-
| `relatedEntity` | `Case.AssetId` | **Replace.** First Asset → `AssetId`. Empty list `[]` → **clears to null**. Omitted → no change. |
|
|
1100
|
-
| `troubleTicketRelationship` | `Case.ParentId` | First item `id` → `ParentId` when list is non-empty. |
|
|
1101
|
-
| `note` | `CaseComment` | **Append-only.** Each entry with non-empty `text` creates a new `CaseComment`; existing notes are never removed. Notes are always created via SOQL, not GraphQL. |
|
|
1102
|
-
| `attachment` | `ContentVersion` + `ContentDocumentLink` | **Append-only.** Each entry with non-empty `url` creates a new attachment; existing attachments are never removed. |
|
|
1103
|
-
| `severity`, `externalIdentifier`, `requestedResolutionDate`, `expectedResolutionDate` | `CaseTroubleTicket` extension | **Update-or-create.** If a `CaseTroubleTicket` already exists for the Case → update it; otherwise create one. Dates are converted to ISO-8601 DateTime. |
|
|
1104
|
-
|
|
1105
|
-
The `{id}` in the PATCH URL is the `CaseNumber`, resolved to the Salesforce Case
|
|
1106
|
-
Id before the mutation runs (§4.1).
|
|
1107
|
-
|
|
1108
|
-
---
|
|
1109
|
-
|
|
1110
|
-
# Part 5 — TMF629 Customer Management (API-specific)
|
|
1111
|
-
|
|
1112
|
-
## 5.1 Endpoint reference (complete)
|
|
1113
|
-
|
|
1114
|
-
TMF resource version segment: **`v4`** — this is the only version wired to the current extensible handler path for every verb below. (A `v6` segment exists in the handler routing table for GET, but only keyed to the deprecated, non-extensible legacy resource capped at Salesforce API version 258, not to the current extensible resource — it is not covered by any functional test and should not be used. Always use `v4`.)
|
|
1115
|
-
|
|
1116
|
-
| # | Method | Path | Purpose | Query / body params |
|
|
1117
|
-
|---|---|---|---|---|
|
|
1118
|
-
| 1 | POST | `/connect/comms/customermanagement/v4/customer` | Create a customer (creates an `Account`, and optionally a related `Contact` as `engagedParty`) | Body = Customer JSON (§5.2) |
|
|
1119
|
-
| 2 | GET | `/connect/comms/customermanagement/v4/customer` | List customers (paginated) | `offset`, `pageLimit`, `fields`, `sort`, `pageinfo`, plus dynamic filter query params. Pagination bounds/defaults: §2.2. |
|
|
1120
|
-
| 3 | GET | `/connect/comms/customermanagement/v4/customer/{id}` | Retrieve a single customer by `Account` Id | `fields` |
|
|
1121
|
-
| 4 | PATCH | `/connect/comms/customermanagement/v4/customer/{id}` | Partially update a customer | Body = partial Customer JSON |
|
|
1122
|
-
| 5 | DELETE | `/connect/comms/customermanagement/v4/customer/{id}` | Delete a customer (`Account`) | none |
|
|
1123
|
-
| 6 | GET | `/connect/comms/customermanagement/v4/customer/{id}/{subResource}` | Paginate a child collection (TMF630 §4.6 nested-resource pattern — TMF629 borrows TMF630's generic customer sub-resource convention) | `offset`, `pageLimit`, `pageinfo`; `{subResource}` = one of the 3 values in §5.3 |
|
|
1124
|
-
|
|
1125
|
-
(Every request always runs through the extensible pipeline — see §2.1.)
|
|
1126
|
-
|
|
1127
|
-
## 5.2 Request/response payload shape (Customer)
|
|
1128
|
-
|
|
1129
|
-
**Request body fields:**
|
|
1130
|
-
|
|
1131
|
-
| Field | Type | Notes |
|
|
1132
|
-
|---|---|---|
|
|
1133
|
-
| `name` | string | Customer/Account name |
|
|
1134
|
-
| `status` | string | Account status |
|
|
1135
|
-
| `type` | string | Customer type |
|
|
1136
|
-
| `engagedParty` | object: `{ "referredType": "Contact"\|"Individual", "name": "...", "id": null }` | The primary contact person. **Mandatory on POST** (POST requires both `name` and `engagedParty`); the object itself must carry a `name` or an `id`. On POST **without** `id`, a new `Contact` is created from `name` → `Contact.LastName`; on POST **with** `id`, the existing `Contact` is linked/updated. |
|
|
1137
|
-
| `contactMedium` | wrapper: `{ "list": [ { "mediumType": "...", "characteristic": { ... } } ] }` | Phone/email/fax contact points. **Only `Email`, `Phone`, `Fax` mediumTypes are honored** — any other value is silently ignored. If the **same mediumType appears more than once**, only one value persists (backed by a map keyed on the Salesforce field — last write wins). Each entry needs a non-blank `mediumType` and `characteristic` or the request fails (`contactMediumValidation`). |
|
|
1138
|
-
| `account` | wrapper: `{ "list": [ { "id": "...", "name": "..." } ] }` | Related/child account references. Each entry needs **both `id` and `name`** (`accountValidation`), and every referenced account **must already exist** — matched via `Id CONTAINS` + `Name CONTAINS` against existing `Account`s; any that don't match fail the request with `ACCOUNT_NOT_PRESENT`. |
|
|
1139
|
-
|
|
1140
|
-
**Example POST body:**
|
|
1141
|
-
|
|
1142
|
-
```json
|
|
1143
|
-
{
|
|
1144
|
-
"name": "Sample",
|
|
1145
|
-
"type": "Enterprise",
|
|
1146
|
-
"engagedParty": {
|
|
1147
|
-
"referredType": "Contact",
|
|
1148
|
-
"name": "Sean Forbes",
|
|
1149
|
-
"id": null
|
|
1150
|
-
}
|
|
1151
|
-
}
|
|
1152
|
-
```
|
|
1153
|
-
|
|
1154
|
-
**Response body fields**: `id`, `href`,
|
|
1155
|
-
`type`, `name`, `agreement` (list of related `Contract`s), `account` (list of
|
|
1156
|
-
related child `Account`s), `engagedParty` (single Account-Contact relation
|
|
1157
|
-
object), `contactMedium` (list), `updatedPayload` (present only if Apex
|
|
1158
|
-
extensibility overwrote the response — see §3.3). The `engagedParty.role` in the
|
|
1159
|
-
response defaults to the literal `"Individual"` when there is no
|
|
1160
|
-
`AccountContactRelation` role to draw from.
|
|
1161
|
-
|
|
1162
|
-
## 5.3 Sub-resource pagination (endpoint #6)
|
|
1163
|
-
|
|
1164
|
-
`GET /connect/comms/customermanagement/v4/customer/{id}/{subResource}`. Built-in values:
|
|
1165
|
-
|
|
1166
|
-
| `{subResource}` value | Backing relationship | Maps to |
|
|
1167
|
-
|---|---|---|
|
|
1168
|
-
| `account` | `Account.ChildAccounts` | Child `Account` |
|
|
1169
|
-
| `engagedparty` (alias: `contact`) | `Account.Contacts` | `Contact` |
|
|
1170
|
-
| `agreement` | `Account.Contracts` | `Contract` |
|
|
1171
|
-
|
|
1172
|
-
Same response shape as the list endpoint. As with TMF621, Apex extensibility
|
|
1173
|
-
can register additional custom sub-resource names at runtime (§3.7) — for
|
|
1174
|
-
example, exposing `Account.Opportunities` as a brand-new `opportunities`
|
|
1175
|
-
sub-resource this way, with zero Java changes.
|
|
1176
|
-
|
|
1177
|
-
## 5.4 API routes — TMF629, zero customization
|
|
1178
|
-
|
|
1179
|
-
Call these directly against `https://<your-instance>.my.salesforce.com/services/data/v<API_VERSION>.0<path>` per Part 1. No Apex required for any of these.
|
|
1180
|
-
|
|
1181
|
-
| Purpose | Method | Path | Body |
|
|
1182
|
-
|---|---|---|---|
|
|
1183
|
-
| List | GET | `/connect/comms/customermanagement/v4/customer?offset=0&pageLimit=10&pageinfo=true` | — |
|
|
1184
|
-
| Create | POST | `/connect/comms/customermanagement/v4/customer` | `{"name":"Sample","type":"Enterprise","engagedParty":{"referredType":"Contact","name":"Sean Forbes","id":null}}` |
|
|
1185
|
-
| Retrieve by id | GET | `/connect/comms/customermanagement/v4/customer/001xx000003GYrsAAG` | — |
|
|
1186
|
-
| Partial update | PATCH | `/connect/comms/customermanagement/v4/customer/001xx000003GYrsAAG` | `{"status":"Active"}` |
|
|
1187
|
-
| Delete | DELETE | `/connect/comms/customermanagement/v4/customer/001xx000003GYrsAAG` | — |
|
|
1188
|
-
| Sub-resource: paginate related contacts (engagedParty) | GET | `/connect/comms/customermanagement/v4/customer/001xx000003GYrsAAG/engagedparty?offset=0&pageLimit=5` | — |
|
|
1189
|
-
|
|
1190
|
-
## 5.5 Filtering and sorting fields — TMF629
|
|
1191
|
-
|
|
1192
|
-
Same mechanism as TMF621 (§2.3 / §4.5): filtering is not a fixed allow-list.
|
|
1193
|
-
TMF629 uses the same filter field-name pass-through as TMF621 — the underlying
|
|
1194
|
-
filter logic drops the field name straight into the `where` clause with no
|
|
1195
|
-
allow-list check (only `t`/null skipped). The table below is the named TMF-field
|
|
1196
|
-
mapping (TMF name → Salesforce field); any other raw Salesforce `Account` field
|
|
1197
|
-
name also works for filtering/sorting.
|
|
1198
|
-
|
|
1199
|
-
**If a user wants to filter by a field not in the table below, follow the
|
|
1200
|
-
decision flow in §2.3.1** (confirm it's on `Account` → raw param, no
|
|
1201
|
-
extensibility; custom name/related object → extensibility with a mapping; not on
|
|
1202
|
-
the entity → say it can't be done). Same empty-result gotcha as §2.3: a filter on
|
|
1203
|
-
a non-existent field returns an **empty list, not an error**.
|
|
1204
|
-
|
|
1205
|
-
**Supported filter fields (TMF name → Salesforce field):**
|
|
1206
|
-
|
|
1207
|
-
| TMF name | Salesforce field |
|
|
1208
|
-
|---|---|
|
|
1209
|
-
| `name` | `Name` |
|
|
1210
|
-
| `id` | `Id` |
|
|
1211
|
-
|
|
1212
|
-
Plus any raw Salesforce `Account` field name passed directly as a query param.
|
|
1213
|
-
|
|
1214
|
-
**Not supported for filtering:**
|
|
1215
|
-
- `t` — same Workbench artifact param, explicitly stripped.
|
|
1216
|
-
- Any filter with a `null` field name or `null` value is silently dropped.
|
|
1217
|
-
|
|
1218
|
-
**Supported sort fields (`sort=` query param, minVersion 264):**
|
|
1219
|
-
- `name`, `id`, plus any raw Salesforce `Account` field name.
|
|
1220
|
-
- One nested (dotted) sort path is whitelisted:
|
|
1221
|
-
|
|
1222
|
-
| TMF dotted sort path | Salesforce path |
|
|
1223
|
-
|---|---|
|
|
1224
|
-
| `parentAccount.name` | `Parent.Name` |
|
|
1225
|
-
|
|
1226
|
-
**Not supported for sorting:** multi-record sub-resources — `account` (child
|
|
1227
|
-
accounts), `agreement` (contracts), `contactMedium`, `engagedParty` — these are
|
|
1228
|
-
GraphQL connections and, like TMF621's `note`/`attachment`/`statusChangeHistory`,
|
|
1229
|
-
are not sortable via the parent list.
|
|
1230
|
-
|
|
1231
|
-
### Full TMF629 field mapping reference — use this when writing extensibility hooks
|
|
1232
|
-
|
|
1233
|
-
Primary backing SObject is `Account`. Use these mappings inside
|
|
1234
|
-
`transformRequest`/`customiseGraphQLQuery`/`handlePostOperation` when you need to
|
|
1235
|
-
translate between a TMF field/sub-resource name and the underlying Salesforce
|
|
1236
|
-
field, or vice versa.
|
|
1237
|
-
|
|
1238
|
-
**1. Flat TMF name → Salesforce field (filtering, sorting, `fields=`):**
|
|
1239
|
-
|
|
1240
|
-
| TMF field | Salesforce field |
|
|
1241
|
-
|---|---|
|
|
1242
|
-
| `name` | `Name` |
|
|
1243
|
-
| `id` | `Id` |
|
|
1244
|
-
|
|
1245
|
-
**2. TMF sub-resource name → identifier:**
|
|
1246
|
-
|
|
1247
|
-
| TMF sub-resource | Identifier |
|
|
1248
|
-
|---|---|
|
|
1249
|
-
| `account` | `account` |
|
|
1250
|
-
| `agreement` | `agreement` |
|
|
1251
|
-
| `contactmedium` | `contactmedium` |
|
|
1252
|
-
| `engagedparty` | `engagedparty` |
|
|
1253
|
-
|
|
1254
|
-
**3. Dotted sort path → Salesforce relationship path:**
|
|
1255
|
-
|
|
1256
|
-
| TMF dotted path | Salesforce path |
|
|
1257
|
-
|---|---|
|
|
1258
|
-
| `parentaccount.name` | `Parent.Name` |
|
|
1259
|
-
|
|
1260
|
-
**4. Salesforce fields returned when caller omits `fields=`:**
|
|
1261
|
-
|
|
1262
|
-
`Name`, `Id`, `ParentId`.
|
|
1263
|
-
|
|
1264
|
-
**5. TMF sub-resource → GraphQL relationship → backing SObject → parent lookup field, used for `GET .../{id}/{subResource}`:**
|
|
1265
|
-
|
|
1266
|
-
| TMF sub-resource | GraphQL relationship (alias) | Backing SObject | Parent lookup field |
|
|
1267
|
-
|---|---|---|---|
|
|
1268
|
-
| `account` | `ChildAccounts` (`childAccounts`) | `Account` | `ParentId` |
|
|
1269
|
-
| `engagedparty` (alias: `contact`) | `Contacts` (`engagedParty`) | `Contact` | `AccountId` |
|
|
1270
|
-
| `agreement` | `Contracts` (`agreements`) | `Contract` | `AccountId` |
|
|
1271
|
-
|
|
1272
|
-
**6. Parent-side relationship node (feeds the `account` array field alongside `ChildAccounts`):**
|
|
1273
|
-
|
|
1274
|
-
| GraphQL relationship (alias) | Backing SObject | Purpose |
|
|
1275
|
-
|---|---|---|
|
|
1276
|
-
| `Parent` (`parentAccount`) | `Account` | Direct (non-connection) relationship; parent + child records both populate the TMF `account` array field |
|
|
1277
|
-
|
|
1278
|
-
**7. `contactmedium` and `engagedparty` share the same underlying GraphQL node:**
|
|
1279
|
-
|
|
1280
|
-
Both pull from the same `Contacts` relationship (alias `engagedParty`), just
|
|
1281
|
-
shaped differently on the way out:
|
|
1282
|
-
- If `contactmedium` was requested → contact records convert into the TMF
|
|
1283
|
-
`contactMedium` field.
|
|
1284
|
-
- If `engagedparty` was requested → the first contact record converts into the
|
|
1285
|
-
TMF `engagedParty` field.
|
|
1286
|
-
- Both can be requested together — they populate independently from the same
|
|
1287
|
-
underlying `Contact` rows.
|
|
1288
|
-
|
|
1289
|
-
**8. `contactMedium.mediumType` → Salesforce field (used when constructing the mutation payload on POST):**
|
|
1290
|
-
|
|
1291
|
-
| TMF `mediumType` | Salesforce field |
|
|
1292
|
-
|---|---|
|
|
1293
|
-
| `PHONE` | `Phone` |
|
|
1294
|
-
| `EMAIL` | `Email` |
|
|
1295
|
-
| `FAX` | `Fax` |
|
|
1296
|
-
|
|
1297
|
-
**9. `account` wrapper (POST request body) — construction/match logic:**
|
|
1298
|
-
|
|
1299
|
-
| TMF field | Salesforce entity | Match logic |
|
|
1300
|
-
|---|---|---|
|
|
1301
|
-
| `account.list[].id` / `.name` | `Account` | Matched via `Id CONTAINS` + `Name CONTAINS` filters against existing `Account` records — every referenced account must already exist or the request fails with `ACCOUNT_NOT_PRESENT` |
|
|
1302
|
-
|
|
1303
|
-
Any raw Salesforce `Account` field not listed in table 1 also works for
|
|
1304
|
-
filtering/sorting/`fields=` — these maps are TMF-friendly aliases, not a
|
|
1305
|
-
restriction (§2.3).
|
|
1306
|
-
|
|
1307
|
-
**Sub-resource pagination — no `sort=`/`fields=` support:** `GET .../{id}/{subResource}`
|
|
1308
|
-
only accepts `offset`, `pageLimit`, `pageinfo` — there is no caller-facing sort
|
|
1309
|
-
or field-selection parameter on this endpoint. Default order is unsorted/Id-order unless an Apex
|
|
1310
|
-
`customiseGraphQLQuery` hook injects a `where`/`orderBy` argument onto the
|
|
1311
|
-
specific sub-resource's GraphQL node (matched by alias, e.g. `childAccounts`,
|
|
1312
|
-
`agreements`, `engagedParty`) — this is the *only* way to sort or filter a
|
|
1313
|
-
sub-resource collection.
|
|
1314
|
-
|
|
1315
|
-
## 5.6 PATCH update semantics — TMF629
|
|
1316
|
-
|
|
1317
|
-
PATCH is partial: a field omitted from the body is left unchanged. Patchable
|
|
1318
|
-
fields and their behavior:
|
|
1319
|
-
|
|
1320
|
-
| TMF field | Salesforce target | PATCH behavior |
|
|
1321
|
-
|---|---|---|
|
|
1322
|
-
| `name` | `Account.Name` | Set to the new value if present. |
|
|
1323
|
-
| `account` | `Account` (child links) | Each entry needs `id`+`name` and must match an existing Account (same `CONTAINS` rule / `ACCOUNT_NOT_PRESENT` failure as POST). |
|
|
1324
|
-
| `contactMedium` | `Contact.Email`/`Phone`/`Fax` | Applied to the engaged-party contact. Only `Email`/`Phone`/`Fax` honored; a `characteristic: {}` for a mediumType effectively clears that medium. |
|
|
1325
|
-
| `engagedParty` | `Contact` link | **Supported on PATCH**, but **`engagedParty.id` is required**. The currently-linked contact(s) are delinked when the new `id` differs, then the contact identified by `id` is linked/updated. |
|
|
1326
|
-
|
|
1327
|
-
**Note:** `engagedParty` **is supported on PATCH** as described above, despite
|
|
1328
|
-
older documentation that may suggest otherwise.
|
|
1329
|
-
|
|
1330
|
-
---
|
|
1331
|
-
|
|
1332
|
-
# Part 6 — End-to-end execution checklist
|
|
1333
|
-
|
|
1334
|
-
1. **Confirm you hold a valid OAuth/session bearer token for the target org.** Check that the token is live and not expired. If you already have one, skip step 2 and go straight to step 3.
|
|
1335
|
-
2. **If not, follow the bundled reference sample `external-client-app-setup` in the skill's references bundle, per §1.2.** In short: first list the org's existing External Client Apps via the Metadata API and reuse a suitable one; only create a new app if none exists — using the defaults unless the user asks to customize, applying the default configuration incl. the Client Credentials run-as user, having the user reveal and store the Consumer Key/Secret in the approved secret manager, then obtaining an access token via a standard OAuth 2.0 flow (web-server/user-agent for interactive use, Client Credentials with the run-as user, or JWT bearer via `POST /services/oauth2/token` for headless/CI). Do not proceed to step 3 until you hold a live token for the target org.
|
|
1336
|
-
3. Confirm your org has `CommsCloud` or `CommsCloudTMFAPI` org permission enabled (ask a Salesforce admin, or check Setup → Feature Settings if you have access).
|
|
1337
|
-
4. **Discover the org's latest supported Salesforce API version.** Call `GET https://<your-instance>.my.salesforce.com/services/data/` with the `Bearer` token and take the highest `version` from the response; use it as the `v<API_VERSION>.0` segment in the base URL (per §1.3). A `200` confirms auth and the correct version to use; never hard-code a version the org may not report.
|
|
1338
|
-
5. Pick your TMF resource version segment: TMF621 → `v5`; TMF629 → `v4` (this is separate from the Salesforce API version from step 4).
|
|
1339
|
-
6. **Verify the endpoint is actually accessible in the org** before doing any real work: call the plain list/GET endpoint (§4.4 #1 or §5.4 #1) with `pageLimit=1` and no filters. A `200` with a (possibly empty) `recordList` confirms the org permission (§1.1), the access check, and FLS/sharing all line up. A `403`/`INSUFFICIENT_ACCESS` means the org permission (`CommsCloud`/`CommsCloudTMFAPI`) isn't enabled or the user lacks object access — stop and fix that before proceeding. A `404` means the wrong TMF version segment was used (double-check step 5).
|
|
1340
|
-
7. Call the endpoint route directly using the tables in §4.4/§5.4 — this works out of the box, zero Apex needed.
|
|
1341
|
-
8. **Only if you explicitly want custom behavior** (extra fields, filtering, validation, response reshaping) — per the mandatory gate at the top of this skill: **first confirm the org's latest supported API version (step 4) is `67.0` or above — extensibility does not work below `67.0`; if the org is below it, stop and tell the user rather than writing any Apex.** Then confirm you actually want an extensibility scenario, pick the one interface from §3.1 matching your verb+API, write one Apex class implementing every method on it (no-op the ones you don't need per §3.2's "No-op return" column), show it and get it confirmed, deploy it per §3.11, and call the same endpoint again — your customization takes effect automatically with no further wiring.
|
|
1342
|
-
|
|
1343
|
-
<!-- skill-validate: ignore-start -->
|
|
1344
|
-
<!-- codey:operations start -->
|
|
1345
|
-
## Operations Reference
|
|
1346
|
-
|
|
1347
|
-
Operations this skill uses — routing and dependency reference.
|
|
1348
|
-
|
|
1349
|
-
| Operation | Purpose | Status | Call | Depends on |
|
|
1350
|
-
|-----------|---------|--------|------|------------|
|
|
1351
|
-
| `tmf-list-troubletickets` | read | — | `GET /services/data/v{V}/connect/comms/troubleticket/v5/troubleticket` | — |
|
|
1352
|
-
| `tmf-get-troubleticket` | read | — | `GET /services/data/v{V}/connect/comms/troubleticket/v5/troubleticket/{caseNumber}` | `tmf-list-troubletickets` |
|
|
1353
|
-
| `tmf-get-troubleticket-subresource` | read | — | `GET /services/data/v{V}/connect/comms/troubleticket/v5/troubleticket/{caseId}/{subresource}` | `tmf-resolve-case-id` |
|
|
1354
|
-
| `tmf-resolve-case-id` | read | — | `POST /services/data/v{V}/graphql` | — |
|
|
1355
|
-
| `tmf-create-troubleticket` | write | — | `POST /services/data/v{V}/connect/comms/troubleticket/v5/troubleticket` | — |
|
|
1356
|
-
| `tmf-update-troubleticket` | write | — | `PATCH /services/data/v{V}/connect/comms/troubleticket/v5/troubleticket/{caseNumber}` | `tmf-get-troubleticket` |
|
|
1357
|
-
| `tmf-delete-troubleticket` | write | — | `DELETE /services/data/v{V}/connect/comms/troubleticket/v5/troubleticket/{caseNumber}` | — |
|
|
1358
|
-
| `cust-list-customers` | read | — | `GET /services/data/v{V}/connect/comms/customermanagement/v4/customer` | — |
|
|
1359
|
-
| `cust-create-customer` | write | — | `POST /services/data/v{V}/connect/comms/customermanagement/v4/customer` | — |
|
|
1360
|
-
| `cust-get-customer` | read | — | `GET /services/data/v{V}/connect/comms/customermanagement/v4/customer/{accountId}` | `cust-list-customers` |
|
|
1361
|
-
| `cust-patch-customer` | write | — | `PATCH /services/data/v{V}/connect/comms/customermanagement/v4/customer/{accountId}` | `cust-get-customer` |
|
|
1362
|
-
| `cust-get-customer-subresource` | read | — | `GET /services/data/v{V}/connect/comms/customermanagement/v4/customer/{accountId}/{subresource}` | `cust-list-customers` |
|
|
1363
|
-
| `cust-delete-customer` | write | — | `DELETE /services/data/v{V}/connect/comms/customermanagement/v4/customer/{accountId}` | — |
|
|
1364
|
-
| `apex-deploy-toolingapi` | write | — | `POST /services/data/v{V}/tooling/sobjects/ApexClass` | — |
|
|
1365
|
-
| `apex-deploy-metadataapi` | write | — | `/headless/metadata` | — |
|
|
1366
|
-
| `apex-conflict-check` | — | — | — | — |
|
|
1367
|
-
<!-- codey:operations end -->
|
|
1368
|
-
<!-- skill-validate: ignore-end -->
|