Overview

All responses are JSON. Public endpoints require no credentials. Authenticated endpoints require a Bearer API key.

Base URL:

https://kerneloftruth.org/api.php

Authentication

Generate an API key from your Profile page. Keys begin with kot_ followed by 48 hex characters. Send your key with every authenticated request:

Authorization: Bearer kot_your_key_here

Keys are shown only once at creation. Revoke any key at any time from your profile.

Public endpoints

No authentication required.

GET ?action=check_hash&hash={sha256}

Check whether a SHA-256 hash has been claimed.

Example request:

https://kerneloftruth.org/api.php?action=check_hash&hash=e3b0c44298fc1c149afb...

Response (claimed):

{
  "claimed": true,
  "public_id": "abc123xyz",
  "claimer": "Jane Smith",
  "claimed_at": "2025-06-01T14:32:00Z",
  "verify_url": "https://kerneloftruth.org/verify/abc123xyz"
}

Response (not claimed):

{
  "claimed": false
}
GET ?action=claim&id={public_id}

Get full details for a claim by its public ID.

Example response:

{
  "public_id": "abc123xyz",
  "title": "My original essay",
  "description": "First draft, published June 2025.",
  "content_type": "text",
  "content_hash": "e3b0c44298fc1c149afb4c8996fb92427ae41e4649b934ca495991b7852b855",
  "hash_algorithm": "sha256",
  "claimer": "Jane Smith",
  "user_id": 42,
  "claimed_at": "2025-06-01T14:32:00Z",
  "verify_url": "https://kerneloftruth.org/verify/abc123xyz"
}
GET ?action=user&id={user_id}

Get a public user profile and their recent claims.

Example response:

{
  "user_id": 42,
  "name": "Jane Smith",
  "bio": "Writer and researcher.",
  "claim_count": 17,
  "recent_claims": [
    {
      "public_id": "abc123xyz",
      "title": "My original essay",
      "content_type": "text",
      "claimed_at": "2025-06-01T14:32:00Z",
      "verify_url": "https://kerneloftruth.org/verify/abc123xyz"
    }
  ]
}

Authenticated endpoints

All requests must include Authorization: Bearer kot_...

GET ?action=my_claims

List your claims. Supports the following query parameters:

p      Page number (default: 1)
limit  Results per page, max 100 (default: 20)
q      Search by title or description
type   Filter by type: text, document, image, other

Example response:

{
  "claims": [ ... ],
  "total": 17,
  "page": 1,
  "limit": 20
}
POST ?action=create_claim

Register a new claim. Send a JSON body:

{
  "hash": "e3b0c44298fc1c149afb4c8996fb92427ae41e4649b934ca495991b7852b855",
  "title": "My original essay",
  "content_type": "text",
  "description": "Optional description."
}

The hash field must be a 64-character lowercase SHA-256 hex string. Success response (HTTP 201):

{
  "success": true,
  "public_id": "abc123xyz",
  "verify_url": "https://kerneloftruth.org/verify/abc123xyz"
}

Webhooks

Configure a webhook URL from your Profile page. When an event fires, we POST a signed JSON payload to your URL.

Verifying signatures

Each request includes an X-KOT-Signature header:

X-KOT-Signature: sha256=HEX

Verify it in PHP:

$payload = file_get_contents('php://input');
$sig     = $_SERVER['HTTP_X_KOT_SIGNATURE'] ?? '';
$expect  = 'sha256=' . hash_hmac('sha256', $payload, YOUR_WEBHOOK_SECRET);
if (!hash_equals($expect, $sig)) {
    http_response_code(401);
    exit;
}

Or in Python:

import hmac, hashlib

def verify(payload: bytes, secret: str, header: str) -> bool:
    expected = 'sha256=' + hmac.new(
        secret.encode(), payload, hashlib.sha256
    ).hexdigest()
    return hmac.compare_digest(expected, header)

Events

EVENT claim.created

Fires when you register a new claim. Example payload:

{
  "event": "claim.created",
  "claim": {
    "public_id": "abc123xyz",
    "title": "My original essay",
    "content_type": "text",
    "content_hash": "e3b0c44298fc1c149afb4c8996fb92427ae41e4649b934ca495991b7852b855",
    "claimed_at": "2025-06-01T14:32:00Z",
    "verify_url": "https://kerneloftruth.org/verify/abc123xyz"
  }
}

Rate limits

Unauthenticated requests: 120 per minute per IP address.

Authenticated requests: 300 per minute per API key.

Exceeding the limit returns 429 Too Many Requests with a Retry-After: 60 header.