ContX IQ: Paginated Query Execution with page_token and page_size
This example demonstrates pagination on the CIQ Execute endpoint.
Request fields:
- page_token (integer, optional): Page index. Any value below 1 returns page 1.
- page_size (integer, optional): Result set size. Default is 100.
Pagination model:
- The client increments page_token by page_size between calls (page 1 -> token 0 or 1, page 2 -> token = page_size, page 3 -> token = 2 * page_size, ...).
- When fewer than page_size records come back, you've hit the last page.
- Pagination applies to the records inside data[]; partial filters and authorization are re-evaluated on every call.
When to use:
- Knowledge Queries that may return hundreds or thousands of nodes/relationships.
- Streaming-style consumers that prefer fixed-size chunks.
Use case
Scenario: A back-office UI lists every car license alice owns, two rows at a time.
Graph structure:
- Person(alice) -[OWNS]-> Car(kitt) -[HAS]-> LicenseNumber("KITT 0001")
- Person(alice) -[OWNS]-> Car(caddilacv16) -[HAS]-> LicenseNumber("CADV16-007")
- Person(alice) -[OWNS]-> Car(skodaOctavia) -[HAS]-> LicenseNumber("OCT-2021-XX")
Walk:
1. Call /execute with page_token=0, page_size=2 -> returns kitt + caddilacv16.
2. Call /execute with page_token=2, page_size=2 -> returns skodaOctavia (one record => last page).
3. The UI knows there are no more rows and stops paging.
Tip: Use page_size to bound memory and latency, not to limit returned data. Authorization is applied to every record on every call.

