API documentation
Register works, check hashes, and list registrations programmatically. Everything the web app can do, the API can do too.
Authentication
Most endpoints require an API key. Generate one from your dashboard. Send it as a Bearer token in the Authorization header:
Authorization: Bearer kdh_your_api_key_hereKeys are shown once on creation — store them securely. You can revoke a key at any time from the dashboard.
Base URL
https://keepdigitalhuman.com/api/v1Rate limiting
API requests are limited to 60 per minuteper API key. If you exceed this, you'll receive a 429 Too Many Requests response with a Retry-After header indicating how many seconds to wait.
Endpoints
/api/v1/registerAuth requiredRegister a new work. Hash your content client-side and send the hash — we never see the original content.
{
"title": "My blog post",
"hash": "a1b2c3d4...64-char SHA-256 hex string",
"contentType": "text",
"wordCount": 1200,
"fileName": null,
"fileSize": null,
"mimeType": null,
"parentId": null
}{
"id": "uuid-of-registration",
"hash": "a1b2c3d4...",
"title": "My blog post",
"verifyUrl": "https://keepdigitalhuman.com/verify/uuid"
}curl -X POST https://keepdigitalhuman.com/api/v1/register \
-H "Authorization: Bearer kdh_your_key" \
-H "Content-Type: application/json" \
-d '{
"title": "My blog post",
"hash": "a1b2c3d4e5f6...",
"contentType": "text",
"wordCount": 1200
}'parentId. The new registration will be linked to the original, and both will show a version history on their verification pages.const hash = Array.from(new Uint8Array(await crypto.subtle.digest("SHA-256", new TextEncoder().encode(text)))).map(b => b.toString(16).padStart(2, "0")).join("")/api/v1/register/batchAuth requiredRegister up to 50 works in a single request. Ideal for back-catalogues.
{
"items": [
{
"title": "Chapter 1",
"hash": "a1b2c3d4...",
"contentType": "text"
},
{
"title": "Chapter 2",
"hash": "e5f6a7b8...",
"contentType": "text"
}
]
}{
"total": 2,
"registered": 2,
"failed": 0,
"results": [
{
"index": 0,
"id": "uuid-1",
"hash": "a1b2c3d4...",
"title": "Chapter 1",
"verifyUrl": "https://keepdigitalhuman.com/verify/uuid-1"
},
{
"index": 1,
"id": "uuid-2",
"hash": "e5f6a7b8...",
"title": "Chapter 2",
"verifyUrl": "https://keepdigitalhuman.com/verify/uuid-2"
}
]
}title, hash, contentType, fileName, fileSize, mimeType, parentId). Items with missing title or hash are skipped and reported in the results array with an error field./api/v1/check/:hashCheck whether a SHA-256 hash matches any registered work. This endpoint is public — no API key needed.
{
"hash": "a1b2c3d4...",
"found": true,
"matches": [
{
"id": "uuid",
"title": "My blog post",
"contentType": "text",
"registeredAt": "2026-04-13T16:46:13.000Z",
"verifyUrl": "https://keepdigitalhuman.com/verify/uuid"
}
]
}curl https://keepdigitalhuman.com/api/v1/check/a1b2c3d4e5f6.../api/v1/registrationsAuth requiredList your registrations. Supports pagination with limit and offset query parameters.
| Parameter | Default | Description |
|---|---|---|
| limit | 50 | Number of results (max 100) |
| offset | 0 | Number of results to skip |
{
"registrations": [ ... ],
"total": 42,
"limit": 50,
"offset": 0
}/api/v1/registrations/:idAuth requiredGet the full details of a specific registration you own.
{
"id": "uuid",
"user_id": "clerk_user_id",
"title": "My blog post",
"content_hash": "a1b2c3d4...",
"content_type": "text",
"word_count": 1200,
"file_name": null,
"file_size": null,
"mime_type": null,
"thumbnail_url": null,
"registered_at": "2026-04-13T16:46:13.000Z"
}Open standard endpoints
These endpoints support the KDH Provenance Record standard. They're designed for AI platforms and tools that want to check content provenance at scale.
/api/v1/verify-bulkCheck up to 100 SHA-256 hashes against the registry in a single request. Public — no auth required.
{
"hashes": [
"a1b2c3d4...",
"e5f6a7b8...",
"c9d0e1f2..."
]
}{
"results": {
"a1b2c3d4...": { "found": true, "matches": [...] },
"e5f6a7b8...": { "found": false, "matches": [] }
},
"checked": 3,
"matched": 1
}/api/v1/provenance/:idGet the full machine-readable provenance record for a registration. Returns application/kdh-provenance+json.
{
"@context": "https://keepdigitalhuman.com/standard/v1",
"@type": "ProvenanceRecord",
"id": "urn:kdh:uuid",
"contentHash": { "algorithm": "SHA-256", "value": "..." },
"title": "...",
"registeredAt": "2026-04-13T16:46:13.000Z",
"registry": {
"name": "Keep Digital Human",
"verifyUrl": "https://keepdigitalhuman.com/verify/uuid"
}
}Error responses
All errors return a JSON object with an error field:
{
"error": "Description of what went wrong"
}| Status | Meaning |
|---|---|
| 400 | Bad request (missing or invalid parameters) |
| 401 | Unauthorised (missing or invalid API key) |
| 404 | Resource not found |
| 429 | Rate limit exceeded |
| 500 | Server error |
Browser extension
The Chrome extension uses this API under the hood. Install it to register works with a right-click, check pages against the registry, and get prompted when publishing on Medium, WordPress, or Ghost.
To install: open chrome://extensions, enable Developer mode, click "Load unpacked", and select the extension/ folder from the GitHub repository.
Need help?
Open an issue on GitHub or get in touch.