The ICustomerManagementDELETE interface provides extensibility for DELETE operations through Apex-based validations, mutation-payload adjustments, and post-operation processing. Users can enforce deletion policies, apply soft-delete or metadata logic, and customize final responses without impacting TMF-compliant delete behavior.
These hooks are not used for the Customer Management API. If implemented, the method may be invoked, but its return values are ignored.
configureDefaultValidations
customiseGraphQLQuery
Note
Deletion Lifecycle Use Cases and Hook Mapping
This table lists common use cases and the hooks required for the DELETE operation.
Use Case
Hook(s)
Description
Example Scenarios
Benefit
Enforce Deletion Rules
applyCustomValidations
Validates whether a record is eligible for deletion by checking dependencies, business constraints, and user permissions. Prevents unsafe deletions that may violate data integrity or operational rules.
• Block deletion if active child records exist• Enforce that only admins can delete high-value accounts• Prevent deletion when linked to open cases or agreements
Prevents accidental deletion of critical records and preserves data integrity
Maintain Audit Trail
customiseMutationPayload, handlePostOperation
Enriches the deletion request with audit metadata and records post-delete events, enabling traceability for compliance and regulatory review. Supports soft-delete or archival strategies.
• Capture who deleted the record and timestamp• Add soft-delete flags before actual deletion• Trigger audit-event logging after deletion
Provides a complete audit trail for compliance and monitoring
Support External Identifiers
resolveUniqueIdentifiers
Allows records to be deleted using external IDs instead of Salesforce IDs. Enables seamless integration with external or legacy customer systems.
• Delete by external CRM customer ID• Resolve telecom subscriber ID to internal account before deletion• Accept partner-system identifier for record lookup
Enables interoperability with external platforms and simplifies integrations
Clean Up Related Data
handlePostOperation
Performs cascading cleanup of related or dependent data after a record has been deleted. Ensures the system remains consistent and free of orphaned or stale records.
• Archive or remove associated contact mediums• Delete orphaned child records after parent deletion• Trigger asynchronous cleanup workflow for related data
Maintains data consistency and avoids accumulation of stale or orphaned records
transformRequest
This hook transforms the request context before processing any operation. It is invoked early in the request lifecycle, allowing implementers to adjust the context for subsequent extensibility hooks.
1public Map<String, Object> applyCustomValidations(Map<String, Object> context) {2 // Input context:3 // {4 // api: 'CustomerManagement',5 // version: '4.0',6 // customerId: '001xx000003DHP'7 // }89 String customerId = (String) context.get('customerId');10 Map<String, Object> validationResult = new Map<String, Object>();1112 try {13 // Check if customer has active contracts14 List<Contract> activeContracts = [15 SELECT Id FROM Contract16 WHERE AccountId = :customerId17 AND Status = 'Active'18 LIMIT 119 ];2021 if (!activeContracts.isEmpty()) {22 validationResult.put('validationStatus', 'FAIL');23 validationResult.put('validationMessage', 'Cannot delete customer with active contracts');24 validationResult.put('validationDetails', new Map<String, Object>{25 'reason' => 'ACTIVE_CONTRACTS_EXIST',26 'contractCount' => activeContracts.size()27 });28 return validationResult;29 }3031 // Check if customer has open opportunities32 List<Opportunity> openOpportunities = [33 SELECT Id FROM Opportunity34 WHERE AccountId = :customerId35 AND IsClosed = false36 LIMIT 137 ];3839 if (!openOpportunities.isEmpty()) {40 validationResult.put('validationStatus', 'FAIL');41 validationResult.put('validationMessage', 'Cannot delete customer with open opportunities');42 validationResult.put('validationDetails', new Map<String, Object>{43 'reason' => 'OPEN_OPPORTUNITIES_EXIST'44 });45 return validationResult;46 }4748 // Check user permissions49 if (!UserInfo.getProfileId().equals('00e000000000001')) { // Admin profile50 validationResult.put('validationStatus', 'FAIL');51 validationResult.put('validationMessage', 'User does not have permission to delete customers');52 validationResult.put('validationDetails', new Map<String, Object>{53 'requiredRole' => 'Administrator'54 });55 return validationResult;56 }5758 // PASS: All validations passed59 validationResult.put('validationStatus', 'PASS');60 validationResult.put('validationMessage', 'Customer deletion validation passed');6162 } catch (Exception e) {63 // FAIL: Error during validation64 validationResult.put('validationStatus', 'FAIL');65 validationResult.put('validationMessage', 'Validation error: ' + e.getMessage());66 }6768 return validationResult;69 }
customiseMutationPayload
This hook modifies the mutation payload before deleting a customer record. Use this to add deletion metadata, set soft-delete flags, or apply business logic transformations.
Here’s a complete sample Apex implementation using all supported hooks.
1/**2 * Complete Customer Management DELETE API Extension3 * Demonstrates all applicable lifecycle hooks with business logic4 */5public class CustomerManagementDELETEExtension implements comms_apex_ext.ICustomerManagementDELETE {67 /**8 * Hook 1: Apply custom validations9 */10 public Map<String, Object> applyCustomValidations(Map<String, Object> context) {11 String customerId = (String) context.get('customerId');12 Map<String, Object> validationResult = new Map<String, Object>();1314 try {15 // Check for active contracts16 List<Contract> activeContracts = [17 SELECT Id FROM Contract18 WHERE AccountId = :customerId AND Status = 'Active' LIMIT 119 ];2021 if (!activeContracts.isEmpty()) {22 validationResult.put('validationStatus', 'FAIL');23 validationResult.put('validationMessage', 'Cannot delete customer with active contracts');24 return validationResult;25 }2627 validationResult.put('validationStatus', 'PASS');28 validationResult.put('validationMessage', 'Validation passed');2930 } catch (Exception e) {31 validationResult.put('validationStatus', 'FAIL');32 validationResult.put('validationMessage', 'Validation error: ' + e.getMessage());33 }3435 return validationResult;36 }3738 /**39 * Hook 2: Customize mutation payload40 */41 public Map<String, Object> customiseMutationPayload(42 Map<String, Object> request,43 Map<String, Object> context44 ) {45 return new Map<String, Object>{46 'nodes' => new List<Object>{47 new Map<String, Object>{48 'path' => 'unlinkCase',49 'insertGraphQlSnippet' => 'unlinkCase: CaseUpdate(input: { Id: "500xx000000bnecAAA" Case: { ContactId: null, AccountId: null } }) { Record { Id ContactId { value } AccountId { value } } }'50 },51 new Map<String, Object>{52 'path' => 'deleteCase',53 'insertGraphQlSnippet' => 'deleteCase: CaseDelete(input: { Id: "500xx000000bnecAAA" }) { Id }'54 }55 }56 };57 }5859 /**60 * Hook 3: Resolve unique identifiers61 */62 public Map<String, String> resolveUniqueIdentifiers(List<String> ids) {63 Map<String, String> resolvedIds = new Map<String, String>();6465 try {66 List<Account> accounts = [67 SELECT Id, ExternalId__c68 FROM Account69 WHERE ExternalId__c IN :ids70 ];7172 for (Account acc : accounts) {73 resolvedIds.put(acc.ExternalId__c, acc.Id);74 }7576 } catch (Exception e) {77 System.debug('Error resolving IDs: ' + e.getMessage());78 }7980 return resolvedIds;81 }8283 /**84 * Hook 4: Post-process response85 */86 public Map<String, Object> handlePostOperation(87 Map<String, Object> graphQLQueryResultAsMap,88 Map<String, Object> constructedTMFResponse,89 Map<String, Object> context90 ) {91 /*92 TODO Any post processing to be performed.93 */9495 return null;96 }9798 /**99 * NOT APPLICABLE: configureDefaultValidations is not used for Customer Management DELETE API100 */101 public Map<String, Boolean> configureDefaultValidations(102 Map<String, Boolean> defaultValidationConfiguration,103 Map<String, Object> context104 ) {105 return defaultValidationConfiguration;106 }107108 /**109 * NOT APPLICABLE: customiseGraphQLQuery is not used for Customer Management DELETE API110 */111 public Map<String, Object> customiseGraphQLQuery(Map<String, Object> graphQLAsMap, Map<String, Object> context) {112 return null;113 }114}
GraphQL Mutation - Delete Operations
Delete mutations remove records. The delete transformation supports inserting GraphQL snippets to perform related operations, such as unlinking relationships before deletion or creating audit logs.
The insertGraphQlSnippet instruction allows you to embed complete GraphQL operations within a mutation and serves as the primary mechanism for extending delete operations.
Delete Enhancements: Unlink Before Delete
Transformation Instructions (JSON):
1{2 "nodes": [3 {4 "path": "unlinkCase",5 "insertGraphQlSnippet": "unlinkCase: CaseUpdate(input: { Id: \"500xx000000bnecAAA\" Case: { ContactId: null, AccountId, null } }) { Record { Id ContactId { value } AccountId { value } } }"6 },7 {8 "path": "deleteCase",9 "insertGraphQlSnippet": "deleteCase: CaseDelete(input: { Id: \"500xx000000bnecAAA\" }) { Id }"10 }11 ]12}