Sources API
Manage data sources: the external systems from which Kanoniv reads records.
Overview
Sources represent the external systems (CRMs, billing platforms, databases) that feed data into Kanoniv. Each source has a type, a name, and a free-form JSON config.
| Method | Endpoint | Use Case |
|---|---|---|
| List | GET /v1/sources | List all sources for your tenant |
| Get | GET /v1/sources/:id | Get a specific source |
| Create | POST /v1/sources | Register a new data source |
| Update | PUT /v1/sources/:id | Update source name and config |
| Delete | DELETE /v1/sources/:id | Delete a source |
| Sync | POST /v1/sources/:id/sync | Trigger a manual sync |
GET /v1/sources
List all configured sources for the current tenant.
Request
import httpx
resp = httpx.get("https://api.kanoniv.com/v1/sources",
headers={"X-API-Key": "kn_..."})
sources = resp.json()
for source in sources:
print(f"{source['name']} ({source['source_type']})")curl "https://api.kanoniv.com/v1/sources" \
-H "X-API-Key: kn_..."Response
Returns an array of DataSource objects:
[
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"tenant_id": "t_abc123",
"name": "Stripe",
"source_type": "webhook",
"config": {
"entity_type": "customer",
"webhook_secret": "a1b2c3d4..."
},
"created_at": "2026-01-10T08:00:00Z"
},
{
"id": "550e8400-e29b-41d4-a716-446655440001",
"tenant_id": "t_abc123",
"name": "CRM Export",
"source_type": "file",
"config": {
"entity_type": "customer"
},
"created_at": "2026-01-12T10:00:00Z"
}
]Response Fields
| Field | Type | Description |
|---|---|---|
id | UUID | Source ID |
tenant_id | UUID | Tenant this source belongs to |
name | string | Human-readable source name |
source_type | string | Source type (e.g., "webhook", "file") |
config | object | Source-specific configuration (free-form JSON) |
created_at | timestamp | When the source was created |
GET /v1/sources/:id
Get details for a specific source.
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
id | UUID | Yes | Source ID |
Request
import httpx
resp = httpx.get("https://api.kanoniv.com/v1/sources/550e8400-e29b-41d4-a716-446655440000",
headers={"X-API-Key": "kn_..."})
source = resp.json()
print(f"Name: {source['name']}")
print(f"Type: {source['source_type']}")curl "https://api.kanoniv.com/v1/sources/550e8400-e29b-41d4-a716-446655440000" \
-H "X-API-Key: kn_..."Response
Returns a single DataSource object (same schema as list response).
Returns 404 if the source does not exist.
POST /v1/sources
Register a new data source.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Human-readable source name (1--100 characters) |
source_type | string | Yes | Source type (1--50 characters, e.g., "webhook", "file") |
config | object | Yes | Source-specific configuration (free-form JSON) |
Request
import httpx
resp = httpx.post("https://api.kanoniv.com/v1/sources",
headers={"X-API-Key": "kn_...", "Content-Type": "application/json"},
json={
"name": "Stripe",
"source_type": "webhook",
"config": {
"entity_type": "customer"
}
})
source = resp.json()
print(f"Created source: {source['id']}")
print(f"Webhook secret: {source['config']['webhook_secret']}")curl -X POST "https://api.kanoniv.com/v1/sources" \
-H "X-API-Key: kn_..." \
-H "Content-Type: application/json" \
-d '{
"name": "Stripe",
"source_type": "webhook",
"config": {
"entity_type": "customer"
}
}'Response
Returns 201 Created with the new DataSource:
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"tenant_id": "t_abc123",
"name": "Stripe",
"source_type": "webhook",
"config": {
"entity_type": "customer",
"webhook_secret": "a1b2c3d4e5f6..."
},
"created_at": "2026-02-05T10:00:00Z"
}Webhook Secret
When creating a source with source_type: "webhook", a webhook_secret is automatically generated and added to the config if one is not provided. Use this secret to sign webhook payloads with HMAC-SHA256.
PUT /v1/sources/:id
Update an existing source's name and configuration.
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
id | UUID | Yes | Source ID |
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Updated source name (1--100 characters) |
config | object | Yes | Updated configuration (free-form JSON) |
Request
import httpx
resp = httpx.put("https://api.kanoniv.com/v1/sources/550e8400-e29b-41d4-a716-446655440000",
headers={"X-API-Key": "kn_...", "Content-Type": "application/json"},
json={
"name": "Stripe Payments",
"config": {
"entity_type": "customer",
"webhook_secret": "a1b2c3d4e5f6..."
}
})
source = resp.json()
print(f"Updated: {source['name']}")curl -X PUT "https://api.kanoniv.com/v1/sources/550e8400-e29b-41d4-a716-446655440000" \
-H "X-API-Key: kn_..." \
-H "Content-Type: application/json" \
-d '{
"name": "Stripe Payments",
"config": {
"entity_type": "customer",
"webhook_secret": "a1b2c3d4e5f6..."
}
}'Response
Returns 200 OK with the updated DataSource object.
DELETE /v1/sources/:id
Delete a source.
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
id | UUID | Yes | Source ID |
Request
import httpx
resp = httpx.delete("https://api.kanoniv.com/v1/sources/550e8400-e29b-41d4-a716-446655440000",
headers={"X-API-Key": "kn_..."})
print(f"Deleted: {resp.status_code}") # 204curl -X DELETE "https://api.kanoniv.com/v1/sources/550e8400-e29b-41d4-a716-446655440000" \
-H "X-API-Key: kn_..."Response
Returns 204 No Content on success. Returns 404 if the source does not exist.
POST /v1/sources/:id/sync
Trigger a manual sync for a source. Currently returns 200 OK to acknowledge the request.
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
id | UUID | Yes | Source ID |
Request
import httpx
resp = httpx.post("https://api.kanoniv.com/v1/sources/550e8400-e29b-41d4-a716-446655440000/sync",
headers={"X-API-Key": "kn_..."})
print(f"Sync triggered: {resp.status_code}") # 200curl -X POST "https://api.kanoniv.com/v1/sources/550e8400-e29b-41d4-a716-446655440000/sync" \
-H "X-API-Key: kn_..."Response
Returns 200 OK with no body. Returns 404 if the source does not exist.
