Entities API
Query, search, and manage canonical entities.
GET /v1/entities
Search and filter entities across all sources.
Query Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
q | string | N/A | Search query (matches against canonical data and entity type) |
entity_type | string | N/A | Filter by entity type (e.g., "customer") |
include_external | boolean | false | Include external entities in results |
limit | int | 50 | Max results (1--1000) |
offset | int | 0 | Pagination offset |
Request
from kanoniv.client import KanonivClient
client = KanonivClient(api_key="kn_...", base_url="https://api.kanoniv.com")
# Search by email
results = client.get("/v1/entities", params={
"q": "[email protected]",
"entity_type": "customer",
"limit": 10
})
for item in results["data"]:
if item["kind"] == "Canonical":
entity = item["entity"]
print(f"{entity['id']}: {entity['canonical_data']['email']}")
print(f"Total: {results['total']}")curl "https://api.kanoniv.com/v1/[email protected]&entity_type=customer&limit=10" \
-H "X-API-Key: kn_..."Response
{
"data": [
{
"kind": "Canonical",
"entity": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"tenant_id": "t_abc123",
"entity_type": "customer",
"canonical_data": {
"email": "[email protected]",
"name": "John Doe",
"company": "Acme Corp"
},
"field_provenance": {
"email": "Stripe",
"name": "Salesforce",
"company": "Salesforce"
},
"confidence_score": 0.94,
"is_locked": false,
"created_at": "2026-01-15T10:00:00Z",
"updated_at": "2026-02-01T09:00:00Z"
}
}
],
"total": 1
}When include_external is true, external entities are included as additional entries:
{
"kind": "External",
"entity": {
"id": "ext_001",
"tenant_id": "t_abc123",
"data_source_id": "src_stripe",
"external_id": "cus_123",
"entity_type": "customer",
"raw_data": { "email": "[email protected]" },
"normalized_data": { "email": "[email protected]", "name": "John Doe" },
"ingested_at": "2026-01-15T10:00:00Z",
"batch_id": "batch_001"
}
}Response Fields
Each item in data is a tagged union with kind and entity:
| Field | Type | Description |
|---|---|---|
kind | string | "Canonical" or "External" |
entity | object | The entity object (schema depends on kind) |
total | int | Total matching results across both types |
See Resolution API for the full field reference of canonical and external entity objects.
GET /v1/entities/:id/history
View the audit trail for an entity: all recorded events including field updates, merges, splits, and reverts.
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
id | UUID | Yes | Canonical entity ID |
Request
history = client.get("/v1/entities/550e8400-e29b-41d4-a716-446655440000/history")
for event in history:
print(f"[{event['timestamp']}] {event['action']} by {event['actor_type']}")
if event.get("reason"):
print(f" Reason: {event['reason']}")curl "https://api.kanoniv.com/v1/entities/550e8400-e29b-41d4-a716-446655440000/history" \
-H "X-API-Key: kn_..."Response
Returns an array of audit events ordered by timestamp descending (most recent first):
[
{
"id": "evt_001",
"tenant_id": "t_abc123",
"actor_id": "user_001",
"actor_type": "user",
"action": "field_update",
"resource_type": "canonical_entity",
"resource_id": "550e8400-e29b-41d4-a716-446655440000",
"before_state": { "email": "[email protected]" },
"after_state": { "email": "[email protected]" },
"reason": null,
"timestamp": "2026-02-01T09:00:00Z"
},
{
"id": "evt_002",
"tenant_id": "t_abc123",
"actor_id": "system",
"actor_type": "worker",
"action": "merge",
"resource_type": "canonical_entity",
"resource_id": "550e8400-e29b-41d4-a716-446655440000",
"before_state": null,
"after_state": { "email": "[email protected]", "name": "John Doe" },
"reason": "Auto-merge: confidence 0.94",
"timestamp": "2026-01-20T14:30:00Z"
}
]Response Fields
| Field | Type | Description |
|---|---|---|
id | UUID | Event ID |
actor_id | UUID | Who performed the action |
actor_type | string | "user", "worker", "system", "api_key" |
action | string | What happened (see table below) |
resource_type | string | Resource type (e.g., "canonical_entity") |
resource_id | UUID | The entity this event applies to |
before_state | object | Entity state before the change (null for creation) |
after_state | object | Entity state after the change |
reason | string | Human-readable explanation (null if not provided) |
timestamp | timestamp | When the event occurred |
POST /v1/entities/:id/lock
Lock or unlock an entity. Locked entities are excluded from automatic merging during reconciliation. They can still be manually overridden.
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
id | UUID | Yes | Canonical entity ID |
Request Body
| Field | Type | Default | Description |
|---|---|---|---|
locked | boolean | true | Set to true to lock, false to unlock |
Request
# Lock an entity
client.post("/v1/entities/550e8400-e29b-41d4-a716-446655440000/lock",
json={"locked": True})
# Unlock an entity
client.post("/v1/entities/550e8400-e29b-41d4-a716-446655440000/lock",
json={"locked": False})# Lock
curl -X POST "https://api.kanoniv.com/v1/entities/550e8400-e29b-41d4-a716-446655440000/lock" \
-H "X-API-Key: kn_..." \
-H "Content-Type: application/json" \
-d '{"locked": true}'
# Unlock
curl -X POST "https://api.kanoniv.com/v1/entities/550e8400-e29b-41d4-a716-446655440000/lock" \
-H "X-API-Key: kn_..." \
-H "Content-Type: application/json" \
-d '{"locked": false}'Response
Returns 200 OK with no body on success. Returns 404 if the entity does not exist.
POST /v1/entities/:id/revert/:event_id
Revert an entity's canonical data to the state captured in a specific audit event. The revert restores the after_state from the target event as the current canonical data.
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
id | UUID | Yes | Canonical entity ID |
event_id | UUID | Yes | Audit event ID to restore state from |
Request
# Get history first to find the event to revert to
history = client.get("/v1/entities/550e8400-e29b-41d4-a716-446655440000/history")
target_event = history[1]["id"] # Revert to second-most-recent state
reverted = client.post(
f"/v1/entities/550e8400-e29b-41d4-a716-446655440000/revert/{target_event}")
print(reverted["canonical_data"])curl -X POST "https://api.kanoniv.com/v1/entities/550e8400-e29b-41d4-a716-446655440000/revert/evt_002" \
-H "X-API-Key: kn_..."Response
Returns the updated CanonicalEntity with the restored data:
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"tenant_id": "t_abc123",
"entity_type": "customer",
"canonical_data": {
"email": "[email protected]",
"name": "John Doe"
},
"field_provenance": { "email": "Stripe", "name": "Salesforce" },
"confidence_score": 0.94,
"is_locked": false,
"created_at": "2026-01-15T10:00:00Z",
"updated_at": "2026-02-05T10:30:00Z"
}Returns 404 if the entity or audit event does not exist. Returns 400 if the audit event has no state to restore.
WARNING
The revert restores the after_state from the target audit event as the entity's current canonical_data. Make sure you select the correct event. Check its after_state in the history response before reverting.
