Skip to content

Admin API ​

User management, API keys, tenant settings, jobs, observability, billing, and dashboard stats.

Admin Only

User management, API key management, and tenant settings require the admin role. Requests from data or viewer roles will receive a 403 Forbidden response.

User Management ​

GET /v1/users ​

List all users in the current tenant.

python
import httpx

resp = httpx.get("https://api.kanoniv.com/v1/users",
    headers={"X-API-Key": "kn_..."})
users = resp.json()

for user in users:
    print(f"{user['email']} - role: {user['role']}")
bash
curl "https://api.kanoniv.com/v1/users" \
  -H "X-API-Key: kn_..."

Response ​

Returns an array of UserResponse objects:

json
[
  {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "tenant_id": "t_abc123",
    "external_id": null,
    "provisioning_source": null,
    "email": "[email protected]",
    "name": "Admin User",
    "role": "admin",
    "must_change_password": false,
    "is_verified": true,
    "created_at": "2026-01-01T00:00:00Z"
  }
]

UserResponse Fields ​

FieldTypeDescription
idUUIDUser ID
tenant_idUUIDTenant this user belongs to
external_idstringExternal identity provider ID (null for local users)
provisioning_sourcestringSSO/SCIM provisioning source (null for local users)
emailstringEmail address
namestringDisplay name
rolestringOne of: admin, data, viewer
must_change_passwordbooleanWhether the user must change their password on next login
is_verifiedbooleanWhether the email has been verified
created_attimestampWhen the user was created

POST /v1/users ​

Create a new user in the current tenant. Admin-created users are automatically verified.

Request Body ​

FieldTypeRequiredDescription
emailstringYesUser email address (max 255 characters)
namestringYesDisplay name (1--100 characters)
rolestringYesOne of: admin, data, viewer
passwordstringYesInitial password (8--128 characters)
bash
curl -X POST "https://api.kanoniv.com/v1/users" \
  -H "X-API-Key: kn_..." \
  -H "Content-Type: application/json" \
  -d '{
    "email": "[email protected]",
    "name": "Data Analyst",
    "role": "data",
    "password": "secure-password-123"
  }'

Response ​

Returns 201 Created with a UserResponse object.


PUT /v1/users/:id ​

Update a user's role.

Request Body ​

FieldTypeRequiredDescription
rolestringYesNew role: admin, data, or viewer
bash
curl -X PUT "https://api.kanoniv.com/v1/users/550e8400-e29b-41d4-a716-446655440000" \
  -H "X-API-Key: kn_..." \
  -H "Content-Type: application/json" \
  -d '{"role": "admin"}'

Response ​

Returns 200 OK with the updated UserResponse.


DELETE /v1/users/:id ​

Delete a user. You cannot delete yourself.

bash
curl -X DELETE "https://api.kanoniv.com/v1/users/550e8400-e29b-41d4-a716-446655440000" \
  -H "X-API-Key: kn_..."

Response ​

Returns 204 No Content on success.


API Key Management ​

GET /v1/api-keys ​

List all API keys for the current tenant.

bash
curl "https://api.kanoniv.com/v1/api-keys" \
  -H "X-API-Key: kn_..."

Response ​

Returns an array of ApiKey objects:

json
[
  {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "tenant_id": "t_abc123",
    "name": "Production Integration",
    "key_hash": "a1b2c3d4...",
    "key_prefix": "kn_abc12",
    "scopes": ["data"],
    "expires_at": null,
    "last_used_at": "2026-02-05T09:45:00Z",
    "created_at": "2026-01-20T10:00:00Z"
  }
]

ApiKey Fields ​

FieldTypeDescription
idUUIDKey ID
tenant_idUUIDTenant this key belongs to
namestringHuman-readable key name
key_hashstringSHA-256 hash of the key (for verification)
key_prefixstringFirst 8 characters of the key (for identification)
scopesJSONPermission scopes (e.g., ["admin"], ["data"], ["ingest"], or [] for full access)
expires_attimestampKey expiration (null for non-expiring keys)
last_used_attimestampLast time the key was used (null if never used)
created_attimestampWhen the key was created

POST /v1/api-keys ​

Create a new API key. The full key value is returned only once in the response.

Request Body ​

FieldTypeRequiredDescription
namestringYesHuman-readable key name (1--200 characters)
expires_attimestampNoOptional expiration date
scopesJSONNoPermission scopes (defaults to [] for full access)
bash
curl -X POST "https://api.kanoniv.com/v1/api-keys" \
  -H "X-API-Key: kn_..." \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Data Pipeline",
    "scopes": ["data"]
  }'

