Please note: learn how to ungate your account for this beta. By using these instructions you agree to adhere to HubSpot's Developer Terms & HubSpot's Developer Beta Terms.
Developers using the Calling SDK can now enable inbound calling within HubSpot. When a user receives and answers a call through your app in HubSpot, they can access call records directly in HubSpot, eliminating the need to switch back to the calling app. Calls are automatically logged in the Call Index Page where users can take real-time notes and review the call after it ends.
Since HubSpot is a multi-page web application, navigating across HubSpot pages triggers a full page refresh. This means that the iframe hosting your calling app is dropped from the DOM, and then re-rendered in the new page. In order to prevent dropped calls when navigating across HubSpot, calling apps can hold their call connection in a calling window.
This experience will be enabled by default. However, calling apps that already prevent dropped calls have the ability to opt out of the calling window. Once you have set your app settings using the calling settings endpoint, use the PATCH endpoint to change usesCallingWindow
to false.
curl --request PATCH \
--url 'https://api.hubapi.com/crm/v3/extensions/calling/APP_ID/settings?hapikey=DEVELOPER_ACCOUNT_API_KEY' \
--header 'accept: application/json' \
--header 'content-type: application/json' \
--data '{"usesCallingWindow":false}'
HubSpot will notify your calling app of the iframe location in the onReady SDK event. You'll need to update your app as follows:
- When
iframe location
iswindow
, create the call connection in the calling window and manage the shared calling state. We recommend using a SharedWorker for cross-tab communication. - When
iframe location
isremote
, subscribe to the shared calling state from the calling window.
For example, when a user clicks on the answer call button in the iframe on the HubSpot navigation bar, the call is placed from the calling window and both iframes show that the user is in a call. In addition to preventing dropped calls, this solution also prevents simultaneous ringing, since this could occur because HubSpot will be hosting your calling app in an iframe in each browser tab the user has opened.
import CallingExtensions from "@hubspot/calling-extensions-sdk";
const extensions = new CallingExtensions({
eventHandlers: {
onReady: ({ engagementId, iframeLocation, ownerId, portalId, userId}) => {
/* HubSpot is ready to receive messages. */
},
});
Property | Type | Description |
---|---|---|
engagementId | Number | A HubSpot created engagement ID. |
iframeLocation | Enum | widget : drag and drop widget shown in record pages when calling app doesn't support inbound inbound calling.remote : iframe in the navigation bar when calling app supports inbound calling.window : iframe in the calling window when calling app supports inbound calling. |
ownerId | String or Number | The ID of the logged in user in HubSpot. |
portalId | Number | The ID of the HubSpot account. |
userId | Number | The ID of the HubSpot user. |
For npm, run:
xxxxxxxxxx
npm i -s @hubspot/calling-extensions-sdk@latest
For yarn, run:
xxxxxxxxxx
yarn add @hubspot/calling-extensions-sdk@latest
You can set the user's availability using on of the following events:
- Via the
initialized
event:
xxxxxxxxxx
const payload = {
// Optional: Whether a user is logged-in
isLoggedIn: boolean,
// Optional: Whether a user is available for inbound calling
isAvailable: boolean,
// Optional: The desired widget size
sizeInfo: {
height: number,
width: number,
},
};
extensions.initialized(payload);
- Via the
userAvailable
event:
xxxxxxxxxx
extensions.userAvailable();
- Via the
userUnavailable
event:
xxxxxxxxxx
extensions.userUnavailable();
You will be able to send calling lifecycle events, such as callAnswered
and callCompleted
, in the same way it is done for outgoing calls.
xxxxxxxxxx
const callInfo = {
fromNumber: string, // Required: The caller's number
toNumber: string, // Required: The recipient's number
createEngagement: boolean, // Whether HubSpot should create an engagement for this call
};
extensions.incomingCall(callInfo);
- If you’ve set
createEngagement
to true, you can subscribe toonCreateEngagementSucceeded
andonCreateEngagementFailed
. It is recommended you do this so that you can enable your calling app to support custom objects. This will allow future integration into other areas of HubSpot.
xxxxxxxxxx
onCreateEngagementSucceeded(data) {
const {
/* A HubSpot created engagement id. */
engagementId: number,
} = data;
}
onCreateEngagementFailed(data) {
const {
error: { message: string }
} = data;
}
- You will be able to subscribe to
onCallerIdMatchSucceeded
andonCalledIdMatchFailed
. This will enable you to receive contact matching data for the incoming call that previously had to be obtained via the Search API, and will solve its rate limitations.
xxxxxxxxxx
onCallerIdMatchSucceeded: data => {
/* HubSpot has fetched caller id matches for this call. */
const {
callerIdMatches: (ContactIdMatch | CompanyIdMatch)[];
} = data;
}
onCallerIdMatchFailed: data => {
/* HubSpot has failed to fetch caller id matches for this call. */
const {
error: { message: string }
} = data;
}
xxxxxxxxxx
type ObjectCoordinates = {
portalId: number;
objectTypeId: string;
objectId: number;
}
type ContactIdMatch = {
callerIdType: 'CONTACT';
objectCoordinates: ObjectCoordinates;
firstName: string;
lastName: string;
email: string;
}
type CompanyIdMatch = {
callerIdType: 'COMPANY';
objectCoordinates: ObjectCoordinates;
name: string;
}
Once you receive the caller ID matches, you can send HubSpot a message to navigate to a contact or company record page.
xxxxxxxxxx
const data = {
objectCoordinates: ObjectCoordinates, // from onCallerIdMatchSucceeded
};
extensions.navigateToRecord(data);
Once the call engagement is created, HubSpot will redirect to the contact page specified in the navigateToRecord
payload and will sync with the SDK in the onReady
event. You'll need to re-initialize the SDK using the engagement ID and show an incoming call within the iframe.
xxxxxxxxxx
// Receive an engagementId for an existing inbound call
type Payload = {
engagementId: number | undefined
}
// Message indicating that HubSpot is ready to receive messages
onReady(payload) {
// Send initialized message to HubSpot to indicate that the call widget is also ready
extensions.initialized(payload);
if (payload.engagementId) {
// Initialize calling state in the app for existing inbound call
}
}
In the following sections, preview how the incoming call feature will work in your calling app.
If you are using a developer test account, follow the local storage instructions. To ungate your account for this beta, open your browser developer console from a HubSpot tab, and set the following:
xxxxxxxxxx
localStorage['LocalSettings:Calling:supportsInboundCalling'] = true;
If you are using another type of account, join the beta.
Before logging in to your calling app, you'll need to select the provider from your call settings:
- In your HubSpot account, click the settings icon in the main navigation bar.
- In the left sidebar menu, click General. Then, click the Calling tab at the top.
- Click the Make and receive calls through dropdown menu, then select your calling app.
Once the preferred provider is selected, incoming calls will only be received through the selected provider. HubSpot will not support receiving incoming calls from multiple providers in this version.
If you wish to change the provider for receiving calls, you'll have to go back to your call settings to make the change.
Please note**:** for outbound calls, you can continue to switch providersfrom the contact record.
If you've not already set up an integration with any of the calling apps, click here to learn more.
- Log in to your calling app through the call widget in HubSpot. The call widget can be accessed on the main navigation bar.
- Set availability to e HubSpot to start receiving calls.
- Answer inbound calls from the call remote.
Please note: the behavior may vary slightly based on each calling apps' implementation.
Once the call is completed, the inbound call gets logged in the Call Index page. Missed calls will also get logged here.
Please note: if the call widget is minimized but you're set to Available, you will still receive calls. If the call tab is closed during an ongoing call, the call will get disconnected.
supportsInboundCalling
is set to false by default. This extension setting gates users to the new inbound calling experience and instead shows the drag and drop call widget in record pages for outbound calling. Once you've set your app settings using the calling settings endpoint, use the PATCH endpoint to change supportsInboundCalling
to true to ungate users to the new inbound calling experience.
xxxxxxxxxx
curl --request PATCH \
--url 'https://api.hubapi.com/crm/v3/extensions/calling/APP_ID/settings?hapikey=DEVELOPER_ACCOUNT_API_KEY' \
--header 'accept: application/json' \
--header 'content-type: application/json' \
--data '{"supportsInboundCalling":true}'
Once the above steps are complete, you can continue to extend the functionality of your calling app in HubSpot by setting up third-party calling in help desk (BETA).