External API — API Keys, Webhooks & Consumer Endpoints¶
Blueprint prefix: /api/v1
Module: app.output.api
See API Reference for auth, errors, and pagination.
This module covers three concerns:
- API Keys — long-lived bearer tokens for scripts and integrations to call the Knora API without a user session.
- Webhooks — outbound HTTP callbacks fired when platform events occur inside an organisation.
- External consumer endpoints — API-key-authenticated routes for querying and listing knowledge programmatically.
All management endpoints (API keys, webhooks) require JWT auth, admin or manager role, and Growth plan or higher. External consumer endpoints (/external/*) use API key auth only.
API Keys¶
API keys are prefixed kn_ and generated from a URL-safe 32-byte random component. Knora stores only the SHA-256 hash and an 8-character display prefix — the full key is shown exactly once at creation and cannot be retrieved again.
Keys are scoped to the organisation. A key cannot access data from a different org. Each org may have up to 20 active API keys.
GET /api-keys¶
List all API keys for the caller's organisation. Key values are never returned — only metadata.
Auth: JWT (admin/manager) | Plan: Growth+
Response 200 OK
{
"api_keys": [
{
"id": "3f2a1c0e-8b4d-4f6e-9a2b-1c3d5e7f9a0b",
"name": "Production Sync",
"prefix": "kn_aB3xYz",
"is_active": true,
"created_at": "2025-11-10T09:14:32.000000+00:00",
"last_used_at": "2026-05-30T17:42:00.000000+00:00",
"request_count": 8214
},
{
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"name": "CI Pipeline",
"prefix": "kn_mN7pQr",
"is_active": true,
"created_at": "2026-01-22T14:00:00.000000+00:00",
"last_used_at": null,
"request_count": 0
}
]
}
| Field | Type | Description |
|---|---|---|
id |
UUID | Unique identifier. Used for revocation. |
name |
string | Human-readable label set at creation. |
prefix |
string | First 8 characters of the raw key. Safe to display. |
is_active |
boolean | Whether the key is currently active. |
created_at |
ISO-8601 | When the key was created. |
last_used_at |
ISO-8601 or null |
Most recent authenticated request, or null if never used. |
request_count |
integer | Total authenticated requests made with this key. |
POST /api-keys¶
Create a new API key. The full key value is returned exactly once. Store it securely immediately — it cannot be recovered later.
Auth: JWT (admin/manager) | Plan: Growth+
Request body
| Field | Type | Required | Constraints |
|---|---|---|---|
name |
string | Yes | 1–80 characters |
curl -X POST https://api.knora.io/api/v1/api-keys \
-H "Authorization: Bearer $KNORA_JWT" \
-H "Content-Type: application/json" \
-d '{"name": "Production Sync"}'
Response 201 Created
{
"id": "3f2a1c0e-8b4d-4f6e-9a2b-1c3d5e7f9a0b",
"name": "Production Sync",
"prefix": "kn_aB3xYz",
"is_active": true,
"created_at": "2026-05-31T11:00:00.000000+00:00",
"last_used_at": null,
"request_count": 0,
"key": "kn_aB3xYzDefGhiJklMnopQrstUvwxYz0123456789abc"
}
The key field is only present in this creation response. It will never appear again. Treat it like a password.
Errors
| HTTP | code |
Cause |
|---|---|---|
400 |
MISSING_NAME |
name is absent or empty. |
400 |
NAME_TOO_LONG |
name exceeds 80 characters. |
400 |
API_KEY_LIMIT_REACHED |
Org has reached the 20 active API key limit. |
GET /api-keys/usage¶
Aggregate usage statistics for all API keys in the caller's organisation.
Auth: JWT (admin/manager) | Plan: Growth+
requests_todayandrequests_this_monthare reserved fields not yet tracked. They always returnnull. Usetotal_requestsfrom individual key objects for usage decisions.
Response 200 OK
{
"key_count": 3,
"total_requests": 15420,
"requests_today": null,
"requests_this_month": null,
"rate_limit_per_minute": 60
}
| Field | Type | Description |
|---|---|---|
key_count |
integer | Total number of API keys in the org (active and revoked). |
total_requests |
integer | Sum of request_count across all API keys. |
requests_today |
null |
Reserved. Not yet tracked. |
requests_this_month |
null |
Reserved. Not yet tracked. |
rate_limit_per_minute |
integer | Platform rate limit per key per minute. Currently 60. |
DELETE /api-keys/{key_id}¶
Soft-revoke an API key. Sets is_active to false — the key record is preserved for audit history but any further requests using it are rejected. This action cannot be undone; create a new key if access needs to be restored.
Auth: JWT (admin/manager) | Plan: Growth+
curl -X DELETE https://api.knora.io/api/v1/api-keys/3f2a1c0e-8b4d-4f6e-9a2b-1c3d5e7f9a0b \
-H "Authorization: Bearer $KNORA_JWT"
Response 204 No Content — empty body.
Errors
| HTTP | code |
Cause |
|---|---|---|
400 |
INVALID_ID |
key_id is not a valid UUID. |
404 |
NOT_FOUND |
No API key with that ID found in the caller's org. |
Webhooks¶
Webhooks let external systems receive real-time notifications when events occur inside a Knora organisation. Each org may have up to 20 webhook endpoints.
Supported Events¶
| Event | Fired when |
|---|---|
knowledge.created |
A new knowledge entry is added. |
knowledge.updated |
An existing knowledge entry is modified. |
knowledge.deleted |
A knowledge entry is removed. |
member.invited |
A new member invitation is sent. |
member.removed |
A member is removed from the org. |
query.asked |
A user submits a query to the knowledge base. |
Webhook delivery¶
Knora delivers events as HTTP POST requests to the registered URL. Each delivery includes two signature headers for authenticity verification:
| Header | Value |
|---|---|
X-Knora-Signature |
sha256=<hmac-hex> — HMAC-SHA256 of the raw request body, keyed with the endpoint's secret. |
X-Knora-Event |
The event type string (e.g. knowledge.created). |
To verify a delivery, compute HMAC-SHA256(secret, raw_body) and compare it to the value after sha256=. Reject requests where the signatures do not match.
Only endpoints with is_active: true receive deliveries. Endpoints subscribed to specific events only receive deliveries for those events.
GET /webhooks¶
List all registered webhook endpoints for the caller's organisation.
Auth: JWT (admin/manager) | Plan: Growth+
Response 200 OK
{
"webhooks": [
{
"id": "c7e8f9a0-1b2c-3d4e-5f6a-7b8c9d0e1f2a",
"url": "https://integrations.example.com/knora/events",
"events": ["knowledge.created", "knowledge.updated", "query.asked"],
"is_active": true,
"created_at": "2026-03-15T08:30:00.000000+00:00"
}
]
}
| Field | Type | Description |
|---|---|---|
id |
UUID | Unique identifier. Used for deletion. |
url |
string | The HTTPS URL Knora will POST events to. |
events |
string[] | Event types this endpoint is subscribed to. |
is_active |
boolean | Whether the endpoint is active and receiving deliveries. |
created_at |
ISO-8601 | When the endpoint was registered. |
POST /webhooks¶
Register a new webhook endpoint. Returns the HMAC signing secret once — store it securely. The secret is not returned in any subsequent response.
Auth: JWT (admin/manager) | Plan: Growth+
Request body
| Field | Type | Required | Constraints |
|---|---|---|---|
url |
string | Yes | https:// only, ≤ 2048 chars, public host (no private/loopback IPs) |
events |
string[] | Yes | At least one item from the supported events list |
curl -X POST https://api.knora.io/api/v1/webhooks \
-H "Authorization: Bearer $KNORA_JWT" \
-H "Content-Type: application/json" \
-d '{
"url": "https://integrations.example.com/knora/events",
"events": ["knowledge.created", "knowledge.updated", "query.asked"]
}'
Response 201 Created
{
"id": "c7e8f9a0-1b2c-3d4e-5f6a-7b8c9d0e1f2a",
"url": "https://integrations.example.com/knora/events",
"events": ["knowledge.created", "knowledge.updated", "query.asked"],
"is_active": true,
"created_at": "2026-05-31T11:05:00.000000+00:00",
"secret": "whs_a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4"
}
The secret field is only present in this creation response. Use it to verify the X-Knora-Signature header on incoming deliveries.
Errors
| HTTP | code |
Cause |
|---|---|---|
400 |
MISSING_URL |
url is absent or empty. |
400 |
INVALID_URL |
url does not contain a valid hostname. |
400 |
INVALID_URL_SCHEME |
url does not use https://. Plain http:// is not accepted. |
400 |
URL_TOO_LONG |
url exceeds 2048 characters. |
400 |
BLOCKED_URL |
url resolves to a private, loopback, or link-local address (SSRF prevention). |
400 |
MISSING_EVENTS |
events array is absent or empty. |
400 |
INVALID_EVENTS |
One or more event types are not in the supported events list. |
400 |
WEBHOOK_LIMIT_REACHED |
Org has reached the 20 webhook endpoint limit. |
409 |
DUPLICATE_WEBHOOK_URL |
A webhook with this URL is already registered for the org. |
DELETE /webhooks/{webhook_id}¶
Remove a webhook endpoint. Knora stops delivering events to this URL immediately. The endpoint record is permanently deleted.
Auth: JWT (admin/manager) | Plan: Growth+
curl -X DELETE https://api.knora.io/api/v1/webhooks/c7e8f9a0-1b2c-3d4e-5f6a-7b8c9d0e1f2a \
-H "Authorization: Bearer $KNORA_JWT"
Response 204 No Content — empty body.
Errors
| HTTP | code |
Cause |
|---|---|---|
400 |
INVALID_ID |
webhook_id is not a valid UUID. |
404 |
NOT_FOUND |
No webhook with that ID found in the caller's org. |
External Consumer Endpoints¶
These routes are authenticated with an API key (not a JWT). Pass the key in the Authorization header:
Rate-limited to 60 requests per minute per key.
GET /external/query¶
Query the organisation's knowledge base using an API key. Delegates to the core RAG query service and returns an answer with citations.
Auth: API key | Plan: Growth+
Query parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
q |
string | Yes | The question or search text. |
curl "https://api.knora.io/api/v1/external/query?q=What+is+our+onboarding+process" \
-H "Authorization: Bearer kn_aB3xYzDefGhiJklMnopQrstUvwxYz0123456789abc"
Response 200 OK
{
"answer": "The onboarding process involves three phases...",
"sources": [
{
"id": "3f2a1c0e-8b4d-4f6e-9a2b-1c3d5e7f9a0b",
"title": "Onboarding Guide",
"excerpt": "Phase 1: Account setup and tool access..."
}
]
}
Errors
| HTTP | code |
Cause |
|---|---|---|
400 |
MISSING_QUERY |
q parameter is absent or empty. |
401 |
INVALID_API_KEY |
API key is missing, revoked, or does not match any active key. |
429 |
— | Rate limit exceeded (60 req/min per key). |
GET /external/knowledge¶
List knowledge entries for the organisation using an API key. Results are paginated via limit and offset.
Auth: API key | Plan: Growth+
Query parameters
| Parameter | Type | Default | Constraints | Description |
|---|---|---|---|---|
limit |
integer | 20 |
Max 100 |
Number of entries to return. |
offset |
integer | 0 |
Min 0 |
Number of entries to skip. |
curl "https://api.knora.io/api/v1/external/knowledge?limit=50&offset=0" \
-H "Authorization: Bearer kn_aB3xYzDefGhiJklMnopQrstUvwxYz0123456789abc"
Response 200 OK
{
"entries": [
{
"id": "3f2a1c0e-8b4d-4f6e-9a2b-1c3d5e7f9a0b",
"title": "Onboarding Guide",
"content": "Phase 1: Account setup...",
"created_at": "2026-01-10T10:00:00.000000+00:00"
}
],
"total": 142,
"limit": 50,
"offset": 0
}
| Field | Type | Description |
|---|---|---|
entries |
array | Knowledge entry objects for the current page. |
total |
integer | Total number of entries in the org. |
limit |
integer | The effective limit applied to this request. |
offset |
integer | The effective offset applied to this request. |
Errors
| HTTP | code |
Cause |
|---|---|---|
400 |
INVALID_PARAMS |
limit or offset are not integers. |
401 |
INVALID_API_KEY |
API key is missing, revoked, or does not match any active key. |
429 |
— | Rate limit exceeded (60 req/min per key). |
Notes¶
API key security¶
- The full key value (
kn_...) is returned once only in thePOST /api-keysresponse and is not stored in plaintext. - Knora stores a SHA-256 hash and an 8-character display prefix. The prefix is safe to show in UIs.
- If a key is lost or compromised, revoke it with
DELETE /api-keys/{key_id}and create a replacement. - Revoked keys have
is_active: falseand are preserved in the record for audit purposes.
Plan tiers¶
| Plan | API keys | Webhooks | External endpoints |
|---|---|---|---|
trial |
No | No | No |
starter |
No | No | No |
growth |
Yes | Yes | Yes |
enterprise |
Yes | Yes | Yes |