PageSourceSearch

https://www.intapp.com/wp-content/plugins/intapp-hubspot/js/hubspotAPICalls.js

js intapp.com collected 2026-10-09 21:41:43 UTC 8,189 bytes, 275 lines download raw bytes

1// === AJAX CALLS TO HUBSPOT API === //
2
3/**
4 * Fetches contact data from HubSpot API
5 * @param {string} email
6 * @returns {Promise<Object|null>}
7 */
8export async function getHsptContactData(email) {
9    if (!email) return;
10
11    let response = await fetch(`${ajax_object.ajaxurl}`, {
12        method: 'POST',
13        headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
14        body: new URLSearchParams({
15            action: 'get_contact_by_email_ajax',
16            email: email,
17            nonce: ajax_object?.nonce || ''
18        })
19    });
20
21    // properly parse the JSON body
22    const {status, data} = await response.json();
23
24    // if contact not found, return null
25    if (status === "error") {
26        console.error("Error fetching contact data. Status:", status);
27        return null;
28    }
29
30    // return the contact data
31    return {
32        id: data?.vid || "",
33        email,
34        cda: data["associated-company"]?.properties?.cda?.value || "",
35        owner: data.properties?.hubspot_owner_id?.value || "",
36        ip_country: data.properties?.ip_country?.value || "",
37        headquarters: data["associated-company"]?.properties?.country?.value || ""
38    };
39}
40
41/**
42 * Sets the sentiment for a contact's message
43 * @param {string} email
44 * @param {string} sentiment
45 * @returns {Promise<void>}
46 */
47export function setContactMessageSentiment(email, sentiment) {
48    if (!email || !sentiment) return;
49
50    // fire and forget. No need to wait
51    fetch(`${ajax_object.ajaxurl}`, {
52        method: 'POST',
53        headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
54        body: new URLSearchParams({
55            action: 'update_hubspot_contact_sentiment',
56            email: email,
57            sentiment: sentiment,
58            nonce: ajax_object?.nonce || ''
59        })
60    }).catch(err => console.error('Failed to update sentiment:', err));
61}
62
63
64/**
65 * Get the company associations for a contact
66 * @param {string} contactId
67 * @returns {Promise<Array>|<Array>|<Error>} Company associations
68 */
69export const getContactCompanyAssociations = async (contactId) => {
70    if (!contactId) {
71        console.error('Missing contactId');
72        return [];
73    }
74    if (!isAjaxDefined()) return [];
75
76    const resp = await fetch(`${ajax_object?.ajaxurl}`, {
77        method: 'POST',
78        headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
79        body: new URLSearchParams({
80            action: 'get_contact_company_associations',
81            contact_id: contactId,
82            nonce: ajax_object?.nonce || ''
83        })
84    });
85
86    const result = await resp.json();
87
88    if (!resp.ok || result.status === 'error') {
89        throw new Error(result.message || 'Failed to fetch company associations');
90    }
91
92    return Array.isArray(result.data) ? result.data : [];
93};
94
95
96/**
97 * Search for companies based on filters
98 * @param {Object} filters { propertyName: 'domain', operator: 'EQ', value: ${domain} }
99 * @param {number} limit
100 * @param {string} after
101 * @returns {Promise<Object>} Search results
102 */
103export const searchCompanies = async (filters, limit = 2, after = undefined) => {
104    if (!isAjaxDefined()) return;
105
106    const resp = await fetch(`${ajax_object.ajaxurl}`, {
107        method: 'POST',
108        headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
109        body: new URLSearchParams({
110            action: 'search_companies',
111            filters: JSON.stringify(filters),
112            limit,
113            after,
114            nonce: ajax_object?.nonce || ''
115        })
116    });
117
118    const json = await resp.json();
119    if (!resp.ok || !json?.data) {
120        throw new Error(`Search API ${resp.status}: ${JSON.stringify(json)}`);
121    }
122
123    const { data } = json;
124    const total = typeof data.total === 'number'
125        ? data.total
126        : (Array.isArray(data.results) ? data.results.length : 0);
127
128    return { total, results: data.results || [], paging: data.paging };
129};
130
131
132/**
133 * Get company properties by ID
134 * @param {string} companyId
135 * @returns {Promise<Object>} Company properties
136 */
137export const getCompanyPropsById = async (companyId) => {
138    if (!companyId) {
139        console.error('Missing companyId');
140        return {};
141    }
142    if (!isAjaxDefined()) return {};
143
144    const resp = await fetch(`${ajax_object.ajaxurl}`, {
145        method: 'POST',
146        headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
147        body: new URLSearchParams({
148            action: 'get_company_props_by_id',
149            company_id: companyId,
150            nonce: ajax_object?.nonce || ''
151        })
152    });
153
154    const result = await resp.json();
155
156    if (!resp.ok || result.status === 'error') {
157        throw new Error(result.message || 'Failed to fetch company properties');
158    }
159
160    return result.data;
161};
162
163
164/**
165 * Remove company associations for a contact
166 * @param {string} contactId
167 * @param {Array<string>} companyIds
168 * @returns {Promise<Object>} API response
169 */
170export const removeAssociations = async (contactId, companyIds = []) => {
171    if (!contactId || !companyIds.length) return;
172    if (!isAjaxDefined()) return;
173
174    const resp = await fetch(`${ajax_object.ajaxurl}`, {
175        method: 'POST',
176        headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
177        body: new URLSearchParams({
178            action: 'remove_company_associations',
179            contact_id: contactId,
180            company_ids: JSON.stringify(companyIds),
181            nonce: ajax_object?.nonce || ''
182        })
183    });
184
185    const result = await resp.json();
186
187    if (!resp.ok || result.status === 'error') {
188        throw new Error(result.message || 'Failed to remove associations');
189    }
190
191    return result.data; // { companyId: 'deleted' | 'error message', ... }
192};
193
194
195/**
196 * Ensure company association for a contact
197 * @param {string} contactId
198 * @param {string} companyId
199 * @returns {Promise<Object>} API response
200 */
201export const ensureAssociation = async (contactId, companyId) => {
202    if (!contactId || !companyId) {
203        console.error('Missing contactId or companyId');
204        return;
205    }
206    if (!isAjaxDefined()) return;
207
208    const resp = await fetch(`${ajax_object.ajaxurl}`, {
209        method: 'POST',
210        headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
211        body: new URLSearchParams({
212            action: 'ensure_company_association',
213            contact_id: contactId,
214            company_id: companyId,
215            nonce: ajax_object?.nonce || ''
216        })
217    });
218
219    const result = await resp.json();
220
221    if (!resp.ok || result.status === 'error') {
222        throw new Error(result.message || 'Failed to ensure association');
223    }
224
225    return result.data.status; // HTTP status code from HubSpot API
226};
227
228
229/**
230 * Set primary company for a contact
231 * @param {string} contactId
232 * @param {string} companyId
233 * @returns {Promise<Object>} API response
234 */
235export const setPrimaryCompany = async (contactId, companyId, cdaId) => {
236    if (!contactId || !companyId || !cdaId) {
237        console.error('Missing contactId or companyId or cdaId');
238        return;
239    }
240    if (!isAjaxDefined()) return;
241
242    const resp = await fetch(`${ajax_object.ajaxurl}`, {
243        method: 'POST',
244        headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
245        body: new URLSearchParams({
246            action: 'set_primary_company',
247            contact_id: contactId,
248            company_id: companyId,
249            cda_id: cdaId,
250            nonce: ajax_object?.nonce || ''
251        })
252    });
253
254    const result = await resp.json();
255
256    if (!resp.ok || result.status === 'error') {
257        throw new Error(result.message || `Failed to set primary company`);
258    }
259
260    return result.data; // { status: HTTP status code, hubspot_owner_id: 'owner id' }
261};
262
263/**
264 * Checks if the AJAX object is defined
265 * pre: ajax_object must be globally available (localized by WordPress)
266 * post: logs error if not defined
267 * @returns {boolean}
268 */
269const isAjaxDefined = () => {
270    if (typeof ajax_object?.ajaxurl === 'undefined') {
271        console.error('ajaxurl not defined. This must be localized by WordPress.');
272        return false;
273    }
274    return true;
275};

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.