Pagination and Incremental Synchronization
Many of the list
endpoints in Ashby's API (for example, candidate.list
and job.list
) implement pagination and incremental synchronization. This guide describes how to:
- Implement the client-side logic needed to iterate through multiple pages of results, and
- Only fetch resources that have been updated since the previous API request
Full sync
Paginated APIs default to a "full" sync, returning data for all the resources of the requested object type. Full syncs can be slow. Ideally, clients should only need to perform one initial full sync, and then switch to more-efficient incremental syncs (see below).
To begin a full sync, POST
an empty JSON object to the target endpoint. If the request succeeds, it will return an object like:
{
"success": true,
"results": [
// An array of the requested object type
],
"moreDataAvailable": true,
"nextCursor": "some-token-value"
}
The length of the results
array will be automatically capped by the API. If you'd like to specify the number of results returned per page, you can do so by specifying a limit
in your API request:
{
"limit": 100
}
If the moreDataAvailable
field in the response is true
, then there are additional pages of objects to fetch. To fetch the next page, re-send a request to the endpoint, this time passing the value of nextCursor
from the latest response as a parameter:
{
"limit": 100,
"cursor": "some-token-value"
}
Repeat this cycle on the client side, replacing cursor
with the latest nextCursor
on each request, until you receive a response with moreDataAvailable
set to false
. This signals that you've fetched all available records of the targeted type, completing the full sync. In this case, the response will contain a new syncToken
field:
{
"success": true,
"results": [
// Array of requested object type
],
"moreDataAvailable": false,
"syncToken": "sync-token-value"
}
You should store this value of syncToken
for use in your next sync.
Example
To list all the candidates in my organization, I would begin with the request:
curl -XPOST https://api.ashbyhq.com/candidate.list -u "${API_KEY}:" \
-H "Accept: application/json" -H "Content-Type: application/json" \
-d '{ "limit": 25 }'
Returning:
{
"success": true,
"results": [
// 25 objects
],
"moreDataAvailable": true,
"nextCursor": "Rl"
}
I'd then send a follow-up request:
curl -XPOST https://api.ashbyhq.com/candidate.list -u "${API_KEY}:" \
-H "Accept: application/json" -H "Content-Type: application/json" \
-d '{ "limit": 25, "cursor": "Rl" }'
Returning:
{
"success": true,
"results": [
// <= 25 objects
],
"moreDataAvailable": false,
"syncToken": "mqXvvQBWO"
}
I would then persist the syncToken
value of "mqXvvQBWO"
for later use.
Incremental sync
Incremental sync allows you to fetch only the resources that have been modified since your last sync request. To do this, include the syncToken
returned at the end of your last sync flow in your initial API request:
{
"syncToken": "sync-token-value"
}
The API will return a response like:
{
"success": true,
"results": [
// An array of the requested object type
],
"moreDataAvailable": true,
"nextCursor": "some-token-value",
"syncToken": "sync-token-value"
}
Note here that as long as moreDataAvailable
is true
, the syncToken
returned by the API will be the same as the syncToken
passed in the request.
To fetch the next page of results, pass the latest values of nextCursor
and syncToken
in your request:
{
"cursor": "some-token-value",
"syncToken": "sync-token-value"
}
Repeat this flow, passing a new cursor
and the same syncToken
in each request, until you receive a response with moreDataAvailable
set to false
. This response will contain a new syncToken
value for you to persist for the next set of requests:
{
"success": true,
"results": [
// Array of requested object type
],
"moreDataAvailable": false,
"syncToken": "new-sync-token-value"
}
Example
To list all the candidates in my organization that have been updated since my last sync, I would take the syncToken
value from that sync and pass it in a request:
curl -XPOST https://api.ashbyhq.com/candidate.list -u "${API_KEY}:" \
-H "Accept: application/json" -H "Content-Type: application/json" \
-d '{ "limit": 25, "syncToken": "mqXvvQBWO" }'
Returning:
{
"success": true,
"results": [
// 25 objects
],
"moreDataAvailable": true,
"nextCursor": "Rl",
"syncToken": "mqXvvQBWO",
}
I'd then send a follow-up request:
curl -XPOST https://api.ashbyhq.com/candidate.list -u "${API_KEY}:"
-H "Accept: application/json" -H "Content-Type: application/json"
-d '{ "limit": 25, "syncToken": "mqXvvQBWO", "cursor": "Rl" }'
Returning:
{
"success": true,
"results": [
// <= 25 objects
],
"moreDataAvailable": false,
"syncToken": "PjJ33rQZl"
}
I would then persist the new syncToken
value of "PjJ33rQZl"
, replacing the previous value of "mqXvvQBWO"
, for later use.
Sync token expiration
Sync tokens returned by the API can be invalidated for various reasons, including token expiration. When the API is passed an invalid token, it will return a response like:
{
"success": false,
"errors": ["sync_token_expired"]
}
If your client receives this response, it should begin a new full sync to re-fetch all data using valid tokens.
To minimize the risk of sync token expiration, we recommend performing an incremental sync at least once per week.
Updated 8 months ago