getContact
This interface is central to App Connect's 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, App Connect 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 App Connect the first time in an attempt to perform an initial contact match operation for recent phone calls.
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, isExtension }) {
// ----------------------------------------
// ---TODO.3: Implement contact matching---
// ----------------------------------------
console.log(`phone number: ${phoneNumber}`)
console.log(`is extesnion number? ${isExtension}`)
const numberToQueryArray = [];
if(isExtension)
{
numberToQueryArray.push(phoneNumber);
}
else{
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 {
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));
}