Rules & Identity Specs API
Manage matching rules and identity spec versions.
Overview
| Method | Endpoint | Use Case |
|---|---|---|
| List rules | GET /v1/rules | Get all active matching rules |
| Create rule | POST /v1/rules | Create a new rule version |
| Rule history | GET /v1/rules/:name/history | View all versions of a rule |
| List specs | GET /v1/identity/specs | List uploaded identity spec versions |
| Upload spec | POST /v1/identity/specs | Validate and compile a new spec |
| Get spec | GET /v1/identity/specs/:version | Get a specific spec version |
GET /v1/rules
List all active matching rules for your tenant. Returns the latest active version of each rule.
Request
import httpx
resp = httpx.get("https://api.kanoniv.com/v1/rules",
headers={"X-API-Key": "kn_..."})
rules = resp.json()
for rule in rules:
print(f"{rule['name']}: type={rule['rule_type']}, weight={rule['weight']}, v{rule['version']}")curl "https://api.kanoniv.com/v1/rules" \
-H "X-API-Key: kn_..."Response
Returns an array of MatchRule objects:
[
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"tenant_id": "t_abc123",
"name": "email_exact",
"rule_type": "exact",
"version": 3,
"config": {
"field": "email",
"case_sensitive": false
},
"weight": 1.0,
"is_active": true,
"created_at": "2026-02-01T10:00:00Z",
"created_by": "660e8400-e29b-41d4-a716-446655440001"
},
{
"id": "550e8400-e29b-41d4-a716-446655440002",
"tenant_id": "t_abc123",
"name": "name_fuzzy",
"rule_type": "similarity",
"version": 1,
"config": {
"field": "name",
"algorithm": "jaro_winkler",
"threshold": 0.85
},
"weight": 0.6,
"is_active": true,
"created_at": "2026-01-10T08:00:00Z",
"created_by": null
}
]Response Fields
| Field | Type | Description |
|---|---|---|
id | UUID | Rule ID |
tenant_id | UUID | Tenant this rule belongs to |
name | string | Rule identifier |
rule_type | string | Rule type (e.g. "exact", "similarity", "composite") |
version | integer | Version number (auto-incremented per rule name) |
config | object | Rule-specific configuration (free-form JSON) |
weight | float | Scoring weight (0.0--1.0) |
is_active | boolean | Whether this version is the active one |
created_at | timestamp | When this version was created |
created_by | UUID | User ID who created it (null if created by system) |
POST /v1/rules
Create a new rule or a new version of an existing rule. If a rule with the same name already exists, a new version is created. If is_active is true, all other versions of the same rule name are deactivated.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Rule identifier (1--100 characters) |
rule_type | string | Yes | Rule type (1--50 characters) |
config | object | Yes | Rule-specific configuration (free-form JSON) |
weight | float | Yes | Scoring weight (0.0--1.0) |
is_active | boolean | Yes | Whether this version should be active |
Request
import httpx
# Create an exact email match rule
resp = httpx.post("https://api.kanoniv.com/v1/rules",
headers={"X-API-Key": "kn_...", "Content-Type": "application/json"},
json={
"name": "email_exact",
"rule_type": "exact",
"config": {"field": "email", "case_sensitive": False},
"weight": 1.0,
"is_active": True
})
rule = resp.json()
print(f"Created rule {rule['name']} v{rule['version']}")curl -X POST "https://api.kanoniv.com/v1/rules" \
-H "X-API-Key: kn_..." \
-H "Content-Type: application/json" \
-d '{
"name": "email_exact",
"rule_type": "exact",
"config": {
"field": "email",
"case_sensitive": false
},
"weight": 1.0,
"is_active": true
}'Response
Returns 201 Created with the new MatchRule:
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"tenant_id": "t_abc123",
"name": "email_exact",
"rule_type": "exact",
"version": 1,
"config": {
"field": "email",
"case_sensitive": false
},
"weight": 1.0,
"is_active": true,
"created_at": "2026-02-05T10:00:00Z",
"created_by": "660e8400-e29b-41d4-a716-446655440001"
}Validation
| Constraint | Error |
|---|---|
name empty or > 100 chars | Rule name must be 1-100 characters |
rule_type empty or > 50 chars | Rule type must be 1-50 characters |
weight outside 0.0--1.0 | Weight must be between 0.0 and 1.0 |
GET /v1/rules/:name/history
View all versions of a rule, ordered by version number. Useful for auditing rule changes over time.
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Rule name |
Request
import httpx
resp = httpx.get("https://api.kanoniv.com/v1/rules/email_exact/history",
headers={"X-API-Key": "kn_..."})
history = resp.json()
for version in history:
status = "active" if version["is_active"] else "inactive"
print(f"v{version['version']}: weight={version['weight']}, {status}")curl "https://api.kanoniv.com/v1/rules/email_exact/history" \
-H "X-API-Key: kn_..."Response
Returns an array of all MatchRule versions for the given name:
[
{
"id": "550e8400-e29b-41d4-a716-446655440003",
"tenant_id": "t_abc123",
"name": "email_exact",
"rule_type": "exact",
"version": 3,
"config": {
"field": "email",
"case_sensitive": false
},
"weight": 1.0,
"is_active": true,
"created_at": "2026-02-01T10:00:00Z",
"created_by": "660e8400-e29b-41d4-a716-446655440001"
},
{
"id": "550e8400-e29b-41d4-a716-446655440002",
"tenant_id": "t_abc123",
"name": "email_exact",
"rule_type": "exact",
"version": 2,
"config": {
"field": "email",
"case_sensitive": true
},
"weight": 0.9,
"is_active": false,
"created_at": "2026-01-20T14:00:00Z",
"created_by": "660e8400-e29b-41d4-a716-446655440001"
}
]GET /v1/identity/specs
List all uploaded identity spec versions for your tenant. Optionally filter by metadata tag.
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
tag | string | No | Filter specs by metadata tag |
Request
import httpx
resp = httpx.get("https://api.kanoniv.com/v1/identity/specs",
headers={"X-API-Key": "kn_..."})
specs = resp.json()
for spec in specs:
print(f"{spec['identity_version']} (hash: {spec['plan_hash'][:12]}...)")curl "https://api.kanoniv.com/v1/identity/specs" \
-H "X-API-Key: kn_..."
# Filter by tag
curl "https://api.kanoniv.com/v1/identity/specs?tag=production" \
-H "X-API-Key: kn_..."Response
Returns an array of spec summaries:
[
{
"identity_version": "customer-v3",
"plan_hash": "a1b2c3d4e5f6...",
"created_at": "2026-02-01T10:00:00Z",
"metadata": {
"name": "Customer Identity Resolution",
"description": "Production customer matching spec",
"owner": "data-team",
"tags": ["production", "customer"]
}
},
{
"identity_version": "customer-v2",
"plan_hash": "f6e5d4c3b2a1...",
"created_at": "2026-01-15T08:00:00Z",
"metadata": null
}
]Response Fields
| Field | Type | Description |
|---|---|---|
identity_version | string | Version identifier from the spec YAML |
plan_hash | string | SHA-256 hash of the compiled plan |
created_at | string | ISO 8601 timestamp |
metadata | object | Optional metadata from the spec (null if not provided) |
metadata.name | string | Spec display name |
metadata.description | string | Human-readable description |
metadata.owner | string | Team or person responsible |
metadata.tags | array | Tags for filtering and organization |
POST /v1/identity/specs
Upload and validate an identity spec (YAML). Optionally compiles it to an execution plan and persists it.
Request Body
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
raw_yaml | string | Yes | N/A | The identity spec as a YAML string (max 1 MB) |
compile | boolean | No | false | If true, compile and persist the plan |
Request
import httpx
spec_yaml = """
identity_version: customer-v3
entity: customer
sources:
crm:
adapter: postgres
table: customers
billing:
adapter: postgres
table: billing_accounts
rules:
- exact:
field: email
weight: 1.0
decision:
thresholds:
match: 0.85
review: 0.70
survivorship:
default_strategy: most_recent
"""
resp = httpx.post("https://api.kanoniv.com/v1/identity/specs",
headers={"X-API-Key": "kn_...", "Content-Type": "application/json"},
json={"raw_yaml": spec_yaml, "compile": True})
result = resp.json()
if result["valid"]:
print(f"Spec compiled! Hash: {result['plan_hash']}")
else:
print(f"Errors: {result['errors']}")curl -X POST "https://api.kanoniv.com/v1/identity/specs" \
-H "X-API-Key: kn_..." \
-H "Content-Type: application/json" \
-d '{
"raw_yaml": "identity_version: customer-v3\nentity: customer\n...",
"compile": true
}'Response
{
"valid": true,
"warnings": [
"Source 'crm' has no freshness config -- staleness detection will be skipped"
],
"errors": [],
"plan_hash": "a1b2c3d4e5f6..."
}Response Fields
| Field | Type | Description |
|---|---|---|
valid | boolean | Whether the spec passed validation |
warnings | array | Non-fatal validation warnings |
errors | array | Validation or tier-gating errors (empty if valid) |
plan_hash | string | SHA-256 hash of compiled plan (null if compile was false or validation failed) |
Tier-Gated Features
Cloud-only features (exclusions, scoring, compliance, freshness, hierarchy, audit config) are validated against your tenant's tier. If your spec uses features above your tier, validation will fail with specific tier-gating errors.
GET /v1/identity/specs/:version
Get a specific spec version, including the raw YAML and compiled execution plan.
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
version | string | Yes | Identity version string (e.g., "customer-v3") |
Request
import httpx
resp = httpx.get("https://api.kanoniv.com/v1/identity/specs/customer-v3",
headers={"X-API-Key": "kn_..."})
detail = resp.json()
print(f"Version: {detail['identity_version']}")
print(f"Hash: {detail['plan_hash']}")
print(f"Entity: {detail['compiled_plan']['entity']}")
print(f"Sources: {len(detail['compiled_plan']['sources'])}")curl "https://api.kanoniv.com/v1/identity/specs/customer-v3" \
-H "X-API-Key: kn_..."Response
{
"identity_version": "customer-v3",
"plan_hash": "a1b2c3d4e5f6...",
"raw_yaml": "identity_version: customer-v3\nentity: customer\n...",
"compiled_plan": {
"entity": "customer",
"plan_hash": "a1b2c3d4e5f6...",
"identity_version": "customer-v3",
"sources": [...],
"blocking": {...},
"match_graph": {...},
"survivorship": {...},
"decision": {...},
"reference_identifiers": [...],
"relations": [...]
},
"created_at": "2026-02-01T10:00:00Z",
"metadata": {
"name": "Customer Identity Resolution",
"description": "Production customer matching spec",
"owner": "data-team",
"tags": ["production", "customer"]
}
}Response Fields
| Field | Type | Description |
|---|---|---|
identity_version | string | Version identifier |
plan_hash | string | SHA-256 hash of the compiled plan |
raw_yaml | string | Original YAML as uploaded |
compiled_plan | object | The full compiled IdentityPlan (see Spec Reference) |
created_at | string | ISO 8601 timestamp |
metadata | object | Optional metadata (null if not present in the spec) |
Returns 404 if the spec version does not exist for your tenant.
See Also
- Rule Versioning — How rule versions work, testing before activating, rollback patterns
- Spec Versioning —
identity_version,plan_hash, and diffing specs