Response ​

Returns 201 Created:

json
{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "name": "Data Pipeline",
  "api_key": "kn_a1b2c3d4e5f6...",
  "expires_at": null
}

Save your API key

The full API key value is only returned once at creation time. Store it securely. If lost, revoke the key and create a new one.


DELETE /v1/api-keys/:id ​

Revoke an API key. Requires admin role.

bash
curl -X DELETE "https://api.kanoniv.com/v1/api-keys/550e8400-e29b-41d4-a716-446655440000" \
  -H "X-API-Key: kn_..."

Response ​

Returns 204 No Content on success.


Tenant Settings ​

PATCH /v1/tenant ​

Update tenant name and settings. Settings are merged; existing keys not included in the request are preserved.

Request Body ​

FieldTypeRequiredDescription
namestringNoUpdated tenant name
settingsobjectNoSettings to merge into current tenant settings
bash
curl -X PATCH "https://api.kanoniv.com/v1/tenant" \
  -H "X-API-Key: kn_..." \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Acme Corp",
    "settings": {
      "default_entity_type": "customer"
    }
  }'

Response ​

Returns 200 OK with the full Tenant object.


Reconciliation Settings ​

GET /v1/settings/reconciliation ​

Get reconciliation threshold settings. These are stored in the tenant's settings.reconciliation JSON path.

bash
curl "https://api.kanoniv.com/v1/settings/reconciliation" \
  -H "X-API-Key: kn_..."

Response ​

json
{
  "merge_threshold": 0.85,
  "review_threshold": 0.60
}
FieldTypeDescription
merge_thresholdfloatScore above which entities are auto-merged
review_thresholdfloatScore above which entities are queued for review

PATCH /v1/settings/reconciliation ​

Update reconciliation thresholds.

bash
curl -X PATCH "https://api.kanoniv.com/v1/settings/reconciliation" \
  -H "X-API-Key: kn_..." \
  -H "Content-Type: application/json" \
  -d '{
    "merge_threshold": 0.90,
    "review_threshold": 0.70
  }'

Response ​

Returns 200 OK with the updated ReconciliationSettings.


Survivorship Policies ​

GET /v1/settings/survivorship ​

List survivorship policies that control field-level source prioritization.

bash
curl "https://api.kanoniv.com/v1/settings/survivorship" \
  -H "X-API-Key: kn_..."

Response ​

Returns an array of SurvivorshipPolicy objects:

json
[
  {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "tenant_id": "t_abc123",
    "field_name": "email",
    "priority_config": {
      "strategy": "source_priority",
      "sources": ["Salesforce", "Stripe", "HubSpot"]
    },
    "is_active": true,
    "created_at": "2026-01-15T10:00:00Z",
    "updated_at": "2026-02-01T09:00:00Z"
  }
]
FieldTypeDescription
idUUIDPolicy ID
tenant_idUUIDTenant this policy belongs to
field_namestringThe canonical field this policy applies to
priority_configobjectFree-form JSON with strategy and prioritization rules
is_activebooleanWhether this policy is active
created_attimestampWhen the policy was created
updated_attimestampWhen the policy was last updated

POST /v1/settings/survivorship ​

Create or update a survivorship policy. If the id is a nil UUID or omitted, a new policy is created.

bash
curl -X POST "https://api.kanoniv.com/v1/settings/survivorship" \
  -H "X-API-Key: kn_..." \
  -H "Content-Type: application/json" \
  -d '{
    "field_name": "email",
    "priority_config": {
      "strategy": "source_priority",
      "sources": ["Salesforce", "Stripe"]
    },
    "is_active": true
  }'

Response ​

Returns 200 OK with the upserted SurvivorshipPolicy.

DELETE /v1/settings/survivorship/:id ​

Delete a survivorship policy. Returns 204 No Content.


Audit Streams ​

GET /v1/settings/audit-streams ​

List configured audit log streaming destinations.

Response ​

Returns an array of AuditStream objects:

json
[
  {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "tenant_id": "t_abc123",
    "destination_type": "webhook",
    "destination_url": "https://logs.company.com/audit",
    "auth_config": { "header": "X-Auth-Token", "value": "secret" },
    "is_active": true,
    "created_at": "2026-01-15T10:00:00Z",
    "updated_at": "2026-02-01T09:00:00Z"
  }
]

