IIndividualPartyManagementPOST Apex Interface

The IIndividualPartyManagementPOST Apex interface provides extensibility for POST operations through Apex pre- and post-hooks and GraphQL query customization. Implementations can validate incoming requests, modify query structures, and refine the response to support business-specific retrieval rules while maintaining TMF-compliant behavior.

This interface supports the following hooks.

Create Operation Use Cases 

Use CaseHook(s)DescriptionExample ScenariosBenefit
Default or Normalize Request FieldstransformRequestTransforms the incoming request before validation and mutation processing. It can supply default values, normalize formats, and map client-specific fields to the canonical Account request structure.- Apply a default Account status or type
- Normalize names, phone numbers, and website URLs
- Standardize country and region codes
- Map legacy fields to TMF632 fields
Ensures consistent, standardized Account data at the point of creation.
Carry Custom Validation FlagsconfigureDefaultValidationsAdds organization-specific validation flags to the validation context. These flags are subsequently read by applyCustomValidations to determine which policies should be enforced for the create request.- Enable duplicate-Account checks
- Require tax or registration identifiers
- Activate stricter address validation
- Require additional checks for regulated Account types
Supports per-organization creation policies by carrying configurable validation flags into custom validation processing.
Enforce Custom Business RulesapplyCustomValidationsReads the configured validation flags and evaluates organization-specific business rules before the Account mutation is built. Invalid payloads are rejected early with an HTTP 400 response and a clear validation message.- Reject duplicate Accounts based on organization rules
- Require registration details for business Accounts
- Validate permitted Account types or lifecycle states
- Require additional fields for specific regions
Rejects invalid payloads early and prevents inconsistent or noncompliant Account records from being created.
Set Organization-Specific Account FieldscustomiseMutationPayloadAdds or modifies organization-specific Account fields in the GraphQL mutation payload before execution. This supports fields that extend beyond the standard TMF632 schema.- Set an internal customer segment
- Add a source-system identifier
- Populate custom risk or compliance fields
- Store organization-specific classification data
Persists custom Account fields beyond the TMF632 data model while preserving the shared API contract.
Audit or Integrate After CreationhandlePostOperationRuns after the Account creation mutation completes and performs post-operation side effects using the creation result. It can write audit records, publish events, or invoke downstream integrations.- Write an Account-creation audit record
- Publish an Account-created event
- Synchronize the Account with billing, CRM, or analytics systems
- Trigger onboarding or compliance workflows
Enables reliable auditing and downstream processing after successful creation while keeping side effects separate from the core operation.

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 

Default a missing organizationType and normalize the country code.

1global class OrganizationPostTransformRequestExt implements comms_apex_ext.IOrganizationPartyManagementPOST {
2    global static Map<String, Object> transformRequest(Map<String, Object> context) {
3        if (context == null || !(context.get('requestBody') instanceof Map<String, Object>)) {
4            return context;
5        }
6        Map<String, Object> body = (Map<String, Object>) context.get('requestBody');
7
8
9        if (body.get('organizationType') == null) {
10            body.put('organizationType', 'Customer');
11        }
12
13
14        if (body.get('contactMedium') instanceof List<Object>) {
15            for (Object cmObj : (List<Object>) body.get('contactMedium')) {
16                if (cmObj instanceof Map<String, Object>) {
17                    Map<String, Object> cm = (Map<String, Object>) cmObj;
18                    if ('GeographicAddressContactMedium'.equals(cm.get('@type'))
19                        && cm.get('country') instanceof String) {
20                        cm.put('country', ((String) cm.get('country')).toUpperCase());
21                    }
22                }
23            }
24        }
25        return context;
26    }
27    // ... other hooks return null / empty map ...
28}

configureDefaultValidations 

This hook enables, disables, or modifies the built-in validation rules before they execute.

Hook Method 

Map<String, Boolean> configureDefaultValidations(Map<String, Boolean> defaultValidationConfiguration, Map<String, Object> context)

Sample Apex Implementation 

Add a custom flag consumed by applyCustomValidations.

1global class OrganizationPostConfigValidationsExt implements comms_apex_ext.IOrganizationPartyManagementPOST {
2    global static Map<String, Boolean> configureDefaultValidations(
3        Map<String, Boolean> defaultValidationConfiguration,
4        Map<String, Object> context
5    ) {
6        Map<String, Boolean> overrides = defaultValidationConfiguration != null
7            ? defaultValidationConfiguration.clone()
8            : new Map<String, Boolean>();
9        overrides.put('nameUniquenessCheck', true);   // your own flag, read in applyCustomValidations
10        return overrides;
11    }
12    // ... other hooks return null / empty map ...
13}

applyCustomValidations 

This hook validates custom business logic before retrieving customer record. If validation fails, it rejects the request and returns an error response.

The handler processes return values as follows.

