Best practices

Good morning,

I have the following use case: we have around 100,000 deals, and we need to retrieve those that have been modified (along with their associations) in the last 15 minutes.

From what I’ve seen, it seems that the only way to find the most recent ones is by using the Search API, but that doesn’t return the associations.

So, the only alternatives I can think of are:

  • Using the list method from the Basic API, which would require around 960 calls, or
  • Using the IDs from the first call and making between 1 and 100,000 calls to the get method from the Basic API.

Is there a more efficient way to do this?
Does the Search API have any option to include associations?
Or does the List API allow filtering by IDs, similar to the Batch API?

Thank you very much for your help.

Great question! For retrieving 100,000 deals modified in the last 15 minutes WITH associations, here’s the most efficient approach:

**Best Solution: Search API with filterGroups**

The Search API is actually the right choice, and YES - it CAN return associations! Here’s how:

```
POST /crm/v3/objects/deals/search
{
“filterGroups”: [{
“filters”: [{
“propertyName”: “hs_lastmodifieddate”,
“operator”: “GTE”,
“value”: “{{timestamp_15_min_ago}}”
}]
}],
“properties”: [“dealname”, “amount”, “closedate”],
“associations”: [“contacts”, “companies”],
“limit”: 100
}
```

**Key points:**
• Use the `associations` parameter in your Search API request
• Set `limit: 100` and paginate through results using `after` token
• Much more efficient than 960+ Basic API calls
• Returns deals AND their associations in one go

**Why this beats your alternatives:**
• **vs Basic API list method**: Search API filters server-side (way faster)
• **vs get + 100k calls**: You’d hit rate limits and waste time
• **vs Batch API**: Still requires you to know which IDs to fetch first

**Pro tip:** If you need this regularly, consider using webhooks to get notified when deals are modified instead of polling every 15 minutes!

Happy to help you implement this if you need code examples.

:backhand_index_pointing_right:

Certified in HubSpot Search API, Deals API & Integrations

HubSpotコミュニティー #SearchAPI #DealsAPI associations #APIOptimization

Hello I tried your solution but

I’ve checked your suggested solution in the documentation, but I couldn’t find the associations parameter in the Search API.
I’ve also tested it both via an HTTP request and using the JavaScript SDK.

Here’s the code:

async function search1() {
 const client = new Client({ accessToken });
 const body = {
 "filterGroups": [{
 "filters": [{
 "propertyName": "hs_object_id",
 "operator": "EQ",
 "value": "43230655641"
 }]
 }],
 "properties": ["dealname", "amount", "closedate"],
 "associations": ["contacts", "companies"],
 "limit": 100
 }
 const resp = await client.crm.deals.searchApi.doSearch(body);
 const { results, paging, ...rest } = resp
 console.log(results)
}

async function search2() {
 const url = 'https://api.hubapi.com/crm/v3/objects/0-3/search';
 const options = {
 method: 'POST',
 headers: {
 Authorization: `Bearer ${accessToken}`,
 'Content-Type': 'application/json'
 },
 body: JSON.stringify({
 "filterGroups": [{
 "filters": [{
 "propertyName": "hs_object_id",
 "operator": "EQ",
 "value": "43230655641"
 }]
 }],
 "properties": ["dealname", "amount", "closedate"],
 "associations": ["contacts", "companies", "line_items"],
 "limit": 200
 })
 };

 const response = await fetch(url, options);
 const { results, paging, ...rest } = await response.json();
 console.log(results)
}

async function works() {
 const client = new Client({ accessToken});
 const resp = await client.crm.deals.basicApi.getById(43230655641, [],[], ["contacts", "companies", "line_items"]);
 console.log(resp)
}

search1() //sdk search api no assoc

// [
// SimplePublicObject {
// createdAt: 2025-09-01T11:41:53.093Z,
// archived: false,
// id: '43230655641',
// properties: {
// amount: '6572.81',
// closedate: '2025-11-30T11:38:12.791Z',
// createdate: '2025-09-01T11:41:53.093Z',
// dealname: 'Intimus International ⭐ Renewal',
// hs_lastmodifieddate: '2025-11-13T10:00:49.886Z',
// hs_object_id: '43230655641'
// },
// updatedAt: 2025-11-13T10:00:49.886Z
// }
// ]

search2() //http search api no assoc

// [
// {
// id: '43230655641',
// properties: {
// amount: '6572.81',
// closedate: '2025-11-30T11:38:12.791Z',
// createdate: '2025-09-01T11:41:53.093Z',
// dealname: 'Intimus International ⭐ Renewal',
// hs_lastmodifieddate: '2025-11-13T10:00:49.886Z',
// hs_object_id: '43230655641'
// },
// createdAt: '2025-09-01T11:41:53.093Z',
// updatedAt: '2025-11-13T10:00:49.886Z',
// archived: false,
// url: 'https://app.hubspot.com/contacts/9471187/record/0-3/43230655641'
// }
// ]

works() // basci api get with assoc

// SimplePublicObjectWithAssociations {
// associations: {
// companies: CollectionResponseAssociatedId { results: [Array] },
// 'line items': CollectionResponseAssociatedId { results: [Array] },
// contacts: CollectionResponseAssociatedId { results: [Array] }
// },
// createdAt: 2025-09-01T11:41:53.093Z,
// archived: false,
// id: '43230655641',
// properties: {
// amount: '6572.81',
// closedate: '2025-11-30T11:38:12.791Z',
// createdate: '2025-09-01T11:41:53.093Z',
// dealname: 'Intimus International ⭐ Renewal',
// dealstage: '44299820',
// hs_lastmodifieddate: '2025-11-13T10:00:49.886Z',
// hs_object_id: '43230655641',
// pipeline: '17469980'
// },
// updatedAt: 2025-11-13T10:00:49.886Z
// }

The are something wrong in te assoc param?

I’ve considered using webhooks, but I can’t receive the full deal information when a property is modified — I have to select each property individually.
Also, it’s not possible to trigger a webhook when the last modified date of a HubSpot deal is updated.

On the other hand, I tested the webhook for deal deletion, and the body we receive is empty.
When running the test webhook it works fine, but in the actual environment it fails.

thanx

Hey @JorgeTwenix :waving_hand: Thank you for the great post. I don’t think you are doing anything wrong. Your analysis is correct about the limitations with the Search API and it not returning associations the way you want. The documentation offers `pseudo-associations" as an option but not associations the way you need it to be returned.

The current approach to solve your problem is a two-step process that uses the Search API and the v4 Associations API together. I’ve also seen folks leverage GraphQL to make unified requests when their portal has access — Query HubSpot data using GraphQL.

Best,

Jaycee

Hi @JorgeTwenix

You’re not missing anything. The associations parameter is only supported on GET by ID and Batch Read, not on the Search API.

The Search endpoint will silently ignore that field, which is exactly what you’re seeing in both your SDK test and the raw HTTP call. HubSpot calls these “pseudo associations,” and they only apply to native joins like owner or pipeline, not object to object associations (Search the CRM - HubSpot docs )

That leaves you with the only scalable pattern for high volume incremental fetches: search for the modified IDs, then pull associations in a second step using the v4 Associations API. Jaycee’s reply is right on that point. For deletion events and incremental updates, HubSpot’s docs explain why the object must be rehydrated manually after the webhook fires because the webhook payload is intentionally minimal (How to Trigger Webhooks in HubSpot Contact-Based Workflows )

A quick question. Do you need this fifteen minute delta because another platform is also writing to deals? If so, Stacksync keeps those bidirectional updates aligned in real time and removes the need for heavy polling cycles. Hope this helps