Trust Score: Filter CIQ Queries by Subject Trust Score Threshold
End-to-end demonstration that the Trust Score lives on the node as a regular property and can be filtered on inside a CIQ policy.
Pipeline:
1. Trust Score Profile (REST): Create a profile scoped to node_classification = "Person" with weighted dimensions (verification, origin, freshness).
2. Capture (REST): Ingest two Person nodes. One carries rich metadata (verified_time, source = "id-verifier.gov"); the other has only a self-attested source. The metadata is what the dimensions evaluate.
3. Scoring runs on the configured schedule: each Person gets a _TrustScore node attached via _HAS, with property _final_score plus one property per active dimension. The score IS a node in the IKG - every CIQ traversal can see it as subject.trust_score.<dim>.
4. CIQ filter (POST /contx-iq/v1/execute): the policy filter requires subject.trust_score._final_score > 0.66 (a fixed threshold baked into the policy). The high-metadata Person clears the bar; the self-attested one does not.
Effect: data quality becomes a first-class authorization input - the policy admits a subject only when its computed trust score clears the threshold.
Use case
Scenario: A KYC-style portal returns a Person's profile only if their underlying identity data clears a freshness/verification bar. The policy hardcodes the threshold at 0.66; the subject is chosen per call via input_params.subject_external_id.
Persons captured (relevant metadata only):
- Person(knightrider) - email + name carry verified_time = "2026-05-10T08:00:00Z" and source = "id-verifier.gov".
- Person(satchmo) - email + name carry source = "user-self-attested" only.
After scoring (THREE_HOURS), the IKG has:
- (knightrider) -[:_HAS]-> _TrustScore { _final_score: 0.83, verification: 1.0, origin: 0.75, freshness: 0.74 }
- (satchmo) -[:_HAS]-> _TrustScore { _final_score: 0.42, verification: 0.0, origin: 0.4, freshness: 0.85 }
CIQ executions:
- subject_external_id = knightrider -> 0.83 > 0.66 -> returns the profile, including subject.trust_score._final_score = 0.83.
- subject_external_id = satchmo -> 0.42 is not > 0.66 -> returns an empty data array. satchmo exists, but the trust threshold isn't met.

