Getting 400 Error When Implementing Pagination with start_cursor in Notion Database API Call

I’m working on fetching data from my Notion database using Unity. Since the API limits results to 100 items per request, I need to implement pagination using the start_cursor parameter to retrieve all records.

The first request to https://api.notion.com/v1/databases/{databaseID}/query works perfectly fine. However, when I try to make subsequent requests using the cursor from the previous response, I get a HTTP/1.1 400 Bad Request error.

I’m collecting all responses in a list and continuing until no more pages exist. The logic seems correct to me, but something is causing the API to reject my paginated requests.

Here’s my implementation:

public class DatabaseManager<T> : APIClient where T : IPropertyType, new()
{
    public DatabaseManager(string token, string dbId) : base(token)
    {
        DatabaseId = dbId;
        QueryEndpoint = $"https://api.notion.com/v1/databases/{dbId}/query";
    }

    private readonly string DatabaseId;
    private readonly string QueryEndpoint;
    private DatabaseResult<T> Response;

    public virtual async void Fetch(Action<T[]> success = null, Action<string> error = null)
    {
        List<DatabaseItem<T>> combinedResults = new();

        string cursorToken = null;
        bool morePages = true;

        RequestThrottler throttler = new RequestThrottler(2);

        while (morePages)
        {
            await throttler.WaitAsync();

            string requestUrl = string.IsNullOrEmpty(cursorToken) ? QueryEndpoint : QueryEndpoint + $"?start_cursor={cursorToken}";
            Debug.Log(requestUrl);

            using var request = CreateAuthenticatedRequest(requestUrl, RequestMethod.POST);
            request.SendWebRequest();
            while (!request.isDone)
            {
                await Task.Yield();
            }
            if (request.result != UnityWebRequest.Result.Success)
            {
                Debug.Log($"Fetch operation for {DatabaseId} failed ({request.error}).");
                error?.Invoke(request.error);
                return;
            }
            Response = JsonUtility.FromJson<DatabaseResult<T>>(request.downloadHandler.text);
            combinedResults.AddRange(Response.results);

            if (ExtractHasMoreFlag(request.downloadHandler.text) == "false")
            {
                morePages = false;
            }
            else
            {
                cursorToken = ExtractCursorToken(request.downloadHandler.text);
            }
        }
        success?.Invoke(combinedResults.ConvertAll(item => item.properties).ToArray());
    }
}

Any ideas why the pagination requests are failing?

The problem is how you’re building the paginated requests. I ran into this exact issue in my Unity project. The start_cursor parameter needs to go in the POST request body, not tacked onto the URL as a query parameter. You’re modifying the URL, but Notion’s database query endpoint wants everything in the JSON payload. Keep your requestUrl the same and put the start_cursor in the request body instead. Serialize an object with the start_cursor field and set it as the request body using request.uploadHandler. Make sure your Content-Type header is application/json for all requests.

You’re passing the start_cursor wrong. For Notion’s API, the start_cursor goes in the POST body as JSON, not in the URL. You’re treating it like a GET request by adding it to the URL.

Don’t modify the URL at all - keep the endpoint the same for every request. Instead, put the cursor in your JSON payload like {“start_cursor”: “your_cursor_value”}.

I made this exact mistake when I first worked with Notion’s pagination. Their docs are confusing since most APIs use URL parameters for pagination, but Notion wants everything in the POST body.

yeah, i had the same prob. notion api can be tricky, just put the start_cursor in the body as json and not in the url, like {“start_cursor”: “your_cursor_value”}. also, dont forget the content-type header as application/json!