Note: Unify Lookup requires a dedicated Unify Lookup Server instance — it is not available on shared infrastructure subscriptions — and DQE One must already be installed in your org. Contact DQE Support to have this feature enabled for your organization before following the steps below.
Custom Settings
- Go to the Custom Settings section. A custom setting named DQE Unify Lookup is available.
- Click Manage and create an instance at your organization default level.
- Fill in the required information.
- Allow Skip: allows users to skip Unify Lookup suggestions and create a new record.
- App Named Cred: name of the named credential.
- Displayed Fields: fields displayed in the suggestions table.
- Lookup record before insert: when enabled, the DQE Create/Edit Record forms run a Unify Lookup search before creating a new record, in addition to the Record Lookup button override described below.
Access to the Record Lookup Setup tab
Open the DQE One app, go to the DQE One Setup tab, then select the Lookup sub-tab. Select your named credential and click Connect. This establishes the connection between your Salesforce org and your Unify Lookup Server instance.
Launching an indexation
After clicking Connect, the DQE One application loads below the Setup card with two tabs, Salesforce and Heroku Connect (Salesforce is selected by default). Repeat the steps below for every Salesforce object you want to make searchable through Record Lookup.
- On the Salesforce tab, click Add (top left). The Add Salesforce Data Source window opens.
- In that window, select the Salesforce object to index from the drop-down list and click Add. The object now appears as a new row below the Add button.
- On the object's row, click the Rulesets button and pick a ruleset in the Ruleset window that opens. Only rulesets already configured for this object in DQE Unify (as a Duplicate Check process on your Salesforce org — see "Set up Unify processes and rules") appear in this list; if it is empty, create that process first.
- Optionally, click the Filters button and pick a Salesforce List View in the Input Filters window to index only the records matched by that List View. If no filter is set, every record of the object is indexed.
- Click the Index Database button (the play icon) on the object's row to start the indexation.
- If this object was already indexed before, a confirmation window titled Erase previous indexation ? appears, warning that the previous index will be cleared and that search performance will be degraded while the new indexation runs. Click Yes to continue, or No to cancel.
- A progress bar appears on the object's row and updates live (Reading, then Running, then Finished) until the indexation completes. Once it shows Finished, the object's records are searchable through the Record Lookup button described below.
Each object's row also offers:
- a checkbox to also expose this object through Salesforce's native Global Search (Federated Search, see the API guide below);
- Clear DB, to delete its indexed data without removing the object from the list;
- Delete Record Type, to remove the object from the data sources entirely (its ruleset and filter selections are discarded).
Record Lookup
Once your objects are indexed, override the standard New button on each of them with the Record Lookup button, so users can search for an existing record before creating a new one:
- Go to Salesforce Setup.
- Open Object Manager.
- Select the relevant object.
- Locate the New button.
- Override the button with the Record Lookup button.
API guide
This section describes the APIs exposed by the Record Lookup app.
Federated Search
OpenSearch Description
Salesforce provides an integration protocol for external data sources. Full documentation is available in the Salesforce Federated Search documentation.
To comply with this protocol, the Unify Lookup application exposes an XML-Atom API in two parts. The first part describes the format.
- Route: /api/openSearch.xml
-
Call:
curl -X GET https://[YOUR APP URL]/api/openSearch.xml - Response:
Since the format must be unique for all responses, the field list is immutable. For each type of record indexed in the Unify Lookup app, you can map an address, email, phone number, first name, and last name.
The Source field corresponds to the record type. For example, if the app indexes Salesforce objects, possible values include Lead, Account, and Contact. For external PostgreSQL tables, the source is named after the table.
OpenSearch Format
The second OpenSearch API is the request for a resource itself.
When this API is used from the external source search bar in your Salesforce org, the settings are passed automatically.
- Route: /api/openSearch
-
Parameters:
- search (string): search terms
- orgId (string): Salesforce org ID
- recordType (string, optional): restrict the search to a single Salesforce object or PostgreSQL table, for example Lead
-
Call:
curl -X GET https://[YOUR APP URL]/api/openSearch?search=Ms. Cha Fadner&orgId=[YOUR ORG ID]&recordType=Lead - Response:
OpenSearch Golden Record
A golden-record variant of the OpenSearch API above: it only returns parent (golden) records instead of every matching record. Configure it as a second, separate Federated Search external data source if you want a dedicated search experience limited to golden records.
- Description route: /api/openSearchGolden.xml
- Search route: /api/openSearchGolden
-
Parameters:
- search (string): search terms
- orgId (string): Salesforce org ID
-
Call:
curl -X GET https://[YOUR APP URL]/api/openSearchGolden?search=Ms. Cha Fadner&orgId=[YOUR ORG ID]
REST API
In addition to the XML APIs used by your Salesforce org, the Unify Lookup server exposes APIs that allow you to perform real-time pre-existence lookups from external systems. This section describes these APIs and their call methods.
Authentication
All APIs described below are secured with Basic Auth. The username is the identifier of the registered Salesforce organization, and the password is the licence key provided by DQE Software. This is the same key entered in the environment variables of your application.
Search
This API is an autocomplete engine on a single search line. It returns a list of suggested potential records matching the search criteria.
Route: /api/searchRecords
This route is also available as /api/searchGolden — it is a plain alias with the exact same behavior, it does not filter for golden records only.
Parameters:
- search (string): search terms
- recordType (string, optional): restrict the search to a single Salesforce object or PostgreSQL table, for example Lead
Any other query parameter is also used to filter the results on that field's value, for example PostalCode=77000.
Response structure:
The response is a list of objects structured with fields such as Id, Source, FirstName, LastName, Phone, Email, Street, City, PostalCode, State, and Country.
Example call:
curl -X GET \
-H "Authorization: Basic {authorization_header}" \
https://[YOUR APP URL]/api/searchRecords?search=Ms. Chantal Fadner&recordType=LeadSample response:
[
{
"Id": "00Q0900000E3ded7FUEAZ",
"Source": "Lead",
"FirstName": "rerere",
"LastName": "azazaza",
"Phone": "0*****31",
"Email": "*****@hotmail.fr",
"Street": "R************NIERES",
"City": "A**********X",
"PostalCode": "12345",
"State": "",
"Country": "France"
}
]Lookup
This API performs a pre-existence search by comparing a complete record with all indexed records.
Route: /api/lookupRecords
Parameters:
You can provide any key/value pair present in your form, either in the body of your query or in the query parameters. Keys are case-sensitive. Keys that are not found in the records are ignored.
Response structure:
The response is a list of objects structured with fields such as Id, Source, FirstName, LastName, Phone, Email, Street, City, PostalCode, State, and Country.
Example call:
curl -X GET \
-H "Authorization: Basic {authorization_header}" \
https://[YOUR APP URL]/api/lookupRecords?Email=airelue.fc@laposte.net&PostalCode=77961&Phone=0695473336&Street=Rue du Clos Gillet&FirstName=Aurélie&LastName=FUALKNERSample response:
[
{
"Phone": "**********",
"City": "A*****LE",
"FirstName": "Au****ei",
"MobilePhone": "",
"State": "",
"PostalCode": "12345",
"LastName": "F****ER",
"Country": "France",
"Email": "ai******@laposte.net",
"Street": "Rue ********et",
"Id": "00Q0900000E37F3EAJ",
"Source": "Lead"
}
]If no deduplication rule sets have been imported into your application:
{
"status": "error",
"error": "No rules set loaded yet"
}Golden record
This API performs a pre-existence search by comparing a complete record with all indexed records. Unlike the previous API, it only returns the record with the best match score.
Route: /api/lookupGolden
Parameters:
You can provide any key/value pair present in your form, either in the body of your query or in the query parameters. Keys are case-sensitive. Keys that are not found in the records are ignored.
Optionally include strict: true to also require the best match to be validated against the ruleset's main matching rule; if it isn't, the next best match is tried instead, and no record is returned if none of them passes.
Response structure:
The response contains the match certainty, the rule that matched the record, and the best matching record.
Example GET call:
curl -X GET \
-H "Authorization: Basic {authorization_header}" \
https://[YOUR APP URL]/api/lookupGolden?Email=ai************.net&PostalCode=1234&Phone=*******&Street=Ru*********t&FirstName=A******&LastName=F*****Example POST call:
curl --location 'https://[YOUR APP URL]/api/lookupGolden' \
--header "Authorization: Basic {authorization_header}" \
--header 'Content-Type: text/plain' \
--data-raw '{
"recordType": "PersonAccount",
"FirstName": "S*****",
"LastName": "T****",
"PersonEmail": "s************id"
}'Sample response:
{
"certainty": 0.05298333333333333335,
"matched_by": "Address",
"record": {
"Phone": "***************",
"City": "**********",
"FirstName": "Au***********",
"MobilePhone": "",
"State": "",
"PostalCode": "12345",
"LastName": "*******************",
"Country": "France",
"Email": "******************.net",
"Street": "Rue ****************et",
"Id": "00Q0900000E37F3EAJ",
"Source": "Lead"
}
}If no deduplication rule sets have been imported into your application:
{
"status": "error",
"error": "No rules set loaded yet"
}In all other cases:
{
"status": "error",
"error": "bad request"
}Add record
Use this API to add a record to your indexing registry without restarting a process across the entire Salesforce database.
Route: /api/add
Parameters:
- recordType: SObject API name, for example Lead, Account, or Contact
- Id: Salesforce ID
You can also provide any key/value pair present in your record in the query parameters. Keys are case-sensitive. Keys that are not found in the records are ignored.
Example GET call:
curl -X GET \
-H "Authorization: Basic {authorization_header}" \
https://[YOUR APP URL]/api/add?recordType=Lead&Email=a************e.net&PostalCode=12345&Phone=0************&Street=Rue*************&FirstName=A**********&LastName=F********RExample POST call:
curl --location 'https://[YOUR APP URL]/api/add' \
--header 'Authorization: Basic {authorization_header}' \
--header 'Content-Type: text/plain' \
--data-raw '{
"0": {
"Phone": "0***********6",
"BillingStreet": "R***********t",
"BillingPostalCode": "12345",
"LastName": "*****",
"PersonEmail": "a**************t",
"BillingCity": "H*****************Y",
"id": "[SALESFORCE ID]",
"FirstName": "A****************e",
"attributes": {"type":"PersonAccount"}
}
}'Successful response:
{
"status": "success",
"label": "Record added"
}If the object API name is not one of the objects currently allowed to be indexed:
{
"status": "error",
"label": "RecordType not mapped in your application"
}In this case, go to the Lightning Unify Lookup app and add the object.
If the record could not be added because the Redis database is running out of storage:
{
"status": "error",
"label": "memory > max memory"
}In all other cases:
{
"status": "error",
"error": "bad request"
}Remove record
Use this API to remove a record from your indexing registry without restarting a process across the entire Salesforce database.
Route: /api/delete
Parameters:
- recordType: SObject API name, for example Lead, Account, or Contact
- Id: Salesforce ID
You can also provide any key/value pair present in your record in the query parameters. Keys are case-sensitive. Keys that are not found in the records are ignored.
Delete a single record:
curl -X GET \
-H "Authorization: Basic {authorization_header}" \
https://[YOUR APP URL]/api/delete?Id=00DX00000DJ19Q&recordType=Lead&Email=a*********netDelete multiple records:
curl -X POST https://[YOUR APP URL]/api/delete \
-H "Authorization: Basic {authorization_header}" \
-d "[JSON Data]"The JSON body should be structured as follows:
{
"recordId": {
"attributes": {
"type": "recordType"
}
}
}Successful response:
{
"status": "success",
"label": "Record(s) removed"
}In all other cases:
{
"status": "error",
"error": "Failed to remove record"
}Index Database
This API starts the global indexing process on an object. The object must already have been added through the interface to the list of objects, and a ruleset must be configured for it.
Route: /api/index
Parameters:
- recordType: SObject API name or PostgreSQL table name, for example Lead, Account, or Contact
-
model:
SFto index a Salesforce object, orHKto index a PostgreSQL table -
access_token: valid Salesforce session token (required when
model=SF) -
instance_url: Salesforce org URL, in the format
https://xxx.my.salesforce.com(required whenmodel=SF)
Example call:
curl -X GET \
-H "Authorization: Basic {authorization_header}" \
https://[YOUR APP URL]/api/index?recordType=Lead&model=SF&access_token=XXXXXXXXXX&instance_url=https://mysforg.my.salesforce.comSuccessful response:
{
"status": "success",
"label": "indexing by Bulk started"
}If the object API name is not one of the objects currently allowed to be indexed:
{
"status": "error",
"label": "RecordType not mapped in your application"
}In this case, go to the Lightning Unify Lookup app and add the object.
In all other cases:
{
"status": "error",
"error": "bad request"
}Apex REST resources
The AppExchange Unify Lookup package provides resources as Apex classes that can be invoked from your Apex classes or through APIs.
Authentication
The API resources described below can only be accessed with a valid Salesforce token retrieved through the OAuth2 API. The {authorization_header} variable in the following examples represents this session token.
UpdateDB
To insert or remove records from the indexed database, use this REST resource. Provide the record IDs, the object type, and the operation to apply.
Route: [YOUR SALESFORCE DOMAIN]/services/apexrest/UnifyLookup/updateDB/
Parameters:
- ids: Salesforce record IDs separated by commas
- sObjectName: SObject API name, for example Lead, Account, or Contact
-
action:
insertordelete(case-sensitive, lowercase)
Example call:
curl -X GET https://[YOUR SALESFORCE DOMAIN]/services/apexrest/UnifyLookup/updateDB/?ids=0017R00002ryGbZQAU,0017R00002kqzFHQAY&sObjectName=Account&action=insert \
-H "Authorization: Bearer {authorization_header}"Successful response:
{
"status": "success",
"label": "Record added"
}If an error occurs:
{
"status": "error",
"label": "Failed to add record"
}Calling from an Apex class
You can also call the functions directly from your Apex classes because the Apex functions are defined as global.
deleteRecord
List<String> ids = new List<String>{'0017R00002ryGbZQAU', '0017R00002kqzFHQAY'};
String sObjectName = 'Account';
Map<String, String> res = UnifyLookup.DQE_Lookup_update_db.deleteRecord(ids, sObjectName);insertRecord
List<String> ids = new List<String>{'0017R00002ryGbZQAU', '0017R00002kqzFHQAY'};
String sObjectName = 'Account';
Map<String, String> res = UnifyLookup.DQE_Lookup_update_db.insertRecord(ids, sObjectName);
Related to