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.