POST /v1/settings/audit-streams ​

Create a new audit stream. Returns 201 Created with the AuditStream.

PUT /v1/settings/audit-streams/:id ​

Update an existing audit stream. Returns 200 OK with the updated AuditStream.

DELETE /v1/settings/audit-streams/:id ​

Delete an audit stream. Returns 204 No Content.


Retention Policies ​

GET /v1/settings/retention-policies ​

List data retention policies.

Response ​

Returns an array of RetentionPolicy objects:

json
[
  {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "tenant_id": "t_abc123",
    "entity_type": "customer",
    "retention_days": 365,
    "shred_pii": true,
    "is_active": true,
    "created_at": "2026-01-15T10:00:00Z",
    "updated_at": "2026-02-01T09:00:00Z"
  }
]
FieldTypeDescription
entity_typestringEntity type this policy applies to
retention_daysintegerDays to retain data before cleanup
shred_piibooleanWhether to shred PII fields on cleanup
is_activebooleanWhether this policy is active

POST /v1/settings/retention-policies ​

Create or update a retention policy. Returns 200 OK with the RetentionPolicy.

DELETE /v1/settings/retention-policies/:id ​

Delete a retention policy. Returns 204 No Content.


SSO Configuration ​

GET /v1/settings/sso-config ​

List SSO configurations for the tenant.

Response ​

Returns an array of SsoConfig objects:

json
[
  {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "tenant_id": "t_abc123",
    "provider_type": "oidc",
    "display_name": "Company SSO",
    "issuer_url": "https://accounts.google.com",
    "client_id": "123456.apps.googleusercontent.com",
    "client_secret_enc": "encrypted...",
    "auth_url": "https://accounts.google.com/o/oauth2/auth",
    "token_url": "https://oauth2.googleapis.com/token",
    "jwks_url": "https://www.googleapis.com/oauth2/v3/certs",
    "saml_metadata_url": null,
    "is_active": true,
    "created_at": "2026-01-15T10:00:00Z",
    "updated_at": "2026-02-01T09:00:00Z"
  }
]

POST /v1/settings/sso-config ​

Create or update an SSO configuration. If id is nil, a new config is created; otherwise the existing config is updated. Returns 200 OK with the SsoConfig.

DELETE /v1/settings/sso-config/:id ​

Delete an SSO configuration. Returns 204 No Content.


Jobs ​

GET /v1/jobs ​

List reconciliation jobs for your tenant.

Query Parameters ​

ParameterTypeDefaultDescription
limitinteger50Max results (capped at 200)
job_typestringN/AFilter by job type
bash
curl "https://api.kanoniv.com/v1/jobs?limit=20" \
  -H "X-API-Key: kn_..."

Response ​

Returns an array of BatchRun objects:

json
[
  {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "tenant_id": "t_abc123",
    "status": "completed",
    "job_type": "reconciliation",
    "stats": { "entities_processed": 5000, "merges": 120, "splits": 5 },
    "started_at": "2026-02-05T09:00:00Z",
    "completed_at": "2026-02-05T09:05:00Z",
    "triggered_by": "660e8400-e29b-41d4-a716-446655440001",
    "created_at": "2026-02-05T09:00:00Z"
  }
]

BatchRun Fields ​

FieldTypeDescription
idUUIDJob ID
tenant_idUUIDTenant this job belongs to
statusstringJob status (e.g., "pending", "running", "completed", "failed", "cancelled")
job_typestringJob type (e.g., "reconciliation")
statsobjectFree-form JSON with execution statistics
started_attimestampWhen the job started (null if pending)
completed_attimestampWhen the job completed (null if still running)
triggered_byUUIDUser ID who triggered the job (null for scheduled jobs)
created_attimestampWhen the job was created

POST /v1/jobs/run ​

Trigger a new reconciliation job. The job is queued and picked up by a worker.

Request Body ​

FieldTypeRequiredDescription
job_typestringNoJob type (defaults to "reconciliation", max 50 characters)
payloadobjectNoFree-form JSON payload for the job
bash
curl -X POST "https://api.kanoniv.com/v1/jobs/run" \
  -H "X-API-Key: kn_..." \
  -H "Content-Type: application/json" \
  -d '{}'

Response ​

Returns 202 Accepted:

json
{
  "job_id": "550e8400-e29b-41d4-a716-446655440000",
  "status": "pending"
}

GET /v1/jobs/:id ​

Get details for a specific job. Returns 404 if not found.

