I’m having trouble with the Notion API when I try to get large amounts of data from a database. Everything works fine when I fetch up to 300 records, but anything beyond that gives me a “PayloadTooLargeError” message.
I know that Notion limits each request to 100 items, so I’m using pagination with cursors to get multiple pages. My code successfully processes the first three pages (300 total items), but then it fails with this error:
{'errorId': 'abc123-def4-5678-90gh-ijklmnopqrst',
'name': 'PayloadTooLargeError',
'message': 'Request body too large.'}
Here’s the function I’m using to handle pagination:
def fetch_more_pages(response_data):
api_url = f"https://api.notion.com/v1/databases/{database_id}/query"
cursor = response_data['next_cursor']
try:
while response_data['has_more']:
response_data['start_cursor'] = cursor
payload = json.dumps(response_data)
# Fetch next batch of 100 items
new_response = requests.post(
api_url, headers=request_headers, data=payload).json()
response_data["results"] += new_response["results"]
cursor = new_response['next_cursor']
if cursor is None:
break
except:
pass
return response_data
Is there actually a hard limit of 300 records in Notion API? Has anyone found a way to retrieve larger datasets without hitting this error?
Yeah, ran into this exact issue last month with a huge content database. You’re cramming all your previous results into every new request, which bloats it massively. Just pass the cursor and original query - ditch the whole response_data object. Notion doesn’t need your accumulated results to fetch the next page.
This isn’t a Notion record limit issue - you’re accidentally sending your entire accumulated response back in each new request. Each page makes your payload exponentially bigger. The culprit is this line: payload = json.dumps(response_data). By your fourth request, you’re cramming 300 records into the request body, which blows past the size limit. For pagination, you only need the cursor and your original query params. Build a fresh payload each time with just the start_cursor and original filters - don’t reuse the response object. I’ve hit this same trap with paginated APIs. It’s super easy to mix up request data with response accumulation if you’re not careful.
You’re passing the entire response_data object as your payload, which includes all the results you’ve already fetched. Each iteration makes your request body bigger until it hits the size limit. Don’t reuse response_data as your payload. Create a clean request body for each call instead - something like payload = json.dumps({'start_cursor': cursor}) plus whatever filters you originally had. I hit this same issue last year pulling from a huge project database. Fixed it by keeping my data collection separate from the pagination requests. Collect your results in one place, but only send the pagination params in your API calls.