API Pagination Guidelines¶
Introduction¶
Without pagination, a simple search could return millions or even billions of records. Most endpoints that return a list of entities need to support some form of pagination. A server MAY choose to limit the number of resources returned in a response to a subset ("page") of the whole set available.
Pagination links [600]¶
A server MAY provide links to traverse a paginated data set ("pagination links").
Pagination links SHOULD appear in the top-level links object.
Pagination links MUST preserve sorting and filtering.
If pagination links are used, then the naming conventions for the link names (keys) MUST be followed:
- first: the first page of data
- last: the last page of data
- prev: the previous page of data
- next: the next page of data
Here is an example with a pagination key.
{
  "links": {
    "next": "https://api.bx.com/buildings?cursor=cXdlcnR5"
  },
  "data": [
    {
      "id": "12345",
      "type": "Building",
      ...
    }
    ...
  ]
}
Pagination strategies [601]¶
Pagination SHOULD be implemented using query parameters. The following topics describe different pagination strategies.
Cursor based strategy [601.1]¶
Cursor-based pagination is useful for server implementations based on NoSQL databases or when backends join data from multiple data sources.
When using cursor-based pagination, the following two parameter names SHOULD be used:
- cursoris an opaque identifier that only the server understands.
- limitis used for the requested maximum page size.
The server MAY return an empty page containing a next-link if that is necessary for scalability and performance reasons.
GET /buildings HTTP/1.1
{
  "links": {
    "self": "https://api.bx.com/buildings",
    "next": "https://api.bx.com/buildings?cursor=cXdlcnR5"
  },
  "data": [
    {
      "id": "12345",
      "type": "Building",
      ...
    }
    ...
  ]
}
GET /buildings?cursor=cXdlcnR5&limit=50 HTTP/1.1
{
  "links": {
    "self": "https://api.bx.com/buildings?cursor=cXdlcnR5&limit=50"
  },
  "data": [
    {
      "id": "45678",
      "type": "Building",
      ...
    }
    ...
  ]
}
Server MAY provide pagination meta information to the API client [601.1.1]¶
The server MAY provide information about the nextCursor that is required to fetch the next page in the meta.page.nextCursor property. It should be a string.
{
  "meta": {
    "page": {
      "nextCursor": "cXdlcnR5"
    }
  }
}
Offset based strategy [601.2]¶
Offset-based pagination MAY be used for servers that can skip records efficiently while also calculating the total number of records, such as SQL-based services.
When using offset-based pagination, the following two parameter names SHOULD be used:
- offsetis an integer representing the elements of records to skip when responding.
- limitis used for the requested maximum page size.
GET /buildings?limit=100 HTTP/1.1
{
  "links": {
    "self": "https://api.bx.com/buildings?limit=100",
    "next": "https://api.bx.com/buildings?limit=100&offset=100"
  },
  "meta": {
    "page": {
      "totalElements": 101,
      "offset": 0,
      "elements": 100
    }
  },
  "data": [
    {
      "id": "12345",
      "type": "Building",
      ...
    }
    ...
  ]
}
GET /buildings?limit=100&offset=100 HTTP/1.1
{
  "links": {
    "self": "https://api.bx.com/buildings?limit=100&offset=100"
  },
  "meta": {
    "page": {
      "totalElements": 101,
      "offset": 100,
      "elements": 1
    }
  }
  "data": [
    {
      "id": "45678",
      "type": "Building",
      ...
    }
  ]
}
Server MAY provide pagination meta information to the API client [601.2.1]¶
The following meta information SHOULD be used:
- meta.page.totalElementstotal number of elements.
- meta.page.offsetcurrent offset.
- meta.page.elementsnumber of records in the current page.
The meta information can be useful for rendering custom paging controls in the API client, for example, in a "data grid" or table where the user wants to skip to an arbitrary page.
{
  "meta": {
    "page": {
      "totalElements": 101,
      "offset": 100,
      "elements": 1
    }
  }
}
Index based strategy [601.3]¶
Index-based pagination MAY be used for servers that can skip records efficiently while also calculating the total number of records, such as SQL based services. It is similar to offset-based pagination but is commonly used when page sizes are not flexible.
When using index-based pagination, the following two parameter names SHOULD be used:
- numberis an integer representing the page-number to fetch.
- sizeis used for the requested maximum page size.
GET /buildings?size=100 HTTP/1.1
{
  "links": {
    "self": "https://api.bx.com/buildings?size=100",
    "next": "https://api.bx.com/buildings?size=100&number=2",
    "last": "https://api.bx.com/buildings?size=100&number=3",
    "first": "https://api.bx.com/buildings?size=100"
  },
  "meta": {
    "page": {
      "totalPages": 3,
      "number": 1,
      "elements": 100
    }
  }
  "data": [
    {
      "id": "12345",
      "type": "Building",
      ...
    }
    ...
  ]
}
GET /buildings?size=100&number=3 HTTP/1.1
{
  "links": {
    "self": "https://api.bx.com/buildings?size=100&number=3",
    "last": "https://api.bx.com/buildings?size=100&number=3",
    "first": "https://api.bx.com/buildings?size=100",
    "prev": "https://api.bx.com/buildings?size=100&number=2"
  },
  "meta": {
    "page": {
      "totalPages": 2,
      "number": 3,
      "size": 100,
      "elements": 1
    }
  },
  "data": [
    {
      "id": "45678",
      "type": "Building",
      ...
    }
  ]
}
Server MAY provide pagination meta information to the API client [601.3.1]¶
The following meta information SHOULD be used:
- meta.page.totalPagesis an integer representing the total number of pages.
- meta.page.numberis an integer representing the current page number.
- meta.page.sizeis an integer representing the page size.
The following meta information MAY be used:
- meta.page.elementsis an integer representing the number of records returned in the current page.
- meta.page.totalElementsis an integer representing the total number of elements.
The meta information can be useful for rendering custom paging controls in the API client, such as in a "data grid" or table where the user wants to skip to an arbitrary page.
{
  "meta": {
    "page": {
      "totalPages": 2,
      "number": 2,
      "size": 100,
      "elements": 1,
      "totalElements": 101
    }
  }
}
Note
JSON:API introduces query parameter families. When using JSON:API, query parameters like page[number] and page[size] should be used instead of just number and size. Then the parameters are compliant with the JSON:API pagination specification. But the names within the square brackets like number and size must comply with this guideline.