Requirements
Prerequisites:
- ServiceAccount credentials: For creating the policy and Knowledge Query.
- AppAgent credentials: For ingesting the graph and executing the query.
- Bearer token for the subject (alice) when subject type is not _Application.
Required API access:
- POST /capture/v1/nodes/ and /capture/v1/relationships/
- POST /configs/v1/authorization-policies
- POST /configs/v1/knowledge-queries
- POST /contx-iq/v1/execute (called once per page)
Steps
Step 1: Capture the Graph
- Action: POST Person (alice), her Cars, and their LicenseNumber nodes, plus OWNS and HAS relationships.
- Result: Three car/license rows for alice to page through.
Step 2: Create a Read-Only Policy
- Action: POST a policy authorizing the Person -> Car -> LicenseNumber traversal, filtered to the subject.
- Result: Policy ID.
Step 3: Create the Knowledge Query
- Action: POST a Knowledge Query that reads car.external_id and ln.property.number.
- Result: Knowledge Query ID.
Step 4: Execute Page 1
- Authentication: AppAgent credential.
- Action: POST to /contx-iq/v1/execute with page_token=0 and page_size=2.
- Result: First 2 records.
Step 5: Execute Page 2
- Action: POST to /contx-iq/v1/execute with page_token=2 and page_size=2.
- Result: Remaining record(s). Fewer than page_size means this is the last page.
Step 1
Capture the Person (alice), her Cars, and their LicenseNumber nodes.
{
"nodes": [
{
"external_id": "alice",
"is_identity": true,
"type": "Person",
"properties": [
{
"type": "email",
"value": "alice@email.com"
},
{
"type": "name",
"value": "Alice Smith"
}
]
},
{
"external_id": "kitt",
"type": "Car",
"properties": [
{
"type": "model",
"value": "Firebird"
}
]
},
{
"external_id": "caddilacv16",
"type": "Car",
"properties": [
{
"type": "model",
"value": "V16"
}
]
},
{
"external_id": "skodaOctavia",
"type": "Car",
"properties": [
{
"type": "model",
"value": "Octavia"
}
]
},
{
"external_id": "ln-kitt-0001",
"type": "LicenseNumber",
"properties": [
{
"type": "number",
"value": "KITT 0001"
}
]
},
{
"external_id": "ln-cad-007",
"type": "LicenseNumber",
"properties": [
{
"type": "number",
"value": "CADV16-007"
}
]
},
{
"external_id": "ln-oct-2021",
"type": "LicenseNumber",
"properties": [
{
"type": "number",
"value": "OCT-2021-XX"
}
]
}
]
}Capture the relationships: alice OWNS each Car, and each Car HAS its LicenseNumber.
{
"relationships": [
{
"source": {
"external_id": "alice",
"type": "Person"
},
"target": {
"external_id": "kitt",
"type": "Car"
},
"type": "OWNS"
},
{
"source": {
"external_id": "alice",
"type": "Person"
},
"target": {
"external_id": "caddilacv16",
"type": "Car"
},
"type": "OWNS"
},
{
"source": {
"external_id": "alice",
"type": "Person"
},
"target": {
"external_id": "skodaOctavia",
"type": "Car"
},
"type": "OWNS"
},
{
"source": {
"external_id": "kitt",
"type": "Car"
},
"target": {
"external_id": "ln-kitt-0001",
"type": "LicenseNumber"
},
"type": "HAS"
},
{
"source": {
"external_id": "caddilacv16",
"type": "Car"
},
"target": {
"external_id": "ln-cad-007",
"type": "LicenseNumber"
},
"type": "HAS"
},
{
"source": {
"external_id": "skodaOctavia",
"type": "Car"
},
"target": {
"external_id": "ln-oct-2021",
"type": "LicenseNumber"
},
"type": "HAS"
}
]
}Step 2
Read-only CIQ Policy authorizing the alice -> Car -> LicenseNumber traversal (subject filtered by subject_external_id).
{
"meta": {
"policy_version": "1.0-ciq"
},
"subject": {
"type": "Person"
},
"condition": {
"cypher": "MATCH (subject:Person)-[:OWNS]->(car:Car)-[:HAS]->(ln:LicenseNumber)",
"filter": [
{
"operator": "=",
"attribute": "subject.external_id",
"value": "$subject_external_id"
}
]
},
"allowed_reads": {
"nodes": [
"car",
"car.*",
"ln",
"ln.*"
]
}
}Request to create the CIQ Policy configuration using REST.
{
"project_id": "your_project_gid",
"description": "Authorize the Person -> Car -> LicenseNumber traversal so a read Knowledge Query can return each car and its license number for the subject.",
"display_name": "policy - person owns cars with license numbers",
"name": "policy-person-owns-car-licenses",
"policy": "{\"meta\":{\"policy_version\":\"1.0-ciq\"},\"subject\":{\"type\":\"Person\"},\"condition\":{\"cypher\":\"MATCH (subject:Person)-[:OWNS]->(car:Car)-[:HAS]->(ln:LicenseNumber)\",\"filter\":[{\"operator\":\"=\",\"attribute\":\"subject.external_id\",\"value\":\"$subject_external_id\"}]},\"allowed_reads\":{\"nodes\":[\"car\",\"car.*\",\"ln\",\"ln.*\"]}}",
"status": "ACTIVE",
"tags": []
}Step 3
Knowledge Query that returns car.external_id and ln.property.number with no filter - pagination will limit how many records come back per call.
{
"nodes": [
"car.external_id",
"ln.property.number"
]
}Request to create the Knowledge Query.
{
"project_id": "your_project_gid",
"description": "Return every car license-number tuple this subject is authorized to see. Designed for pagination via page_token / page_size on /contx-iq/v1/execute.",
"display_name": "knowledge query - paginated car licenses",
"name": "kq-paginated-licenses",
"policy_id": "your_policy_gid",
"query": "{\"nodes\":[\"car.external_id\",\"ln.property.number\"]}",
"status": "ACTIVE"
}Step 4
Page 1: page_token=0, page_size=2 - returns the first two records.
{
"id": "your_query_gid_or_name",
"input_params": {
"subject_external_id": "alice"
},
"page_token": 0,
"page_size": 2
}Page 1 response - 2 records.
{
"data": [
{
"nodes": {
"car.external_id": "kitt",
"ln.property.number": "KITT 0001"
}
},
{
"nodes": {
"car.external_id": "caddilacv16",
"ln.property.number": "CADV16-007"
}
}
]
}Step 5
Page 2: advance page_token to 2 (page_size). Same page_size keeps result chunks consistent.
{
"id": "your_query_gid_or_name",
"input_params": {
"subject_external_id": "alice"
},
"page_token": 2,
"page_size": 2
}Page 2 response - 1 record. Fewer than page_size, so this is the last page.
{
"data": [
{
"nodes": {
"car.external_id": "skodaOctavia",
"ln.property.number": "OCT-2021-XX"
}
}
]
}API Endpoints
/capture/v1/nodes /capture/v1/relationships /configs/v1/authorization-policies /configs/v1/knowledge-queries /contx-iq/v1/execute