Unity Notion API returns 400 error when implementing pagination with start_cursor in database queries

I’m working with the Notion API in Unity and running into a pagination issue. When I query my database normally without any parameters, everything works fine. But when I try to use the start_cursor parameter to get the next page of results, I get a 400 Bad Request error.

The first request to the database works perfectly, but subsequent requests using the cursor from the previous response fail. I’m following the official API documentation for pagination but something seems wrong with my implementation.

Here’s my current code:

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

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

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

        string cursor = null;
        bool morePages = true;

        RequestLimiter limiter = new RequestLimiter(2);

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

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

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

            if (ParseHasMore(request.downloadHandler.text) == "false")
            {
                morePages = false;
            }
            else
            {
                cursor = ParseNextCursor(request.downloadHandler.text);
            }
        }
        success?.Invoke(combinedResults.ConvertAll(x => x.properties).ToArray());
    }
}

Any ideas what might be causing this 400 error on paginated requests?

I hit this same issue before. It’s definitely your request body structure, but there’s a tricky part with how you’re building the JSON payload. When you have a start_cursor, send it in the POST body as JSON, not as a URL parameter. Your CreateAuthenticatedRequest method probably doesn’t handle dynamic JSON body creation though. Here’s what I’d do - always send a JSON body. First request gets {}, subsequent ones get {“start_cursor”: “cursor_value”}. Make sure you’re setting Content-Type to application/json and encoding the JSON string properly. The 400 error happens because the API wants valid JSON in the body for all POST requests to that query endpoint.

Yeah, the issue is how you’re building the request. Claire29’s right about body vs URL parameters, but there’s more going on here. You’re making a POST request without setting the Content-Type header or sending any body data. The Notion API wants application/json and needs pagination parameters in the JSON body. Your CreateAuthenticatedRequest method probably just sets the auth header - you need to add the content type and include a proper JSON body with the start_cursor field. Even for the first request without pagination, send an empty JSON object instead of no body at all.

you’re passing the cursor as a URL parameter, but notion’s api wants it in the request body for post requests. put {“start_cursor”: “your_cursor_here”} in the post body instead of the url params.