Response ​

Returns a BatchRun object (same schema as list response).


POST /v1/jobs/:id/cancel ​

Cancel a pending or locked job. Returns 200 OK on success, 404 if the job is not found or not in a cancellable state.


Observability ​

GET /v1/identity/specs/:version/summary ​

Get a static plan summary for a compiled identity spec. Returns analysis of rules, risk flags, and coverage.

bash
curl "https://api.kanoniv.com/v1/identity/specs/customer-v3/summary" \
  -H "X-API-Key: kn_..."

Response ​

Returns a PlanSummary object with rule counts, risk analysis, and coverage breakdown.


GET /v1/jobs/:id/summary ​

Get the identity summary from a completed reconciliation job. Returns 400 if the job has not completed.

Response ​

Returns an IdentitySummary extracted from the job's stats.identity_summary.


GET /v1/jobs/:id/health ​

Get health metrics from a completed reconciliation job. Returns 400 if the job has not completed.

Response ​

Returns a RunHealth object extracted from the job's stats.run_health.


GET /v1/jobs/:id/telemetry ​

Get per-rule telemetry data from a completed reconciliation job. Returns 400 if the job has not completed.

Response ​

json
{
  "rules": [
    {
      "rule_name": "email_exact",
      "matches": 1200,
      "avg_score": 0.95,
      "p50_latency_ms": 2,
      "p99_latency_ms": 15
    }
  ]
}

GET /v1/jobs/:id/diff ​

Compare two reconciliation runs. Requires baseline_id query parameter. Currently a placeholder; returns a message indicating the feature is coming in a future release.

Query Parameters ​

ParameterTypeRequiredDescription
baseline_idUUIDYesThe baseline job ID to compare against

Billing ​

POST /v1/billing/checkout ​

Create a Stripe checkout session for subscribing to a plan.

Request Body ​

FieldTypeRequiredDescription
planstringYesPlan name: "starter" or "growth"
bash
curl -X POST "https://api.kanoniv.com/v1/billing/checkout" \
  -H "X-API-Key: kn_..." \
  -H "Content-Type: application/json" \
  -d '{"plan": "starter"}'

Response ​

json
{
  "checkout_url": "https://checkout.stripe.com/c/pay/cs_..."
}

Redirect the user to checkout_url to complete payment. Cloud plans require contacting sales.


POST /v1/billing/portal ​

Create a Stripe billing portal session for managing subscriptions, invoices, and payment methods.

bash
curl -X POST "https://api.kanoniv.com/v1/billing/portal" \
  -H "X-API-Key: kn_..."

Response ​

json
{
  "portal_url": "https://billing.stripe.com/p/session/..."
}

Returns 400 if no billing account exists (subscribe first).


GET /v1/billing/status ​

Get current billing status and usage.

bash
curl "https://api.kanoniv.com/v1/billing/status" \
  -H "X-API-Key: kn_..."

Response ​

json
{
  "plan": "starter",
  "billing_status": "active",
  "identity_count": 45000,
  "included_limit": 100000,
  "overage": 0,
  "is_trial": false
}
FieldTypeDescription
planstringCurrent tier: "local", or "cloud"
billing_statusstringBilling state (e.g., "active", "past_due", "canceled")
identity_countintegerCurrent number of external entities
included_limitintegerEntities included in the plan (Local: unlimited local, Cloud: per agreement)
overageintegerEntities exceeding the included limit
is_trialbooleanWhether the tenant is on a trial (no billing account)

Dashboard Stats ​

GET /v1/stats ​

Get dashboard statistics for the current tenant.

bash
curl "https://api.kanoniv.com/v1/stats" \
  -H "X-API-Key: kn_..."

Response ​

json
{
  "total_canonical_entities": 12500,
  "total_external_entities": 45000,
  "pending_reviews": 23,
  "merge_rate": 0.87
}
FieldTypeDescription
total_canonical_entitiesintegerTotal canonical entities for the tenant
total_external_entitiesintegerTotal external entities for the tenant
pending_reviewsintegerEntity pairs awaiting manual review
merge_ratefloatRatio of merge decisions to total match results

Roles Reference ​

RoleUsersAPI KeysSettingsSourcesRulesOverridesJobs
adminFullFullFullFullFullFullFull
dataN/AN/AN/ARead/WriteRead/WriteRead/WriteRead/Write
viewerN/AN/AN/AReadReadReadRead

The identity and delegation layer for AI agents.