REST API
Base path: /api/v1
Auth column legend:
- Public — no authentication required
- Auth — login or API token required
- Org — organization member / editor / admin
- sysadmin — system administrator only
Datasets (packages)
Section titled “Datasets (packages)”| Method | Path | Description | Auth |
|---|---|---|---|
| GET | /packages | List datasets (with search and filters) | Public |
| POST | /packages | Create dataset (include resources array to create resources simultaneously) | Org editor |
| POST | /packages/drafts | Create draft dataset (every field optional) | Auth |
| GET | /packages/{nameOrId} | Get dataset details | Public |
| PUT | /packages/{nameOrId} | Update dataset (active: full replacement / draft: partial update; resources not included) | Org editor |
| DELETE | /packages/{nameOrId} | Delete dataset (active: soft delete / draft: immediate permanent delete) | Org editor |
| POST | /packages/{nameOrId}/publish | Publish a draft (draft → active) | Org editor |
| POST | /packages/{nameOrId}/restore | Restore soft-deleted dataset | sysadmin |
| POST | /packages/{nameOrId}/purge | Permanently delete soft-deleted dataset | Org admin |
| GET | /packages/{id}/resources | List resources | Public |
| POST | /packages/{id}/resources | Add resource | Org editor |
| PUT | /packages/{id}/resources/reorder | Reorder resources | Org editor |
Key query parameters (GET /packages)
Section titled “Key query parameters (GET /packages)”| Parameter | Description |
|---|---|
q | Search query (keywords or natural language; hybrid search) |
semantic | false limits results to keyword matches only (default: true) |
offset / limit | Pagination (max 100) |
organization[] | Filter by organization |
groups[] | Filter by category |
tags[] | Filter by tag |
res_format[] | Filter by resource format (e.g., CSV) |
license_id[] | Filter by license |
state | active / deleted / draft (draft requires auth; see below) |
my_org | Limit to user’s organizations |
private | Include private datasets |
sort_by | updated / created / name |
sort_order | asc / desc |
include_facets | Include facet information |
Example: dataset search
Section titled “Example: dataset search”curl "https://your-kukan-site/api/v1/packages?q=population&organization[]=stat-bureau&limit=10"Drafts
Section titled “Drafts”Datasets can be created as drafts and published once the publish requirements are met. Drafts never appear in search or listings (including the CKAN-compatible API) until published.
Create — POST /packages/drafts (auth required):
Every field is optional. When name is omitted, a placeholder of the form
untitled-xxxxxxxx is auto-generated (a draft cannot be published with the placeholder).
Specifying ownerOrg at creation requires editor rights in that organization.
curl -X POST https://your-kukan-site/api/v1/packages/drafts \ -H 'Authorization: Bearer <token>' \ -H 'Content-Type: application/json' \ -d '{"title": "Work-in-progress dataset"}'Publish — POST /packages/{nameOrId}/publish:
One-way draft → active transition (there is no way back to draft after publishing).
Returns 400 unless all three of the following are set:
nameset explicitly (the auto-generated placeholder is not accepted)ownerOrgsetlicenseIdset
Permission is the same as dataset update, and editor rights in the ownerOrg organization
are re-verified at publish time. Re-publishing an already active package is allowed and
re-runs the publish-time search index sync (idempotent — the retry entry point after a
failed sync).
List — GET /packages?state=draft (auth required):
Returns only drafts created by the caller plus drafts of organizations where the caller is
editor or above. Supported filters: q / name / organization[] / private /
sort_by / sort_order / offset / limit. Specifying tags[] / groups[] /
res_format[] / license_id[] / creator_user_id / my_org / include_facets
returns 400. Rows whose deletion failed partway (deletion incomplete) are included in
the listing.
Get, update, delete:
- Fetch details with
GET /packages/{id}?state=draft(auth and draft access required) PUTon a draft is a partial update: only the keys present in the request are applied, and an explicitnullclears that field.name: nullregenerates the placeholder (back to “unnamed”) andownerOrg: nullclears the organization (both block publishing again).PUTon anactivepackage remains full replacementDELETEon a draft skips the trash and permanently deletes it immediately (irreversible). If a deletion fails partway, re-running the sameDELETEcompletes the permanent deletion
Resources
Section titled “Resources”| Method | Path | Description | Auth |
|---|---|---|---|
| GET | /resources/count | Active resource count | Public |
| GET | /resources/formats | List used formats | Public |
| GET | /resources/{id} | Resource details | Public |
| GET | /resources/{id}/text | Text content (preview-size limited) | Public |
| GET | /resources/{id}/download | Download file (302 redirect for external URLs) | Public |
| GET | /resources/{id}/preview | Server-proxied preview (Range supported) | Public |
| GET | /resources/{id}/pipeline-status | Pipeline job status | Public |
| GET | /resources/{id}/schema | Column schema (names, types, row count, numeric stats). CSV/TSV only | Public |
| POST | /resources/{id}/query | Server-side DuckDB query (SELECT only). CSV/TSV only | Public |
| POST | /resources/{id}/upload-url | Issue presigned upload URL | Org editor |
| POST | /resources/{id}/upload | Server-proxied upload | Org editor |
| POST | /resources/{id}/upload-complete | Notify completion, enqueue pipeline | Org editor |
| POST | /resources/{id}/run-pipeline | Manually trigger pipeline | Org editor |
| PUT | /resources/{id} | Update resource (full replacement; extras is system-managed) | Org editor |
| DELETE | /resources/{id} | Delete resource | Org editor |
Schema and data query
Section titled “Schema and data query”CSV/TSV resources (with a pipeline-generated preview Parquet, ≤50 MB) support column schema
retrieval and read-only SQL queries. The MCP get_resource_schema / query_resource
tools offer the same capability for AI agents.
Get schema — GET /resources/{id}/schema:
{ "id": "…", "queryable": true, "schema": { "rowCount": 1688, "columns": [ { "name": "prefecture", "type": "string", "nullable": true, "nullCount": 3 }, { "name": "weight_limit", "type": "integer", "nullable": false, "nullCount": 0, "stats": { "min": "600", "max": "1350" } } ] }}Resources that cannot be queried (unsupported format, not yet processed) return
queryable: false, schema: null. type is one of integer / float / boolean / string;
stats is present only for numeric columns, and integer min/max are decimal strings.
Query data — POST /resources/{id}/query:
curl -X POST https://your-kukan-site/api/v1/resources/{id}/query \ -H 'Content-Type: application/json' \ -d '{"sql": "SELECT prefecture AS city, count(*) AS n FROM data GROUP BY 1 ORDER BY n DESC LIMIT 3"}'{ "id": "…", "columns": ["city", "n"], "rows": [ { "city": "Adachi", "n": "117" }, { "city": "Edogawa", "n": "110" }, { "city": "Ota", "n": "86" } ], "rowCount": 3, "truncated": false, "elapsedMs": 31}Query rules:
- The data is exposed as a table named
data. Double-quote column names that contain spaces or non-ASCII characters. - A single
SELECT/WITHstatement only. Writes and DDL (INSERT/UPDATE/DELETE/CREATE/DROP/ATTACH/COPY/PRAGMA, …) are rejected. - Runs in a throwaway in-memory DuckDB instance; all external access (files, URLs, extension loading) is disabled.
Limits and errors:
| Item | Value |
|---|---|
| Max rows | 10,000 (truncated: true when exceeded) |
| Max result size | 5 MB |
| Execution timeout | 15 s (408) |
| Concurrency | 1 (429 when exceeded) |
| Error | Condition |
|---|---|
400 | Invalid SQL / non-SELECT / over length / non-queryable resource |
404 | Resource not found / private without access |
408 | Execution timeout |
429 | Concurrent query limit |
Organizations
Section titled “Organizations”| Method | Path | Description | Auth |
|---|---|---|---|
| GET | /organizations | List organizations | Public |
| POST | /organizations | Create organization | sysadmin |
| GET | /organizations/{nameOrId} | Organization details | Public |
| PUT | /organizations/{nameOrId} | Update organization (full replacement) | Org admin |
| DELETE | /organizations/{nameOrId} | Soft-delete organization | Org admin |
| POST | /organizations/{nameOrId}/restore | Restore soft-deleted organization | sysadmin |
| POST | /organizations/{nameOrId}/purge | Permanently delete soft-deleted organization (async via SQS) | sysadmin |
| GET | /organizations/{nameOrId}/members | List members | Org member |
| POST | /organizations/{nameOrId}/members | Add member / change role | Org admin |
| DELETE | /organizations/{nameOrId}/members/{userId} | Remove member | Org admin |
Member roles are one of admin / editor / member.
Categories (groups)
Section titled “Categories (groups)”| Method | Path | Description | Auth |
|---|---|---|---|
| GET | /groups | List categories | Public |
| POST | /groups | Create category | sysadmin |
| GET | /groups/{nameOrId} | Category details | Public |
| PUT | /groups/{nameOrId} | Update category (full replacement) | Category admin |
| DELETE | /groups/{nameOrId} | Delete category | Category admin |
| POST | /groups/{nameOrId}/restore | Restore soft-deleted category | sysadmin |
| POST | /groups/{nameOrId}/purge | Permanently delete soft-deleted category | sysadmin |
| GET | /groups/{nameOrId}/members | List members | Category member |
| POST | /groups/{nameOrId}/members | Add member / change role | Category admin |
| DELETE | /groups/{nameOrId}/members/{userId} | Remove member | Category admin |
| Method | Path | Description | Auth |
|---|---|---|---|
| GET | /tags | List tags | Public |
| GET | /tags/{id} | Tag details | Public |
| Method | Path | Description | Auth |
|---|---|---|---|
| GET | /users/me | Current user info | Auth |
| GET | /users/me/organizations | User’s organizations | Auth |
| GET | /users | Search users (for member management) | Auth |
API tokens
Section titled “API tokens”| Method | Path | Description | Auth |
|---|---|---|---|
| POST | /api-tokens | Create token | Auth |
| GET | /api-tokens | List own tokens | Auth |
| DELETE | /api-tokens/{id} | Revoke token | Auth |
All sysadmin only.
| Method | Path | Description |
|---|---|---|
| GET | /admin/search/stats | Search index statistics (doc count, size, DB counts) |
| GET | /admin/search/doc/{index}/{id} | Get index document (index: packages / resources / contents) |
| GET | /admin/search/browse/{index} | Browse index documents (pagination, search) |
| POST | /admin/reindex-metadata | Rebuild search index (async via SQS) |
| POST | /admin/jobs/enqueue-all | Enqueue pipeline for all resources |
| GET | /admin/jobs/stats | Pipeline job statistics |
| GET | /admin/jobs | List pipeline jobs |
| DELETE | /admin/data | Delete all data (preserves users) |
| GET | /admin/health/stats | Health check statistics |
| GET | /admin/health | Health check results |
| GET | /admin/users/stats | User statistics |
| GET | /admin/users | List users |
| POST | /admin/users | Create user |
| PATCH | /admin/users/{userId} | Update user |
| DELETE | /admin/users/{userId} | Soft-delete user (revokes sessions/tokens) |
| POST | /admin/users/{userId}/restore | Restore user |
| POST | /admin/users/{userId}/purge | Permanently delete user |
| Method | Path | Description | Auth |
|---|---|---|---|
| GET | /api/health | Health check | Public |
| GET | /api/v1/site/settings | Site settings (registration etc.) | Public |