Why isn't my HubSpot UI Extension making an API call on component mount?

I’m building a HubSpot UI extension using React. I want the extension to fetch deal data automatically when the component loads. Here’s a simplified version of my code:

import React, {useState, useEffect} from "react";
import {Text, Flex, hubspot} from "@hubspot/ui-extensions";

// Register extension
hubspot.extend(({context}) => <Extension context={context}/>);

const Extension = ({context}) => {
 const dealId = context?.crm?.objectId;
 const [properties, setProperties] = useState(null);
 const [contactIds, setContactIds] = useState([]);
 const [companyIds, setCompanyIds] = useState([]);

 useEffect(() => {
 const fetchDealData = async () => {
 try {
 const response = await hubspot.fetch(`https://api.hubapi.com/crm/v3/objects/0-3/${dealId}?properties=num_associated_contacts,no_of_rooms&associations=contacts,companies`,
 {
 method: "GET",
 });

 const data = await response.json();

 setProperties(data.properties);

 const companies =
 data.associations?.companies?.results.map((r) => r.id) || [];
 const contacts =
 data.associations?.contacts?.results.map((r) => r.id) || [];

 setCompanyIds([...new Set(companies)]);
 setContactIds(contacts);
 } catch (error) {
 console.error("Error fetching deal data:", error);
 }
 };

 if (dealId) {
 fetchDealData();
 }
 }, [dealId]); // Run once when dealId is available

 return (
 <Flex direction="column" gap="medium">
 <Text>Deal Data (Loaded on Mount)</Text>

 {properties ? (
 <Flex direction="column" gap="small">
 <Text>Created At: {properties.createdate}</Text>
 <Text>Contacts: {contactIds.join(", ")}</Text>
 <Text>Companies: {companyIds.join(", ")}</Text>
 </Flex>
 ) : (
 <Text>Loading...</Text>
 )}
 </Flex>
 );
};

The link is added in the permittedUrls section

"permittedUrls": {
 "fetch": [
 "https://api.hubapi.com"
 ],
 "iframe": [],
 "img": []
 },

Hi @NVaniyanValap, I hope that you are well!
Thanks for reaching out to the HubSpot Community!
I’d love to put you in touch with our Top Experts: Hi @LauraMarie, @GRajput and @MichaelMa do you have suggestions to help @NVaniyanValap, please?
Have a lovely weekend and thanks so much!
Bérangère

Hi @NVaniyanValap

I suggest making your permitted URLs more specific, like:

“permittedUrls”: {
“fetch”: [
“https://api.hubapi.com/crm/v3/objects/*”,
“https://api.hubapi.com/crm/*”
],
“iframe”: [],
“img”: []
}

Also verify that your required scopes in the .yml are there:

- crm.objects.deals.read, crm.objects.contacts.read, crm.objects.companies.read, crm.associations.read

Alternatively, the context timing might be an issue if the context is not immediately available when the component mounts. You could add a check like:

useEffect(() => {
const fetchDealData = async () => {
console.log(“Attempting to fetch deal data for ID:”, dealId); // Debug log
try {
const response = await hubspot.fetch(
`https://api.hubapi.com/crm/v3/objects/0-3/${dealId}?properties=num_associated_contacts,no_of_rooms&associations=contacts,companies`,
{
method: “GET”,
}
);

if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}

const data = await response.json();
console.log(“Fetched data:”, data); // Debug log

setProperties(data.properties);
// … rest of your logic
} catch (error) {
console.error(“Error fetching deal data:”, error);
}
};

// Add more robust checking
if (dealId && context?.crm?.objectId) {
console.log(“Context and dealId available:”, { dealId, context }); // Debug log
fetchDealData();
} else {
console.log(“Missing dealId or context:”, { dealId, context }); // Debug log
}
}, [dealId, context]); // Add context as dependency

Lastly, there is an option to use HubSpot’s CRM API methods instead of a direct fetch.

Let us know how it goes.

Hi,

I’m encountering the following error in the logs while running an app card on my developer test account:

{ "status": "error", "message": "Hub 146840846 is unknown to this Hublet, but it appears to exist in Hublet eu1", "correlationId": "01f3c7f0-4088-4425-9f81-df8504651430", "correctHublet": "eu1" }

It seems to be a hublet mismatch issue. Has anyone experienced this before, or can anyone advise how to resolve it?
and if if you could tell me about the HubSpot’s CRM API methods instead of a direct fetch. even for associated contacts and companies details with the deal taht would be helpful.
Thank you

@LauraMarie@BérangèreL

Could you help guide me on how to solve this?

For context, I’m using OAuth for authentication.

Hi @NVaniyanValap, thanks for getting back to me and sharing the error message!
Did you double-check the base URL in your API requests to ensure it matches the hublet where your account is hosted?
I’d love to check with our Top Experts: Hi @sylvain_tirreau, @Anton and @Mike_Eastwood do you have other suggestions to help @NVaniyanValap, please?
Have a great day and thanks so much in advance for your help!
Bérangère

Hi,

Ty to replace:

const response = await hubspot.fetch(https://api.hubapi.com/crm/v3/objects/0-3/${dealId}?properties=num_associated_contacts,no_of_rooms&associations=contacts,companies`, {method: “GET”,});`

By something like that:

const res = await hubspot.fetch(/crm/v3/objects/deals/${dealId}?properties=num_associated_contacts,no_of_rooms&associations=contacts,companies,{ method: "GET" });

It seems that hubspot.fetch is proxied by Hubspot and can route to the current portal hublet if you use a relative path.