Constructing the right Domain with Freshsales Suite

As you build integration with Freshsales, you will quickly find there’s a need for two critical requirements for your integration to succeed.

  1. Subdomain + Root Domain
  2. API Key

The subdomain is usually the brand name of the organization.

The root domain can be one of the following.

  1. freshsales.io
  2. freshworks.com
  3. myfreshworks.com

As an app developer, you want your integration to work seamlessly with any user of Freshsales with any of the above root domains possible amongst the users. Both of these details are necessary to consume Freshsales API.

This Handbook will explore the right way to accomplish it and get your app the right combination of domain and API keys to make API calls and make the integration accurately. It is important to note that there is

  1. Freshsales
  2. Freshsales Suite (previously freshsales suite)

If your app runs on Freshworks App Platform, developers can choose to build their app either by using iparams.json or by iparams.html (labeled custom installation page).

Iparams.json

This allows the app developer to define a JSON file in the config/ directory.

Previously (labeled: Freshsales Classic)

config/iparams.json

 "domainName": {
    "display_name": "Domain Name",
    "description": "Please enter your domain name",
    "type": "domain",
    "type_attributes": {
      "product": "freshsales"
    },
    "required": true
  },
  "apiKey": {
    "display_name": "API Key",
    "description": "Please enter your api_key",
    "type": "api_key",
     "type_attributes": {
      "product": "freshsales"
    },
    "secure": true,
    "required": true,
  }

App expected the above declaration of installation parameters. The above would render the following:
image

The app can access the user entered Domain Name as follows:

// app.js

let client;
(async function init(){
  client = await app.initialized(); 
  client.events.on('app.activated', ignite);
})();

async function ignite(){
  // 'brandname' is retrievable as follows:
  let domainName = await client.iparams.get("domainName"); 
}

// server.js

// All serverless event payloads get the "iparams" property where the app can access stored data.

Prime points to pay attention to:

  1. All the users who newly sign up for Freshsales will have brandname.myfreshworks.com instead of brandname.freshsales.io.
  2. Eventually, accounts on brandname.freshsales.io will be moved under brandname.freshworks.com.
  3. All the apps using brandname.freshsales.io to construct API endpoints and make API calls will continue to succeed.

If the type_attributes.product value is freshworks_crm , in the input box that is displayed on the Installation page, the domain name part is populated as myfreshworks.com .

// iparams.json

{
  "domainName": {
    "display_name": "Domain Name",
    "description": "Please enter your domain name",
    "type": "domain", // use type "text" to populate "http
    "type_attributes": {
      "product": "freshworks_crm"
    },
    "data-bind": "product.domain",
    "required": true,
    "visible": false // (Optional) The field won't be displayed but it will be correctly populated and stored.
  },
  "apiKey": {
    "display_name": "API Key",
    "description": "Please enter your api_key",
     "type_attributes": {
      "product": "freshworks_crm"
    },
    "type": "text",
    "secure": true,
    "required": true
  }
}

Render:

image

If the value is freshworks_crm and if the app is installed on a Freshsales Suite (FCRM) account that has been migrated from Freshsales, the domain name part is populated as freshworks.com.

image

Omni apps supporting Freshsales and Freshsales suite simultaneously, If the type_attributes.product value is current , the domain name is populated based on the product on which the app is installed.

If the app is installed on a Freshsales account, the domain name part is populated as freshsales.io . If the app is installed on a Freshsales Suite (FCRM) account, the domain name part is populated as myfreshworks.com or freshworks.com (if the account is migrated from Freshsales).
image

Tip: Learn about Data Bind to Auto Populate these fields as needed.

Custom Installation Page

You can use data-bind to auto-populate domain names or even API keys without users having to enter them. This way app can use DOM manipulation to access the values to perform any validations if necessary.

Get Domain at App Runtime

Now can get the domain or URL at the runtime of the app. The app doesn’t need to capture those details from the user.

// app.js. on Freshsales Suite

let client;
(async function init(){
  client = await app.initialized(); 
  client.events.on('app.activated', ignite);
})();

async function ignite(){
  // The domain details is retrive-able as follows
  let data = await client.data.get("domainName"); 
 /*
data:
{
  domainName:"brandname.myfreshworks.com",
  productContext:{
    url:"https://brandname.myfreshworks.com/crm",
    name:"freshworks_crm"
  }
}

*/

// You can access the above details at runtime automatically. 
}

Unless required based on the use case, you can avoid getting the domain name completely, and gain them at runtime. Construct API endpoints and make API calls worry-free.

Alternate Approach to get Domain Details at Runtime

Let’s say the following is your iparams.json. It’s mandatory to have both domainName and apiKey.

// iparams.json

 "domainName": {
    "display_name": "Domain Name",
    "description": "Please enter your domain name",
    "type": "domain",
    "type_attributes": {
      "product": "freshworks_crm"
    },
    "required": true
  },
  "apiKey": {
    "display_name": "API Key",
    "description": "Please enter your api_key",
    "type": "api_key",
     "type_attributes": {
      "product": "freshworks_crm"
    },
    "secure": true,
    "required": true,
  }

In app.js or anywhere


let client;
(async function init(){
  client = await app.initialized(); 
  client.events.on('app.activated', ignite);
})();

async function ignite(){
  // 'brandname' is retrievable as follows:
  let data = await client.iparams.get($domainName); 
  /* data
  { url: https://brandname.myfreshworks.com/crm, name: ‘freshworks_crm’ }
 */
}

Note:

  • The $domainName here should be of "type":"domain"
  • The domainName in $domainName should be the same property key in iparams.json . For example, the iparams.json mentions domain. At the time of retrieval $domain should be be used as await client.iparams.get($domain).
  • This way of retrieving the root domain and subdomain will require another property listed in iparams.json with the "type":"api_key"