---
schema_version: "1"
id: 3268a1a37dfd5fa1e1028dd2ad58809925d0e9f1e8f4283dc81229232eb58ae7
title: ICustomerManagementDELETE Apex Interface
collection: developer
version: current
locale: en-us
portal_url: https://docs.salesforce.com/developer/current/en-us/industries-integrations/comms/guides/Extensibility/ICustomerManagementDELETE.md
canonical_url: https://developer.salesforce.com/docs/industries/communications/guide/ICustomerManagementDELETE.html
source_site: developer.salesforce.com
content_type: documentation
content_hash: ac038a95a5bfa5479ecc7bd1316994b63da561d22d78d23ae67d6bd3d2fda0d9
products:
  - Communications Cloud TM Forum API
  - Industries Integrations
---
# ICustomerManagementDELETE Apex Interface

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.

This interface supports the following hooks.

- [transformRequest](#transformrequest)
- [applyCustomValidations](#applycustomvalidations)
- [customiseMutationPayload](#customisemutationpayload)
- [handlePostOperation](#handlepostoperation)

**note:** 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`

## 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** <div style="width:290px"></div>                                                                                                                                                           | **Example Scenarios** <div style="width:290px"></div>                                                                                                             | **Benefit** <div style="width:290px"></div>                                     |
| -------------------------------- | ------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------- |
| **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.

## Hook Method

`Map<String, Object> transformRequest(Map<String, Object> context)`

## Sample Apex Implementation

```
public Map<String, Object> transformRequest(Map<String, Object> context) {
       if (context == null) {
           return context;
       }

       Object idObj = context.get('id');
       if (idObj == null || !(idObj instanceof String)) {
           return context;
       }

       String idValue = (String)idObj;

       // Check if the ID looks like a Salesforce ID (starts with 001, 003, etc.)
       // If not, assume it's an AccountNumber and resolve it
       if (idValue.length() == 15 || idValue.length() == 18) {
           // Looks like a Salesforce ID, return context as-is
           return context;
       }

       // Query Account objects where AccountNumber matches the provided ID
       List<Account> accounts = [
           SELECT Id, AccountNumber
           FROM Account
           WHERE AccountNumber = :idValue
           LIMIT 1
       ];

       // If found, replace the ID in context with the Salesforce ID
       if (!accounts.isEmpty() && accounts[0].AccountNumber != null) {
           context.put('id', accounts[0].Id);
       }

       return context;
   }
```

## applyCustomValidations

This hook validates custom business logic before deleting customer record. If validation fails, rejects the request and returns an error response.

The handler processes return values as follows.

Success:

- Return a map with validationStatus set to any value other than "fail" (case-insensitive).
- The API request continues normally.
- Other fields in the map are logged but not used.

Failure:

- Return a map with validationStatus set to "fail" (case-insensitive).
- The API request is terminated immediately.
- Raise a ValidationException containing
  - message: value from validationMessage key (or "Validation failed" by default)
  - details: value from validationDetails key (optional)
- The client receives an HTTP 400 error response.

## Hook Method

`Map<String, Object> applyCustomValidations(Map<String, Object> context)`

## Sample Apex Implementation

```
public Map<String, Object> applyCustomValidations(Map<String, Object> context) {
        // Input context:
        // {
        //   api: 'CustomerManagement',
        //   version: '4.0',
        //   customerId: '001xx000003DHP'
        // }

        String customerId = (String) context.get('customerId');
        Map<String, Object> validationResult = new Map<String, Object>();

        try {
            // Check if customer has active contracts
            List<Contract> activeContracts = [
                SELECT Id FROM Contract
                WHERE AccountId = :customerId
                AND Status = 'Active'
                LIMIT 1
            ];

            if (!activeContracts.isEmpty()) {
                validationResult.put('validationStatus', 'FAIL');
                validationResult.put('validationMessage', 'Cannot delete customer with active contracts');
                validationResult.put('validationDetails', new Map<String, Object>{
                    'reason' => 'ACTIVE_CONTRACTS_EXIST',
                    'contractCount' => activeContracts.size()
                });
                return validationResult;
            }

            // Check if customer has open opportunities
            List<Opportunity> openOpportunities = [
                SELECT Id FROM Opportunity
                WHERE AccountId = :customerId
                AND IsClosed = false
                LIMIT 1
            ];

            if (!openOpportunities.isEmpty()) {
                validationResult.put('validationStatus', 'FAIL');
                validationResult.put('validationMessage', 'Cannot delete customer with open opportunities');
                validationResult.put('validationDetails', new Map<String, Object>{
                    'reason' => 'OPEN_OPPORTUNITIES_EXIST'
                });
                return validationResult;
            }

            // Check user permissions
            if (!UserInfo.getProfileId().equals('00e000000000001')) { // Admin profile
                validationResult.put('validationStatus', 'FAIL');
                validationResult.put('validationMessage', 'User does not have permission to delete customers');
                validationResult.put('validationDetails', new Map<String, Object>{
                    'requiredRole' => 'Administrator'
                });
                return validationResult;
            }

            // PASS: All validations passed
            validationResult.put('validationStatus', 'PASS');
            validationResult.put('validationMessage', 'Customer deletion validation passed');

        } catch (Exception e) {
            // FAIL: Error during validation
            validationResult.put('validationStatus', 'FAIL');
            validationResult.put('validationMessage', 'Validation error: ' + e.getMessage());
        }

        return validationResult;
    }

```

## 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.

## Hook Method

`Map<String, Object> customiseMutationPayload(Map<String, Object> request, Map<String, Object> context)`

## Sample Apex Implementation

```
public Map<String, Object> customiseMutationPayload(
        Map<String, Object> request,
        Map<String, Object> context
    ) {
        return new Map<String, Object>{
            'nodes' => new List<Object>{
                new Map<String, Object>{
                    'path' => 'unlinkCase',
                    'insertGraphQlSnippet' => 'unlinkCase: CaseUpdate(input: { Id: "500LT00000DmBZaYAN" Case: { ContactId: null, AccountId: null } }) { Record { Id ContactId { value } AccountId { value } } }'
                },
                new Map<String, Object>{
                    'path' => 'deleteCase',
                    'insertGraphQlSnippet' => 'deleteCase: CaseDelete(input: { Id: "500xx000000bnecAAA" }) { Id }'
                }
            }
        };
    }

```

## handlePostOperation

This hook post-processes and transforms the API response after data is deleted.

## Hook Method

`Map<String, Object> handlePostOperation(Map<String, Object> graphQLQueryResultAsMap, Map<String, Object> constructedTMFResponse, Map<String, Object> context)`

## Full Implementation Example

Here's a complete sample Apex implementation using all supported hooks.

```
/**
 * Complete Customer Management DELETE API Extension
 * Demonstrates all applicable lifecycle hooks with business logic
 */
public class CustomerManagementDELETEExtension implements comms_apex_ext.ICustomerManagementDELETE {

    /**
     * Hook 1: Apply custom validations
     */
    public Map<String, Object> applyCustomValidations(Map<String, Object> context) {
        String customerId = (String) context.get('customerId');
        Map<String, Object> validationResult = new Map<String, Object>();

        try {
            // Check for active contracts
            List<Contract> activeContracts = [
                SELECT Id FROM Contract
                WHERE AccountId = :customerId AND Status = 'Active' LIMIT 1
            ];

            if (!activeContracts.isEmpty()) {
                validationResult.put('validationStatus', 'FAIL');
                validationResult.put('validationMessage', 'Cannot delete customer with active contracts');
                return validationResult;
            }

            validationResult.put('validationStatus', 'PASS');
            validationResult.put('validationMessage', 'Validation passed');

        } catch (Exception e) {
            validationResult.put('validationStatus', 'FAIL');
            validationResult.put('validationMessage', 'Validation error: ' + e.getMessage());
        }

        return validationResult;
    }

    /**
     * Hook 2: Customize mutation payload
     */
    public Map<String, Object> customiseMutationPayload(
        Map<String, Object> request,
        Map<String, Object> context
    ) {
        return new Map<String, Object>{
            'nodes' => new List<Object>{
                new Map<String, Object>{
                    'path' => 'unlinkCase',
                    'insertGraphQlSnippet' => 'unlinkCase: CaseUpdate(input: { Id: "500xx000000bnecAAA" Case: { ContactId: null, AccountId: null } }) { Record { Id ContactId { value } AccountId { value } } }'
                },
                new Map<String, Object>{
                    'path' => 'deleteCase',
                    'insertGraphQlSnippet' => 'deleteCase: CaseDelete(input: { Id: "500xx000000bnecAAA" }) { Id }'
                }
            }
        };
    }

    /**
     * Hook 3: Resolve unique identifiers
     */
    public Map<String, String> resolveUniqueIdentifiers(List<String> ids) {
        Map<String, String> resolvedIds = new Map<String, String>();

        try {
            List<Account> accounts = [
                SELECT Id, ExternalId__c
                FROM Account
                WHERE ExternalId__c IN :ids
            ];

            for (Account acc : accounts) {
                resolvedIds.put(acc.ExternalId__c, acc.Id);
            }

        } catch (Exception e) {
            System.debug('Error resolving IDs: ' + e.getMessage());
        }

        return resolvedIds;
    }

    /**
     * Hook 4: Post-process response
     */
    public Map<String, Object> handlePostOperation(
        Map<String, Object> graphQLQueryResultAsMap,
        Map<String, Object> constructedTMFResponse,
        Map<String, Object> context
    ) {
       /*
	  TODO Any post processing to be performed.
       */

        return null;
    }

    /**
     * NOT APPLICABLE: configureDefaultValidations is not used for Customer Management DELETE API
     */
    public Map<String, Boolean> configureDefaultValidations(
        Map<String, Boolean> defaultValidationConfiguration,
        Map<String, Object> context
    ) {
        return defaultValidationConfiguration;
    }

    /**
     * NOT APPLICABLE: customiseGraphQLQuery is not used for Customer Management DELETE API
     */
    public Map<String, Object> customiseGraphQLQuery(Map<String, Object> graphQLAsMap, Map<String, Object> context) {
        return null;
    }
}

```

## 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):**

```
{
  "nodes": [
    {
      "path": "unlinkCase",
      "insertGraphQlSnippet": "unlinkCase: CaseUpdate(input: { Id: \"500xx000000bnecAAA\" Case: { ContactId: null, AccountId, null } }) { Record { Id ContactId { value } AccountId { value } } }"
    },
    {
      "path": "deleteCase",
      "insertGraphQlSnippet": "deleteCase: CaseDelete(input: { Id: \"500xx000000bnecAAA\" }) { Id }"
    }
  ]
}

```

**Result (GraphQL):**

```
mutation DeleteCase {
  uiapi(input: { allOrNone: true }) {
    unlinkCase: CaseUpdate(input: { Id: "500xx000000bnecAAA" Case: { ContactId: null, AccountId: null } }) {
      Record {
        Id
        ContactId {
          value
        }
        AccountId {
          value
        }
      }
    }
    deleteCase: CaseDelete(input: { Id: "500xx000000bnecAAA" }) {
      Id
    }
  }
}
```
