API Reference

All endpoints are JSON over HTTP.


Authentication

All authenticated requests require an API key in the x-api-key header.

x-api-key: your-api-key

API keys are issued during onboarding. Visit pricing to subscribe, or contact hello@chainoffact.com.


Rate Limits

Default rate limits apply per API key.

  • POST /api/witness: 60 requests per minute
  • GET /api/facts/*: 60 requests per minute
  • POST /api/verify/*: 60 requests per minute
  • POST /api/bundles/facts: 10 requests per minute

Higher limits available on request for production deployments.


Error Codes

400

Bad Request

Invalid request body or missing required fields.

401

Unauthorized

Missing or invalid API key.

409

Conflict

Duplicate witness artifact. This witnessHash has already been recorded.

429

Too Many Requests

Rate limit exceeded. Wait and retry.

500

Internal Server Error

Unexpected error. Contact support if persistent.


POST /api/witness

Ingests a verified witness artifact into the fact ledger. Requires API key.

Request

{
  "witnessVersion": "string",
  "intentHash": "sha256 hex (64 chars)",
  "verdictHash": "sha256 hex (optional)",
  "commitHash": "sha256 hex",
  "executionTarget": "string (optional)",
  "executionResultHash": "sha256 hex",
  "witnessHash": "sha256 hex",
  "timestamp": "ISO-8601 datetime",
  "executionReceipt": {
    "engineId": "string (optional)",
    "enginePublicKey": "string (optional)",
    "signature": "string (optional)",
    "status": "string (optional)"
  }
}

Response (201)

{
  "factHash": "sha256",
  "factObservedAt": "ISO-8601",
  "ledgerRoot": "sha256",
  "factCount": number
}

The witness artifact is immutable once recorded. Each produces exactly one canonical fact.


GET /api/facts/:factHash

Retrieves a canonical fact by its hash. Requires API key.

Response

  • Canonical fact object if found
  • { "state": "UNKNOWN" } if not found

POST /api/verify/fact

Verifies the integrity of a single fact by hash. Public endpoint.

Request

{
  "factHash": "sha256 hex (64 chars)"
}

Response

{
  "state": "MATCH | MISMATCH | UNKNOWN"
}

POST /api/verify/fact-chain

Verifies the integrity of the full fact ledger. Public endpoint.

Response

{
  "state": "MATCH | MISMATCH | ABSTAIN | UNKNOWN",
  "fact_count": number
}

GET /api/ledger/root

Returns the current ledger root. Public endpoint.

Response

{
  "ledgerRoot": "sha256",
  "factCount": number,
  "headFactHash": "sha256",
  "computedAt": "ISO-8601"
}

POST /api/bundles/facts

Generates a sealed fact evidence bundle. Requires API key.

Public Disclosure Warning

This endpoint may generate a publicly accessible, immutable verification artifact.

Once created:

  • The artifact cannot be modified or revoked
  • The artifact may be accessed by third parties
  • The artifact may be retained indefinitely

ChainOfFact does not evaluate whether publication is appropriate, safe, lawful, or advisable.

You are responsible for determining whether public disclosure is intended.

Response

{
  "bundle_id": "uuid",
  "created_utc": "ISO-8601",
  "chain_state": "MATCH | MISMATCH | ABSTAIN | UNKNOWN",
  "download_path": "string"
}

GET /api/bundles/download/:filename

Downloads a fact evidence bundle ZIP. Requires API key.


GET /api/health

Health and ledger status. Public endpoint.

Response

{
  "ok": true,
  "fact_ledger_head": "sha256 | null",
  "fact_count": number,
  "mode": "append-only"
}

Examples

Ingest a Witness Artifact (curl)

curl -X POST https://api.chainoffact.com/api/witness \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "witnessVersion": "chainoffact.witness.v1",
    "intentHash": "a1b2c3...64 hex chars",
    "commitHash": "d4e5f6...64 hex chars",
    "executionResultHash": "789abc...64 hex chars",
    "witnessHash": "def012...64 hex chars",
    "timestamp": "2026-01-29T18:42:00Z"
  }'

Ingest a Witness Artifact (Python)

import requests

response = requests.post(
    "https://api.chainoffact.com/api/witness",
    headers={
        "x-api-key": "YOUR_API_KEY",
        "Content-Type": "application/json"
    },
    json={
        "witnessVersion": "chainoffact.witness.v1",
        "intentHash": "a1b2c3...64 hex chars",
        "commitHash": "d4e5f6...64 hex chars",
        "executionResultHash": "789abc...64 hex chars",
        "witnessHash": "def012...64 hex chars",
        "timestamp": "2026-01-29T18:42:00Z"
    }
)

result = response.json()
print(f"Fact Hash: {result['factHash']}")
print(f"Ledger Root: {result['ledgerRoot']}")

Verify Fact Chain (curl)

curl -X POST https://api.chainoffact.com/api/verify/fact-chain \
  -H "Content-Type: application/json"

Verify Fact Chain (Python)

import requests

response = requests.post(
    "https://api.chainoffact.com/api/verify/fact-chain"
)

result = response.json()
print(f"State: {result['state']}")
print(f"Fact count: {result['fact_count']}")

Generate Fact Bundle (curl)

curl -X POST https://api.chainoffact.com/api/bundles/facts \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json"

Generate Fact Bundle (Python)

import requests

response = requests.post(
    "https://api.chainoffact.com/api/bundles/facts",
    headers={"x-api-key": "YOUR_API_KEY"}
)

result = response.json()
print(f"Bundle ID: {result['bundle_id']}")
print(f"Download: {result['download_path']}")

Direct Answer

ChainOfFact is accessible via a REST API for submitting witness artifacts, retrieving canonical facts, and verifying the complete ledger integrity.

Authentication

All write and read endpoints require an API key via the x-api-key header. API keys use the cof_ prefix and are provisioned via self-serve Stripe checkout. Keys are shown once at creation.


Fact Ingestion

POST /api/witness accepts a verified OpenWitness artifact. The system verifies the witness hash, checks Ed25519 receipt signature if present, and appends the canonical fact to the ledger.


Verification Endpoints

POST /api/verify/fact verifies a single fact hash. POST /api/verify/fact-chain verifies the entire ledger. Both return one of four proof states: MATCH, MISMATCH, ABSTAIN, or UNKNOWN.