Skip to main content
Version: Latest (4.0.3)

Read users in bulk mode

POST 

/user-ext-srv/bulkread/users

The Bulk Read API allows you to retrieve large volumes of user data efficiently. It supports advanced filtering, cursor-based pagination via searchAfter, and consistent data snapshots using Point-In-Time (pit) queries.

Key Concepts

  • Cursor-Based Pagination (searchAfter):
    • Requires a sortfield to be specified in the request (e.g., updatedTime or sub).
    • Every user record in the response contains a sort array.
    • To fetch the next page, pass the complete, unmodified sort array of the last user in the current response as searchAfter in the subsequent request.
  • Data Type & Formatting Requirement:
    • searchAfter MUST be passed as a native JSON array (e.g., [1629375844777, "b8c4d2e1-8f3a-4e2b-9a1c-5d6e7f8a9b0c"]).
    • Never pass searchAfter as a stringified array (e.g., "searchAfter": "[1629375844777, \"b8c4d2e1-8f3a-4e2b-9a1c-5d6e7f8a9b0c\"]"). Passing a stringified array string will result in API request parsing failures.
  • Mixed-Array Cursor Structure & sortfield=sub Exception:
    • The sort cursor is a mixed-type JSON array containing values for the primary sort field and tie-breakers (e.g., [timestamp, sub]).
    • When sorting by fields like updatedTime, cidaas automatically appends sub as a second element in the sort array to guarantee deterministic ordering across identical timestamps (e.g., [1629375844777, "b8c4d2e1-8f3a-4e2b-9a1c-5d6e7f8a9b0c"]).
    • Exception (sortfield=sub): When sortfield is set directly to sub ("sortfield": "sub"), the sort array contains only a single string element (e.g., ["b8c4d2e1-8f3a-4e2b-9a1c-5d6e7f8a9b0c"]) because sub is already unique.
    • Always pass the complete sort array unchanged in searchAfter (do not omit or truncate tie-breaker elements).
  • Point-In-Time (PIT): Enabling a PIT session creates a consistent data snapshot. This ensures all pagination requests see the exact same data state as it existed when the session was initiated, preventing duplicate or missing records caused by concurrent data updates during export.

End-to-End Pagination Flow Example

1. Initial Request (First Page)

POST /user-ext-srv/bulkread/users
{
"sortfield": "updatedTime",
"descending": true,
"size": 2
}

2. API Response (First Page)

{
"success": true,
"status": 200,
"data": [
{
"sub": "user-001",
"email": "[email protected]",
"updatedTime": 1700000000000,
"sort": [1700000000000, "user-001"]
},
{
"sub": "user-002",
"email": "[email protected]",
"updatedTime": 1699999900000,
"sort": [1699999900000, "user-002"]
}
]
}

3. Subsequent Request (Next Page)

Extract the complete sort array from the last user ([1699999900000, "user-002"]) and pass it as searchAfter:

POST /user-ext-srv/bulkread/users
{
"sortfield": "updatedTime",
"descending": true,
"size": 2,
"searchAfter": [1699999900000, "user-002"]
}

Format Note:

  • Correct (JSON Array): "searchAfter": [1699999900000, "user-002"]
  • Incorrect (Stringified): "searchAfter": "[1699999900000, \"user-002\"]"

4. Completion

Repeat until the API returns an HTTP 204 No Content status.

Usage with Point-In-Time (PIT)

  1. Initial Request: Include sortfield and a pit object with a keepAlive duration (in minutes).
    \{
    "sortfield": "updatedTime",
    "pit": \{
    "keepAlive": "5"
    \}
    \}
  2. Extract PIT ID: The response will include a pitId.
    \{
    "users": [...],
    "pitId": "gcSHBAM2Y2lkYWFz..."
    \}
  3. Subsequent Requests: Provide the last user's complete sort array as searchAfter and the pitId as id inside the pit object.
    \{
    "sortfield": "updatedTime",
    "pit": \{
    "keepAlive": "5",
    "id": "gcSHBAM2Y2lkYWFz..."
    \},
    "searchAfter": [1629375844777, "8589940405"]
    \}
  4. Completion: Continue the loop until the API returns an HTTP 204 No Content status.

Request

Responses

OK