Pagination using Search API

I have been trying to do a filtered contact search to return any contacts that have been updated in the past 24 hours. I have the code working to bring back a list of contacts, but if the number returned is over the limit parameter I’m not being given a link to the next page of records.

I’m using the hubspot-api-client package for Python. Here is my code:

import os
import logging
from datetime import datetime, timedelta
from dotenv import load_dotenv
from pathlib import Path
from hubspot import HubSpot
from hubspot.crm.contacts import ApiException, PublicObjectSearchRequest
from core.models import Person
from django.core.management.base import BaseCommand

dotenv_path = Path('../../app/.env')
load_dotenv(dotenv_path=dotenv_path)

ACCESS_TOKEN = os.getenv('HUBSPOT_ACCESS_TOKEN')

class Command(BaseCommand):
 help = 'Syncs Atlas profiles with Hubspot data'

 def handle(self, *args, **options):
 time_current = datetime.utcnow()
 time_24_hours_ago = time_current - timedelta(hours=24)
 time_24_hours_ago_ms = int(time_24_hours_ago.timestamp() * 1000)
 log_file = 'test.log'
 logging.basicConfig(filename=log_file, level=logging.INFO, format='%(asctime)s - %(levelname)s: %(message)s')

 client = HubSpot(access_token=ACCESS_TOKEN)
 public_object_search_request = PublicObjectSearchRequest(
 filter_groups=[
 {
 "filters": [
 {
 "value": time_24_hours_ago_ms,
 "propertyName": "lastmodifieddate",
 "operator": "GTE"
 }
 ]
 }
 ],
 properties=['firstname'],
 limit=1
 )
 try:
 api_response = client.crm.contacts.search_api.do_search(public_object_search_request=public_object_search_request)
 logging.info(api_response) 
 except ApiException as e:
 logging.error(f'An error occurred: {str(e)}', exc_info=True)
 print("Exception when calling search_api->do_search: %s\n" % e)

This all works fine and returns the expected amount of contacts, but the response I get literally has a “link” value of None, see below. I set the limit to one to keep this example short.

{'paging': {'next': {'after': '1', 'link': None}},
 'results': [{'archived': False,
 'archived_at': None,
 'created_at': datetime.datetime(2020, 4, 25, 15, 36, 26, 822000, tzinfo=tzlocal()),
 'id': '56313',
 'properties': {'createdate': '2020-04-25T15:36:26.822Z',
 'firstname': 'Chris',
 'hs_object_id': '56313',
 'lastmodifieddate': '2024-02-06T13:54:59.535Z'},
 'properties_with_history': None,
 'updated_at': datetime.datetime(2024, 2, 6, 13, 54, 59, 535000, tzinfo=tzlocal())}],
 'total': 40}

I have tried adding the “after” paramater like the documentation says but it does nothing. Also, the documentation says that param expects a string, but I get an error that it’s expecting an integer.

I tried in Hubspot as well and got the same thing.

Any ideas? I feel like this is just broken.

I have been trying to do a filtered contact search to return any contacts that have been updated in the past 24 hours. I have the code working to bring back a list of contacts, but if the number returned is over the limit parameter I’m not being given a link to the next page of records.

I’m using the hubspot-api-client package for Python. Here is my code:

import os
import logging
from datetime import datetime, timedelta
from dotenv import load_dotenv
from pathlib import Path
from hubspot import HubSpot
from hubspot.crm.contacts import ApiException, PublicObjectSearchRequest
from core.models import Person
from django.core.management.base import BaseCommand

dotenv_path = Path('../../app/.env')
load_dotenv(dotenv_path=dotenv_path)

ACCESS_TOKEN = os.getenv('HUBSPOT_ACCESS_TOKEN')

class Command(BaseCommand):
 help = 'Syncs Atlas profiles with Hubspot data'

 def handle(self, *args, **options):
 time_current = datetime.utcnow()
 time_24_hours_ago = time_current - timedelta(hours=24)
 time_24_hours_ago_ms = int(time_24_hours_ago.timestamp() * 1000)
 log_file = 'test.log'
 logging.basicConfig(filename=log_file, level=logging.INFO, format='%(asctime)s - %(levelname)s: %(message)s')

 client = HubSpot(access_token=ACCESS_TOKEN)
 public_object_search_request = PublicObjectSearchRequest(
 filter_groups=[
 {
 "filters": [
 {
 "value": time_24_hours_ago_ms,
 "propertyName": "lastmodifieddate",
 "operator": "GTE"
 }
 ]
 }
 ],
 properties=['firstname'],
 limit=1
 )
 try:
 api_response = client.crm.contacts.search_api.do_search(public_object_search_request=public_object_search_request)
 logging.info(api_response) 
 except ApiException as e:
 logging.error(f'An error occurred: {str(e)}', exc_info=True)
 print("Exception when calling search_api->do_search: %s\n" % e)

This all works fine and returns the expected amount of contacts, but the response I get literally has a “link” value of None, see below. I set the limit to one to keep this example short.

{'paging': {'next': {'after': '1', 'link': None}},
 'results': [{'archived': False,
 'archived_at': None,
 'created_at': datetime.datetime(2020, 4, 25, 15, 36, 26, 822000, tzinfo=tzlocal()),
 'id': '56313',
 'properties': {'createdate': '2020-04-25T15:36:26.822Z',
 'firstname': 'Chris',
 'hs_object_id': '56313',
 'lastmodifieddate': '2024-02-06T13:54:59.535Z'},
 'properties_with_history': None,
 'updated_at': datetime.datetime(2024, 2, 6, 13, 54, 59, 535000, tzinfo=tzlocal())}],
 'total': 40}

I have tried adding the “after” paramater like the documentation says but it does nothing. Also, the documentation says that param expects a string, but I get an error that it’s expecting an integer.

I tried in Hubspot as well and got the same thing.

Any ideas? I feel like this is just broken.

Hey, @jweiskittel :waving_hand: Thanks for your question and for including your details. Can you try a simplified version of your request using Postman? Do you get the same errors? If so, can you share the request, response, and the full error body here, please?

Thank you! — Jaycee

Jaycee, I was able to figure it out. Just a small error on my part. Thank you for your response.

Hi, I have the same problem, I can get maximum 100 records, as this is the maximum value for limit. But how to loop through all pages when the link is none?