TypeScript SDK
The @kanoniv/sdk package is a zero-dependency TypeScript client for the Kanoniv Cloud API. It uses native fetch (Node 18+ and modern browsers) and provides full type definitions for all resources.
Installation
bash
npm install @kanoniv/sdkQuick start
typescript
import { KanonivClient } from '@kanoniv/sdk';
const client = new KanonivClient({ apiKey: 'kn_...' });
// Resolve an identity
const entity = await client.resolve({ system: 'crm', externalId: 'sf_123' });
// Real-time resolve
const result = await client.resolveRt.realtime({
sourceName: 'crm',
externalId: 'cus_456',
data: { email: '[email protected]', name: 'Jane Doe' },
});
// Batch ingest
await client.ingest('crm', [
{ external_id: '1', email: '[email protected]', name: 'Alice' },
{ external_id: '2', email: '[email protected]', name: 'Bob' },
]);
client.close();Configuration
typescript
const client = new KanonivClient({
apiKey: 'kn_...', // API key (kn_ for prod, kn_test_ for sandbox)
// accessToken: 'jwt_...', // Or use JWT bearer token
baseUrl: 'https://api.kanoniv.com', // Default
timeout: 30000, // Request timeout in ms (default: 30s)
maxRetries: 2, // Retries on transient errors (default: 2)
});Sub-resources
The client exposes 12 sub-resources matching the API surface:
| Property | Class | Purpose |
|---|---|---|
client.entities | EntitiesResource | Search, get, link, lock, revert entities |
client.sources | SourcesResource | CRUD data sources, sync, preview, mappings |
client.resolveRt | ResolveResource | Real-time and bulk identity resolution |
client.jobs | JobsResource | List, run, cancel reconciliation jobs |
client.rules | RulesResource | List, create, view history of matching rules |
client.reviews | ReviewsResource | List and decide on pending match reviews |
client.overrides | OverridesResource | Force merge or split via manual overrides |
client.audit | AuditResource | View audit trail and entity event history |
client.specs | SpecsResource | List, get, upload identity specs |
client.feedback | FeedbackResource | Active learning feedback labels |
client.webhooks | WebhooksResource | Outbound webhook management |
client.sandbox | SandboxResource | Sandbox status and reset |
Top-level methods
typescript
// Resolve by source + ID or free-text query
await client.resolve({ system: 'crm', externalId: 'sf_123' });
await client.resolve({ query: '[email protected]' });
// Batch ingest records
await client.ingest('source_name', records, { entityType: 'person' });
// Dashboard statistics
await client.stats();Entities
typescript
// Search entities
const { data, total } = await client.entities.search({
q: 'jane',
entityType: 'person',
limit: 20,
});
// Get canonical entity
const entity = await client.entities.get('entity-uuid');
// Get entity with linked records
const linked = await client.entities.getLinked('entity-uuid');
// Bulk linked entities (max 1000)
const bulk = await client.entities.getLinkedBulk(['id1', 'id2']);
// Entity history
const history = await client.entities.history('entity-uuid');
// Lock entity
await client.entities.lock('entity-uuid');
// Revert to previous state
await client.entities.revert('entity-uuid', 'event-uuid');Real-time resolution
typescript
// Single record resolve
const result = await client.resolveRt.realtime({
sourceName: 'crm',
externalId: 'cus_123',
data: { email: '[email protected]', name: 'Jane' },
});
// result.entity_id, result.is_new, result.confidence
// Bulk resolve (max 1000 lookups)
const bulk = await client.resolveRt.bulk([
{ source: 'crm', id: 'cus_123' },
{ source: 'erp', id: 'emp_456' },
]);
// bulk.resolved, bulk.not_found, bulk.resultsWebhooks
typescript
// Create (signing secret returned only on creation)
const webhook = await client.webhooks.create({
url: 'https://your-server.com/hook',
eventTypes: ['entity.merged', 'reconciliation.completed'],
});
// List, get, delete, test
const all = await client.webhooks.list();
const one = await client.webhooks.get('wh-id');
await client.webhooks.delete('wh-id');
await client.webhooks.test('wh-id');
// Delivery history
const deliveries = await client.webhooks.deliveries('wh-id', { limit: 50 });Sandbox
typescript
const status = await client.sandbox.status();
// { is_sandbox: true, entity_count: 42, entity_limit: 1000, source_count: 3 }
const reset = await client.sandbox.reset();
// { message: "...", entities_deleted: 42 }Error handling
All errors extend KanonivError. Catch specific types for targeted handling:
typescript
import {
KanonivError,
ValidationError,
AuthenticationError,
NotFoundError,
RateLimitError,
ServerError,
} from '@kanoniv/sdk';
try {
await client.entities.get('nonexistent');
} catch (err) {
if (err instanceof NotFoundError) {
console.log('Entity not found');
} else if (err instanceof RateLimitError) {
console.log(`Retry after ${err.retryAfter}s`);
} else if (err instanceof KanonivError) {
console.log(`API error ${err.statusCode}: ${err.message}`);
}
}| Error class | HTTP status | When |
|---|---|---|
ValidationError | 400 | Invalid request body |
AuthenticationError | 401 | Missing or invalid credentials |
ForbiddenError | 403 | Insufficient permissions |
NotFoundError | 404 | Resource not found |
ConflictError | 409 | Duplicate resource |
RateLimitError | 429 | Rate or quota limit hit |
ServerError | 5xx | Server-side issue |
Automatic retries
The SDK automatically retries on transient errors (408, 429, 502, 503, 504) with exponential backoff. Rate limit responses honor the Retry-After header. Configure with maxRetries (default: 2).
Requirements
- Node.js 18+ (uses native
fetch) - Or any modern browser with
fetchsupport - Zero runtime dependencies
