How to
Adding Console to Salesforce records
The Pendula Console component can be placed on any Salesforce record page — not just Contact, Lead, User, or Person Account pages. When placed on objects like Case, Opportunity, or custom objects, it resolves related person entities (Contacts, Leads, Users, Person Accounts) by following relationship paths you configure.
Configuration is done by creating Recipient Lookup Path custom metadata records. No code changes are required.
How It Works
- A user opens a record page (e.g. a Case) that has the Pendula Console component
- The component reads all active Recipient Lookup Path records for that object type
- It follows each configured relationship path to find related person entities
- If multiple people are found, a dropdown arrow appears next to the recipient name — the user clicks it to switch between conversation partners
On person entity pages (Contact, Lead, User, Person Account), the page record itself is always auto-included as the first recipient. Custom Metadata Types (CMDT) paths can add more.
Creating Recipient Lookup Path Records
Navigate to Setup → Custom Metadata Types → Recipient Lookup Path → Manage Records → New.
Fields
| Field | Description |
|---|---|
| Label | Admin-friendly name (e.g. "Case — Primary Contact") |
| Source Object | API name of the page object (e.g. Case, Opportunity, My_Custom_Object__c) |
| Target Entity | The type of person to resolve: Contact, Lead, User, or PersonAccount |
| Relationship Path | The lookup path to follow (see syntax below) |
| Role Label | Display label shown in the dropdown (e.g. "Primary Contact", "Case Owner") |
| Is Active | Checked = active. Uncheck to disable without deleting |
| Sort Order | Controls display order in the dropdown. Lower numbers appear first |
| Max Results | Maximum records returned for this path. Default 10 |
Relationship Path Syntax
The Relationship Path field supports three patterns.
Pattern 1: Direct Lookup
Use when the source object has a lookup field that points directly to a Contact, Lead, or User.
Syntax: <LookupFieldApiName>
Example: ContactId on Case points to a Contact. The resolver queries:
SELECT Id, Name, MobilePhone FROM Contact WHERE Id = <value of Case.ContactId>
Pattern 2: Parent → Children
Use when you need to traverse through an intermediate object. The source record has a lookup to a parent, and the parent has child records of the target entity type.
Syntax: <LookupFieldApiName>.<ChildRelationshipName>
Example: AccountId.Contacts on Case — first resolve the Case's AccountId, then find all Contacts under that Account. The resolver queries:
SELECT Id, Name, MobilePhone FROM Contact WHERE AccountId = <value of Case.AccountId> LIMIT <Max Results>
The second segment (Contacts) is the child relationship name as defined on the parent object, not a field API name. You can find it in Setup → Object Manager → [Parent Object] → Fields & Relationships → [Lookup Field] → Child Relationship Name.
Pattern 3: Self Children
Use when the source object itself is the parent and you want its child records. The path is simply the child relationship name on the source object.
Syntax: <ChildRelationshipName>
Example: Contacts on Account — finds all Contacts that belong to the Account. The resolver queries:
SELECT Id, Name, MobilePhone FROM Contact WHERE AccountId = <source Account Id> LIMIT <Max Results>
The resolver detects that Contacts is a child relationship name (not a lookup field) on Account and uses the source record's own Id as the parent.
Person Account Paths
For Person Accounts, set Target Entity to PersonAccount and use the lookup field that points to the Account.
Syntax: <LookupFieldApiName> (direct) or <LookupFieldApiName>.PersonContact
The resolver automatically checks IsPersonAccount = true and returns PersonMobilePhone instead of MobilePhone. In orgs without Person Accounts enabled, these paths return no results (no errors).
Examples with Standard Objects
Case
A typical Case configuration resolves the primary contact, all contacts under the related account, the case owner, and a person account if applicable.
| Label | Source Object | Target Entity | Relationship Path | Role Label | Sort Order |
|---|---|---|---|---|---|
| Case — Primary Contact | Case | Contact | ContactId | Primary Contact | 1 |
| Case — Account Contacts | Case | Contact | AccountId.Contacts | Account Contact | 2 |
| Case — Owner | Case | User | OwnerId | Case Owner | 3 |
| Case — Person Account | Case | PersonAccount | AccountId | Person Account | 4 |
Behaviour:
- If the Case has a ContactId set and no other contacts on the Account → single recipient, no dropdown
- If the Case has a ContactId and the Account has 3 Contacts → 3 recipients shown (the primary contact appears once thanks to deduplication), dropdown arrow visible
- If the Case has no ContactId and no Account → no recipients resolved
Account
An Account page can resolve its own child Contacts directly using the child relationship name.
| Label | Source Object | Target Entity | Relationship Path | Role Label | Sort Order |
|---|---|---|---|---|---|
| Account — Contacts | Account | Contact | Contacts | Account Contact | 1 |
| Account — Owner | Account | User | OwnerId | Account Owner | 2 |
| Account — Person Account | Account | PersonAccount | Id | Person Account | 3 |
Behaviour:
- If the Account has 3 Contacts → 3 recipients shown, dropdown arrow visible
- If the Account is a Person Account → the Person Account is auto-included at sort order 0 (before the CMDT paths)
- The
Contactspath uses the child relationship name directly — no intermediate lookup needed
Opportunity
| Label | Source Object | Target Entity | Relationship Path | Role Label | Sort Order |
|---|---|---|---|---|---|
| Opp — Account Contacts | Opportunity | Contact | AccountId.Contacts | Account Contact | 1 |
| Opp — Owner | Opportunity | User | OwnerId | Opportunity Owner | 2 |
| Opp — Person Account | Opportunity | PersonAccount | AccountId | Person Account | 3 |
Contact (adding related people)
On a Contact page, the Contact itself is auto-included as the first recipient (sort order 0). You can add more:
| Label | Source Object | Target Entity | Relationship Path | Role Label | Sort Order |
|---|---|---|---|---|---|
| Contact — Created By | Contact | User | CreatedById | Created By | 1 |
| Contact — Owner | Contact | User | OwnerId | Contact Owner | 2 |
| Contact — Account Contacts | Contact | Contact | AccountId.Contacts | Account Contact | 3 |
Behaviour:
- The Contact page record appears first as "Contact" (auto-included, sort order 0)
- The Created By user appears second (sort order 1)
- The Contact Owner appears third (sort order 2)
- Other Contacts under the same Account appear with sort order 3
- The page Contact is deduplicated from the Account Contacts list
- The dropdown arrow appears because there are multiple recipients
Lead
On a Lead page, the Lead is auto-included. Additional paths:
| Label | Source Object | Target Entity | Relationship Path | Role Label | Sort Order |
|---|---|---|---|---|---|
| Lead — Owner | Lead | User | OwnerId | Lead Owner | 1 |
| Lead — Created By | Lead | User | CreatedById | Created By | 2 |
Custom Objects
For a custom object Project__c with lookup fields to Contact and Account:
| Label | Source Object | Target Entity | Relationship Path | Role Label | Sort Order |
|---|---|---|---|---|---|
| Project — Primary Contact | Project__c | Contact | Primary_Contact__c | Primary Contact | 1 |
| Project — Sponsor | Project__c | Contact | Sponsor__c | Project Sponsor | 2 |
| Project — Account Contacts | Project__c | Contact | Account__c.Contacts | Account Contact | 3 |
| Project — Owner | Project__c | User | OwnerId | Project Owner | 4 |
Note: for custom lookup fields, use the field API name including the __c suffix (e.g. Primary_Contact__c). For parent→children paths with custom relationships, the child relationship name typically ends in __r (e.g. Account__c.Project_Members__r).
Finding the Right API Names
Lookup Field API Name (first segment)
- Go to Setup → Object Manager → [Your Object] → Fields & Relationships
- Find the lookup field (e.g. "Contact" on Case)
- The Field Name column shows the API name (e.g.
ContactId) - For custom fields, the API name ends in
__c(e.g.Primary_Contact__c)
Child Relationship Name (second segment)
- Go to Setup → Object Manager → [Parent Object] (e.g. Account)
- Go to Fields & Relationships
- Find the lookup field on the child object that creates the relationship (e.g. the
AccountIdfield on Contact) - Click it → the Child Relationship Name is shown (e.g.
Contacts) - For custom relationships, this typically ends in
__r
Deduplication
If the same person is resolved by multiple paths (e.g. a Contact found via both ContactId and AccountId.Contacts), they appear only once in the dropdown. The first occurrence (lowest sort order) wins.
On person entity pages, the page record is always included with sort order 0 and is deduplicated from any CMDT results.
Limits and Considerations
- Max 2-hop traversal: Paths support at most one intermediate object (e.g.
AccountId.Contacts). Three-hop paths likeAccountId.ParentId.Contactsare not supported. - Governor limits: Each path executes 1 SOQL query. With 5 paths configured, that's ~6 queries total (including the source record query). Well within the 100-query limit per transaction. If you configure many paths, use Is Active and Max Results to tune.
- Field-Level Security: All queries run in
USER_MODE, so users only see records and fields they have access to. - Person Accounts: Paths targeting Person Accounts silently return no results in orgs where Person Accounts are not enabled. No errors.
- Caching: Results are cached by the Lightning Data Service. Changes to relationships (e.g. reassigning a Case contact) are reflected after a page refresh or when the user clicks the Refresh option in the Console settings menu.