Select programming language for code examples

linkPagination

All top-level API resources have support for bulk fetches via "list" API methods. For instance you can list users, list licenses, and list machines. These list API methods share a common format, taking an optional page query parameter.

Our API utilizes a cursor-based pagination strategy (also known as "keyset" pagination) via the page[size] and page[cursor] parameters. The cursor is the ID of the last record you received, and the API will return the next set of records after that ID (exclusive). To fetch the first page, omit the page[cursor] parameter or pass an empty value.

To paginate through an entire result set:

  1. Make an initial request to a resource list with the page[size] parameter set to your desired page size and the page[cursor] parameter set to an empty value.
  2. Check the response's links object. If a links.next URI is present, more results may be available on the next page. If the links.next property is null, you've reached the end of the result set.
  3. Follow the links.next URI, or use the ID of the last record in the current data array as the page[cursor] for your next request.
  4. Repeat step 2 and 3 until links.next is null, or until the data array is empty, both of which indicate you've reached the end of the requested result set.

All results are returned in reverse chronological order.

We also support an offset-based strategy via the page[number] parameter, but offset-based pagination can become slow on large datasets, and worse, correctness issues can arise when paginating across many pages, e.g. records created or deleted between requests can cause duplicate or even missing results. As such, we've deprecated the offset-based pagination strategy in favor of the cursor-based strategy, outlined above.

linkQuery parameters

  • linkpage

    object<string, integer | string>

    Object containing page size and page cursor, or page size and page number.

  • linkpage[size]

    integerdefault=10

    The page size. Must be a number between 1 and 100.

  • linkpage[cursor]

    string

    The page cursor. Must be the UUID of a resource, representing the starting point of the page (exclusive), or an empty string.

    For most cases, navigating pages will start with an empty cursor, then the ID of the last record in your current result set should be used as the cursor for the next request. You can also follow the links.next URI provided in each response.
    /v1/accounts/<account>/licenses?page[cursor]=
  • linkpage[number]

    integerdeprecatedThis param has been deprecated and its use is no longer recommended.

    The page number. Must be a number between 1 and 100.

    Offset-based pagination has been deprecated and has been limited to a maximum of 100 pages. Please use cursor-based pagination.

Example request

const fetch = require("node-fetch")
 
const response = await fetch("https://api.keygen.sh/v1/accounts/<account>/users?page[size]=25&page[cursor]=4a3eb389-5742-49f2-92f8-29347196a265", {
method: "GET",
headers: {
"Accept": "application/vnd.api+json",
"Authorization": "Bearer <token>"
}
})
 
const { data, links, errors } = await response.json()
import requests
import json
 
res = requests.get(
"https://api.keygen.sh/v1/accounts/<account>/users?page[size]=25&page[cursor]=4a3eb389-5742-49f2-92f8-29347196a265",
headers={
"Accept": "application/vnd.api+json",
"Authorization": "Bearer <token>"
}
).json()
import SwiftyJSON
import Alamofire
 
Alamofire.request("https://api.keygen.sh/v1/accounts/<account>/users?page[size]=25&page[cursor]=4a3eb389-5742-49f2-92f8-29347196a265",
headers: [
"Accept": "application/vnd.api+json",
"Authorization": "Bearer <token>"
]
).responseJSON { response in
let json = JSON(data: response.data!)
}
using RestSharp;
 
var client = new RestClient("https://api.keygen.sh/v1/accounts/<account>");
var request = new RestRequest("users", Method.GET);
 
request.AddHeader("Accept", "application/vnd.api+json");
request.AddHeader("Authorization", "Bearer <token>");
 
request.AddParameter("page[size]", 25);
request.AddParameter("page[cursor]", "4a3eb389-5742-49f2-92f8-29347196a265");
 
var response = client.Execute(request);
import com.mashape.unirest.http.exceptions.*
import com.mashape.unirest.http.*
 
val res = Unirest.get("https://api.keygen.sh/v1/accounts/<account>/users")
.header("Authorization", "Bearer <token>")
.header("Accept", "application/vnd.api+json")
.queryString("page[size]", 25)
.queryString("page[cursor]", "4a3eb389-5742-49f2-92f8-29347196a265")
.asJson()
import com.mashape.unirest.http.exceptions.*;
import com.mashape.unirest.http.*;
 
HttpResponse<JsonNode> res = Unirest.get("https://api.keygen.sh/v1/accounts/<account>/users")
.header("Authorization", "Bearer <token>")
.header("Accept", "application/vnd.api+json")
.queryString("page[size]", 25)
.queryString("page[cursor]", "4a3eb389-5742-49f2-92f8-29347196a265")
.asJson();
#include <iostream>
#include <string>
#include <cpprest/http_client.h>
#include <cpprest/filestream.h>
 
using namespace std;
using namespace web;
using namespace web::http;
using namespace web::http::client;
using namespace utility;
 
http_client client("https://api.keygen.sh/v1/accounts/<account>");
http_request req;
 
req.headers().add("Authorization", "Bearer <token>");
req.headers().add("Accept", "application/json");
 
uri_builder uri("/users");
uri.append_query("page[size]", 25);
uri.append_query("page[cursor]", "4a3eb389-5742-49f2-92f8-29347196a265");
 
req.set_request_uri(uri.to_uri());
req.set_method(methods::GET);
 
client.request(req)
.then([](http_response res) {
auto data = res.extract_json().get();
})
.wait();
curl 'https://api.keygen.sh/v1/accounts/<account>/users?page[size]=25&page[cursor]=4a3eb389-5742-49f2-92f8-29347196a265' -g \
-H 'Accept: application/vnd.api+json' \
-H 'Authorization: Bearer <token>'

Example response

{
"data": [
{
"id": "6ed498fe-5f5f-49af-82ee-cb7400cc4522",
"type": "users",
"links": {
"self": "/v1/accounts/<account>/users/6ed498fe-5f5f-49af-82ee-cb7400cc4522"
},
"attributes": {
"fullName": "Marty McFly",
"firstName": "Marty",
"lastName": "McFly",
"email": "[email protected]",
"status": "ACTIVE",
"role": "user",
"metadata": {},
"created": "2017-01-02T19:48:50.077Z",
"updated": "2017-01-02T19:48:50.077Z"
},
"relationships": {
"account": {
"links": {
"related": "/v1/accounts/<account>"
},
"data": {
"type": "accounts",
"id": "<account>"
}
},
"products": {
"links": {
"related": "/v1/accounts/<account>/users/a5a154d2-f026-40fa-bc8d-a7e3ca415298/products"
}
},
"licenses": {
"links": {
"related": "/v1/accounts/<account>/users/a5a154d2-f026-40fa-bc8d-a7e3ca415298/licenses"
}
},
"machines": {
"links": {
"related": "/v1/accounts/<account>/users/a5a154d2-f026-40fa-bc8d-a7e3ca415298/machines"
}
},
"tokens": {
"links": {
"related": "/v1/accounts/<account>/users/a5a154d2-f026-40fa-bc8d-a7e3ca415298/tokens"
}
}
}
},
],
"links": {
"self": "/v1/accounts/<account>/users?page[size]=25&page[cursor]=4a3eb389-5742-49f2-92f8-29347196a265",
"next": "/v1/accounts/<account>/users?page[size]=25&page[cursor]=6ed498fe-5f5f-49af-82ee-cb7400cc4522",
}
}