Requirements
Prerequisites:
- ServiceAccount credentials: For creating the Trust Score Profile, the CIQ policy, and the Knowledge Query.
- AppAgent credentials: For ingesting Person nodes via the Capture API and for executing the query.
- Bearer token: the subject is a Person, so /contx-iq/v1/execute needs a third-party bearer token alongside X-IK-ClientKey. The subject identity itself comes from input_params.subject_external_id.
- Patience: scores are computed on the schedule (THREE_HOURS in this example). The first run produces the initial _TrustScore nodes; subsequent runs update them.
Required API access:
- POST /configs/v1/trust-score-profiles
- POST /capture/v1/nodes
- POST /configs/v1/authorization-policies
- POST /configs/v1/knowledge-queries
- POST /contx-iq/v1/execute
Steps
Step 1: Create the Trust Score Profile for Person
- Schedule: THREE_HOURS (allowed values: THREE_HOURS, SIX_HOURS, TWELVE_HOURS, DAILY). Pick longer intervals for stable identity data.
- Dimensions: VERIFICATION, ORIGIN, FRESHNESS weighted 1 each; COMPLETENESS and VALIDITY present but weight 0 so they don't influence _final_score. Weights must be between 0 and 1.
- node_classification: "Person" - only Person nodes are scored by this profile.
Step 2: Capture Persons (with the metadata the profile cares about)
- Each scored property should carry the metadata fields the profile uses (property.metadata is a single object: source, verified_time, assurance_level, custom_metadata).
- verification dimension reads property.metadata.verified_time.
- origin dimension reads property.metadata.source.
- freshness dimension uses node + property update times.
- Two contrasting Persons make the threshold visible: a high-quality one (DMV-sourced, recently verified) and a self-attested one.
- After capture, scoring runs on the profile schedule; each Person gets a _TrustScore node and the value becomes readable as subject.trust_score.* in CIQ. There is no synchronous read - wait for the scheduled pass, then run the query below.
Step 3: Create the CIQ Policy
- The condition filter ANDs subject.external_id = $subject_external_id with subject.trust_score._final_score > 0.66 (the threshold is fixed in the policy).
- allowed_reads exposes the trust score so the response can show why the row was accepted.
Step 4: Create and Execute the Knowledge Query
- The query simply returns the subject's own fields + subject.trust_score._final_score.
- Send input_params.subject_external_id per call (knightrider clears the bar, satchmo does not).
- Bearer token + X-IK-ClientKey are required as for any Person-subject CIQ call.
Step 1
Trust Score Profile config for Person (flat REST body). node_classification controls which nodes get scored; schedule is one of THREE_HOURS/SIX_HOURS/TWELVE_HOURS/DAILY; each dimensions[].weight is between 0 and 1 (weight = 0 means computed-but-ignored).
{
"project_id": "your_project_gid",
"name": "person-trust-score-profile",
"display_name": "Person Trust Score Profile",
"description": "Trust Score profile for Person nodes. Combines verification, origin and freshness with equal weights; completeness and validity are present but weighted 0 (still computed, not used in _final_score).",
"node_classification": "Person",
"schedule": "THREE_HOURS",
"dimensions": [
{
"name": "VERIFICATION",
"weight": 1
},
{
"name": "ORIGIN",
"weight": 1
},
{
"name": "FRESHNESS",
"weight": 1
},
{
"name": "COMPLETENESS",
"weight": 0
},
{
"name": "VALIDITY",
"weight": 0
}
]
}Step 2
Capture two contrasting Person nodes. The metadata object on each property is the actual input to the scoring dimensions - verified_time, source, and update times.
{
"nodes": [
{
"external_id": "knightrider",
"type": "Person",
"is_identity": true,
"properties": [
{
"type": "email",
"value": "knightrider@demo.com",
"metadata": {
"verified_time": "2026-05-10T08:00:00Z",
"source": "id-verifier.gov"
}
},
{
"type": "name",
"value": "Michael Knight",
"metadata": {
"verified_time": "2026-05-10T08:00:00Z",
"source": "id-verifier.gov"
}
}
]
},
{
"external_id": "satchmo",
"type": "Person",
"is_identity": true,
"properties": [
{
"type": "email",
"value": "satchmo@demo.com",
"metadata": {
"source": "user-self-attested"
}
},
{
"type": "name",
"value": "Louis Armstrong",
"metadata": {
"source": "user-self-attested"
}
}
]
}
]
}Step 3
CIQ Policy. The trust score appears on the subject just like any other node attribute via subject.trust_score._final_score, so it can be ANDed into the regular filter.
{
"meta": {
"policy_version": "1.0-ciq"
},
"subject": {
"type": "Person"
},
"condition": {
"cypher": "MATCH (subject:Person)",
"filter": [
{
"operator": "AND",
"operands": [
{
"operator": "=",
"attribute": "subject.external_id",
"value": "$subject_external_id"
},
{
"operator": ">",
"attribute": "subject.trust_score._final_score",
"value": 0.66
}
]
}
]
},
"allowed_reads": {
"nodes": [
"subject.external_id",
"subject.property.email",
"subject.property.name",
"subject.trust_score._final_score"
]
}
}Request to create the policy.
{
"project_id": "your_project_gid",
"description": "CIQ policy that returns the requested Person record ONLY when its computed Trust Score _final_score is above the hardcoded threshold (0.66). The Trust Score Profile must already be active for node_classification = Person; otherwise subject.trust_score._final_score is undefined and the filter rejects every row.",
"display_name": "policy - person with trust score filter",
"name": "policy-trust-score-filter",
"policy": "{\"meta\":{\"policy_version\":\"1.0-ciq\"},\"subject\":{\"type\":\"Person\"},\"condition\":{\"cypher\":\"MATCH (subject:Person)\",\"filter\":[{\"operator\":\"AND\",\"operands\":[{\"operator\":\"=\",\"attribute\":\"subject.external_id\",\"value\":\"$subject_external_id\"},{\"operator\":\">\",\"attribute\":\"subject.trust_score._final_score\",\"value\":0.66}]}]},\"allowed_reads\":{\"nodes\":[\"subject.external_id\",\"subject.property.email\",\"subject.property.name\",\"subject.trust_score._final_score\"]}}",
"status": "ACTIVE",
"tags": []
}Step 4
Knowledge Query - returns the subject's own profile plus subject.trust_score._final_score.
{
"nodes": [
"subject.external_id",
"subject.property.email",
"subject.property.name",
"subject.trust_score._final_score"
]
}Request to create the Knowledge Query.
{
"project_id": "your_project_gid",
"description": "Returns the requested Person's profile but ONLY if their Trust Score _final_score is above the policy threshold (0.66). The trust score itself is included in the response so you can see why a subject was accepted or excluded.",
"display_name": "knowledge query - my profile if trustworthy",
"name": "kq-my-profile-trusted",
"policy_id": "your_policy_gid",
"query": "{\"nodes\":[\"subject.external_id\",\"subject.property.email\",\"subject.property.name\",\"subject.trust_score._final_score\"]}",
"status": "ACTIVE"
}Execute for Knight Rider (high-quality data): input_params.subject_external_id = knightrider. His _final_score 0.83 clears the policy's 0.66 threshold.
{
"id": "your_query_gid_or_name",
"input_params": {
"subject_external_id": "knightrider"
}
}Response: profile returned, _final_score = 0.83 is included as a regular field in the result row.
{
"data": [
{
"nodes": {
"subject.external_id": "knightrider",
"subject.property.email": "knightrider@demo.com",
"subject.property.name": "Michael Knight",
"subject.trust_score._final_score": 0.83
}
}
]
}Execute for Satchmo (self-attested data): input_params.subject_external_id = satchmo. His _final_score 0.42 does not clear the 0.66 threshold.
{
"id": "your_query_gid_or_name",
"input_params": {
"subject_external_id": "satchmo"
}
}Response: empty data array. The Person exists but the trust score is below the threshold, so the filter drops the row.
{
"data": []
}API Endpoints
/configs/v1/trust-score-profiles /capture/v1/nodes /configs/v1/authorization-policies /configs/v1/knowledge-queries /contx-iq/v1/execute