Skip to content

getContact

This interface is a central interface to the Unified CRM adapter framework as it is responsible for matching phone numbers with contacts in the target CRM. This interface powers the following key features:

  • call pop
  • call logging
  • sms logging

This interface can return one or more contacts. If multiple contacts are returned, the Unified CRM extension will prompt the end user to select the specific contact to be used when logging calls.

This interface is called in the following circumstances:

  • When a call is received.
  • When a user manually clicks the "refresh contact" action for a contact or phone call.
  • When a user accesses the Unified CRM Chrome extension the first time in an attempt to perform an initial contact match operation for recent phone calls.

Manually refresh contact

The "Refresh contact" action in the Unified CRM extension's contact list

Request parameters

Parameter Description
user An object describing the Chrome extension user associated with the action that triggered this interface.
authHeader The HTTP Authorization header to be transmitted with the API request to the target CRM.
phoneNumber The phone number to search for within the target CRM, provided in an E.164 format, e.g. +11231231234.
overridingFormat (Optional) If defined by the user under advanced settings, this will contain alternative formats the user may wish to use when searching for the phoneNumber

Alternative formats

Some CRM's have very restrictive APIs with regards to searching for phone numbers, meaning they require an exact match in order to find a contact with that phone number. To work around this restriction, users are allowed to specify a list of phone number formats which they often use when entering phone numbers into the CRM. It is the intention that each adapter when provided a list of overridingFormat values to convert the E.164 phone number into each of the overriding formats, and to search for each one until a contact is found.

Remember: only a single call the getContact interface will be made. The developer is responsible for searching for each alternative format.

Return value(s)

This interface returns a single object. That object describes the contacts that were found. It has following properties:

Parameter Description
matchedContactInfo An array of objects containing id, name and optionally additionalInfo and isNewContact.
returnMessage message, messageType and ttl

isNewContact is only used as an extra option in contact list for users to be able to create new contacts

Example

{
  matchedContactInfo:[
    {
      id: 'contact id',
      name: 'John Doe',
      additionalInfo: null,
      isNewContact: false
    },
    {
        id: 'createNewContact',
        name: 'Create new contact...',
        additionalInfo: null,
        isNewContact: true
    }
  ],
  returnMessage:{
    message: 'Found 1 contact',
    messageType: 'warning', // 'success', 'warning' or 'danger'
    ttl: 30000 // in miliseconds
  }
}

Reference

async function findContact({ user, authHeader, phoneNumber, overridingFormat }) {
    // ----------------------------------------
    // ---TODO.3: Implement contact matching---
    // ----------------------------------------

    const numberToQueryArray = [];
    numberToQueryArray.push(phoneNumber.replace(' ', '+'));
    // You can use parsePhoneNumber functions to further parse the phone number
    const matchedContactInfo = [];
    // for (var numberToQuery of numberToQueryArray) {
    //     const personInfo = await axios.get(
    //         `https://api.crm.com/contacts?query=number:${numberToQuery}`,
    //         {
    //             headers: { 'Authorization': authHeader }
    //         });
    //     if (personInfo.data.length > 0) {
    //         for (var result of personInfo.data) {
    //             foundContacts.push({
    //                 id: result.id,
    //                 name: result.name,
    //                 type: result.type,
    //                 phone: numberToQuery,
    //                 additionalInfo: null
    //             })
    //         }
    //     }
    // }
    if (mockContact != null) {
        matchedContactInfo.push(mockContact);
    }
    console.log(`found contacts... \n\n${JSON.stringify(matchedContactInfo, null, 2)}`);

    // If you want to support creating a new contact from the extension, below placeholder contact should be used
    matchedContactInfo.push({
        id: 'createNewContact',
        name: 'Create new contact...',
        additionalInfo: null,
        isNewContact: true
    });
    //-----------------------------------------------------
    //---CHECK.3: In console, if contact info is printed---
    //-----------------------------------------------------
    return {
        matchedContactInfo,
        returnMessage: {
            messageType: 'success',
            message: 'Successfully found contact.',
            ttl: 3000
        }
    };  //[{id, name, phone, additionalInfo}]
}
async function findContact({ user, authHeader, phoneNumber, overridingFormat }) {
    phoneNumber = phoneNumber.replace(' ', '+')
    // without + is an extension, we don't want to search for that
    if (!phoneNumber.includes('+')) {
        return {
            matchedContactInfo: null,
            returnMessage: {
                message: 'Logging against internal extension number is not supported.',
                messageType: 'warning',
                ttl: 3000
            }
        };
    }
    const phoneNumberObj = parsePhoneNumber(phoneNumber);
    let phoneNumberWithoutCountryCode = phoneNumber;
    if (phoneNumberObj.valid) {
        phoneNumberWithoutCountryCode = phoneNumberObj.number.significant;
    }
    const personInfo = await axios.get(
        `https://${user.hostname}/v1/persons/search?term=${phoneNumberWithoutCountryCode}&fields=phone`,
        {
            headers: { 'Authorization': authHeader }
        });
    const matchedContactInfo = [];
    for (const person of personInfo.data.data.items) {
        const dealsResponse = await axios.get(
            `https://${user.hostname}/v1/persons/${person.item.id}/deals?status=open`,
            {
                headers: { 'Authorization': authHeader }
            });
        const relatedDeals = dealsResponse.data.data ?
            dealsResponse.data.data.map(d => { return { const: d.id, title: d.title } })
            : null;
        matchedContactInfo.push(formatContact(person.item, relatedDeals));
    }