Success:

  • Return a map with validationStatus set to “pass” (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 

Require an approved organizationType.

1global class OrganizationPostValidationExt implements comms_apex_ext.IOrganizationPartyManagementPOST {
2    private static final Set<String> ALLOWED_TYPES = new Set<String>{ 'Customer', 'Partner', 'Prospect' };
3    global static Map<String, Object> applyCustomValidations(Map<String, Object> context) {
4        Map<String, Object> result = new Map<String, Object>();
5        if (!(context.get('requestBody') instanceof Map<String, Object>)) {
6            return result;
7        }
8        Map<String, Object> body = (Map<String, Object>) context.get('requestBody');
9
10
11        Object typeObj = body.get('organizationType');
12        if (typeObj instanceof String && !ALLOWED_TYPES.contains((String) typeObj)) {
13            result.put('validationStatus', 'fail');
14            result.put('validationMessage',
15                'organizationType must be one of: Customer, Partner, Prospect.');
16        }
17        return result;   // empty => proceed; validationStatus="fail" => HTTP 400
18    }
19    // ... other hooks return null / empty map ...
20}

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 

Add custom Account fields on creation.

1global class OrganizationPostCustomMutationExt implements comms_apex_ext.IOrganizationPartyManagementPOST {
2    global static Map<String, Object> customiseMutationPayload(
3        Map<String, Object> graphQLAsMap,
4        Map<String, Object> context
5    ) {
6        Map<String, Object> node = new Map<String, Object>{
7            'path' => 'organizationData',
8            'addFields' => new Map<String, Object>{
9                'Industry'       => 'Telecommunications',
10                'AccountSource'  => 'Web',
11                'Segment__c'     => 'Enterprise'
12            }
13        };
14        return new Map<String, Object>{
15            'nodes' => new List<Object>{ node }
16        };
17    }
18    // ... other hooks return null / empty map ...
19}

handlePostOperation 

This hook post-processes and transforms the API response after data retrieval.

Hook Method 

Map<String, Object> handlePostOperation(Map<String, Object> graphQLQueryResultAsMap, Map<String, Object> constructedTMFResponse, Map<String, Object> context)

Sample Apex Implementation 

Publish a platform event after creation.

1global class OrganizationPostHandlePostOpExt implements comms_apex_ext.IOrganizationPartyManagementPOST {
2    global static Map<String, Object> handlePostOperation(
3        Map<String, Object> graphQLQueryResultAsMap,
4        Map<String, Object> constructedTMFResponse,
5        Map<String, Object> context
6    ) {
7        // Read the created Account Id from the mutation result (organizationData alias).
8        String newId = extractCreatedId(graphQLQueryResultAsMap);
9        if (newId != null) {
10            EventBus.publish(new Organization_Created__e(Account_Id__c = newId));
11        }
12        return null;   // ignored for POST
13    }
14
15
16    @SuppressWarnings('PMD')
17    private static String extractCreatedId(Map<String, Object> resultMap) {
18        try {
19            Map<String, Object> data = (Map<String, Object>) resultMap.get('data');
20            Map<String, Object> uiapi = (Map<String, Object>) data.get('uiapi');
21            Map<String, Object> org = (Map<String, Object>) uiapi.get('organizationData');
22            Map<String, Object> record = (Map<String, Object>) org.get('Record');
23            return (String) record.get('Id');
24        } catch (Exception e) {
25            return null;
26        }
27    }
28    // ... other hooks return null / empty map ...
29}

Full Implementation Example 

Here’s a complete sample Apex implementation using all supported hooks.

1/**
2 * Complete TMF632 Organization (Party Management) POST API extension,
3 * demonstrating all hooks with business logic.
4 */
5global class OrganizationPartyManagementPOSTExtension implements comms_apex_ext.IOrganizationPartyManagementPOST {
6
7
8    private static final Set<String> ALLOWED_TYPES = new Set<String>{ 'Customer', 'Partner', 'Prospect' };
9
10
11    // Hook 1: normalize the request body.
12    global static Map<String, Object> transformRequest(Map<String, Object> context) {
13        if (context != null && context.get('requestBody') instanceof Map<String, Object>) {
14            Map<String, Object> body = (Map<String, Object>) context.get('requestBody');
15            if (body.get('organizationType') == null) {
16                body.put('organizationType', 'Customer');
17            }
18        }
19        return context;
20    }
21
22
23    // Hook 2: the built-in checks are always enforced; return empty (no custom flags).
24    global static Map<String, Boolean> configureDefaultValidations(
25        Map<String, Boolean> defaultValidationConfiguration,
26        Map<String, Object> context
27    ) {
28        return new Map<String, Boolean>();
29    }
30
31
32    // Hook 3: enforce an approved organizationType.
33    global static Map<String, Object> applyCustomValidations(Map<String, Object> context) {
34        Map<String, Object> result = new Map<String, Object>();
35        if (context.get('requestBody') instanceof Map<String, Object>) {
36            Map<String, Object> body = (Map<String, Object>) context.get('requestBody');
37            Object typeObj = body.get('organizationType');
38            if (typeObj instanceof String && !ALLOWED_TYPES.contains((String) typeObj)) {
39                result.put('validationStatus', 'fail');
40                result.put('validationMessage',
41                    'organizationType must be one of: Customer, Partner, Prospect.');
42            }
43        }
44        return result;
45    }
46
47
48    // Hook 4: add custom Account fields to the create mutation.
49    global static Map<String, Object> customiseMutationPayload(
50        Map<String, Object> graphQLAsMap,
51        Map<String, Object> context
52    ) {
53        Map<String, Object> node = new Map<String, Object>{
54            'path' => 'organizationData',
55            'addFields' => new Map<String, Object>{ 'Industry' => 'Telecommunications', 'AccountSource' => 'Web' }
56        };
57        return new Map<String, Object>{ 'nodes' => new List<Object>{ node } };
58    }
59
60
61    // Hook 5: side effect only (return ignored).
62    global static Map<String, Object> handlePostOperation(
63        Map<String, Object> graphQLQueryResultAsMap,
64        Map<String, Object> constructedTMFResponse,
65        Map<String, Object> context
66    ) {
67        return null;
68    }
69}

Response Structure 

Request Body 

A TMF632 Individual create payload supports the following input fields:

  • Scalars:@type (must be Organization), name (required), organizationType.

  • contactMedium[]: Each item includes an @type discriminator and a corresponding value field:

    • PhoneContactMediumphoneNumber
    • FaxContactMediumfaxNumber
    • GeographicAddressContactMediumstreet1, city, stateOrProvince, postCode, country
  • relatedParty[]: Each item includes a role, @type, and partyOrPartyRole (id + @referredType).

  • @referredType = "Individual": Creates an AccountContactRelation, or links Contact.AccountId when Shared Contacts is disabled.

  • @referredType = "Organization": Creates an AccountAccountRelation. This requires PartyRoleRelation configuration, and the role must match a configured RoleName.

1{
2  "@type": "Organization",
3  "name": "Acme Corporation",
4  "organizationType": "Customer",
5  "contactMedium": [
6    {
7      "@type": "GeographicAddressContactMedium",
8      "street1": "1 Market St",
9      "city": "San Francisco",
10      "stateOrProvince": "CA",
11      "postCode": "94105",
12      "country": "US"
13    },
14    { "@type": "PhoneContactMedium", "phoneNumber": "+1-555-0100" },
15    { "@type": "FaxContactMedium", "faxNumber": "+1-555-0101" }
16  ],
17  "organizationParentRelationship": {
18    "@type": "OrganizationParentRelationship",
19    "organization": { "@type": "OrganizationRef", "id": "001xx000003DEF" }
20  },
21  "relatedParty": [
22    {
23      "@type": "RelatedPartyRefOrPartyRoleRef",
24      "role": "Decision Maker",
25      "partyOrPartyRole": { "@type": "PartyRef", "@referredType": "Individual", "id": "003xx000004MZZ" }
26    },
27    {
28      "@type": "RelatedPartyRefOrPartyRoleRef",
29      "role": "Supplier",
30      "partyOrPartyRole": { "@type": "PartyRef", "@referredType": "Organization", "id": "001xx000003DaB" }
31    }
32  ]
33}

Response (HTTP 201 Created) 

The created Organization, in the same representation returned by GET (relative href, @type = “Organization”, @baseType = “Party”):

1{
2  "id": "001xx000003DHP",
3  "href": "/connect/comms/partymanagement/v5/organization/001xx000003DHP",
4  "@type": "Organization",
5  "@baseType": "Party",
6  "name": "Acme Corporation",
7  "organizationType": "Customer",
8  "contactMedium": [
9    {
10      "@type": "GeographicAddressContactMedium",
11      "street1": "1 Market St",
12      "city": "San Francisco",
13      "stateOrProvince": "CA",
14      "postCode": "94105",
15      "country": "US"
16    },
17    { "@type": "PhoneContactMedium", "phoneNumber": "+1-555-0100" },
18    { "@type": "FaxContactMedium", "faxNumber": "+1-555-0101" }
19  ],
20  "organizationParentRelationship": {
21    "@type": "OrganizationParentRelationship",
22    "organization": {
23      "id": "001xx000003DEF",
24      "href": "/connect/comms/partymanagement/v5/organization/001xx000003DEF",
25      "name": "Acme Holdings",
26      "@type": "OrganizationRef"
27    }
28  },
29  "relatedParty": [
30    {
31      "@type": "RelatedPartyRefOrPartyRoleRef",
32      "role": "Decision Maker",
33      "partyOrPartyRole": {
34        "id": "003xx000004MZZ",
35        "href": "/connect/comms/partymanagement/v5/individual/003xx000004MZZ",
36        "name": "John Smith",
37        "@type": "PartyRef",
38        "@referredType": "Individual"
39      }
40    },
41    {
42      "@type": "RelatedPartyRefOrPartyRoleRef",
43      "role": "Supplier",
44      "partyOrPartyRole": {
45        "id": "001xx000003DaB",
46        "href": "/connect/comms/partymanagement/v5/organization/001xx000003DaB",
47        "name": "Globex Supplies",
48        "@type": "PartyRef",
49        "@referredType": "Organization"
50      }
51    }
52  ]
53}