KAIRONULL

Umbra Trust Protocol

Get to your first verified record in 5 minutes

You'll send an AI decision event to the UTP ledger, verify it with a public endpoint, and confirm it's sealed into an RFC3161-timestamped chain — without touching any infrastructure.

Estimated time: 5 minutes


01

Prerequisites

You need one API key tied to your organisation. Request access here — keys are issued by hand after review and no response time is promised. The key looks like:

API KEY FORMAT
utp_live_a3f7b2c1d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1
Your key is shown exactly once. Store it in a secrets manager or environment variable immediately. The server stores only the SHA-256 digest — the raw key cannot be recovered.

Set it as an environment variable for the examples below:

export UTP_API_KEY="utp_live_your_key_here"
$env:UTP_API_KEY = "utp_live_your_key_here"
02

Send your first record

POST to /api/v1/records with a JSON body describing the AI decision event. Every record is immediately hashed, chained to the previous entry, and sealed.

$ curl -s -X POST https://kaironull.com/api/v1/records \
  -H "Authorization: Bearer $UTP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "pipeline_id":  "loan-approval-v2",
    "entry_type":   "pass",
    "stage_slug":   "credit-check",
    "summary":      "Automated credit check passed for application #8821",
    "trust_score":  0.91,
    "model_version": "gemini-2.5-flash",
    "detail": {
      "applicant_id": "APP-8821",
      "score_band":   "A",
      "rule_version": "CREDIT-RULES-2026-Q2"
    }
  }'
import os, requests

resp = requests.post(
    "https://kaironull.com/api/v1/records",
    headers={
        "Authorization": f"Bearer {os.environ['UTP_API_KEY']}",
        "Content-Type": "application/json",
    },
    json={
        "pipeline_id":   "loan-approval-v2",
        "entry_type":    "pass",
        "stage_slug":    "credit-check",
        "summary":       "Automated credit check passed for #8821",
        "trust_score":   0.91,
        "model_version": "gemini-2.5-flash",
        "detail": {
            "applicant_id": "APP-8821",
            "score_band":   "A",
        },
    },
)

record = resp.json()
print(f"Entry hash: {record['entry_hash']}")
const res = await fetch('https://kaironull.com/api/v1/records', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${process.env.UTP_API_KEY}`,
    'Content-Type':  'application/json',
  },
  body: JSON.stringify({
    pipeline_id:   'loan-approval-v2',
    entry_type:    'pass',
    stage_slug:    'credit-check',
    summary:       'Automated credit check passed for #8821',
    trust_score:   0.91,
    model_version: 'gemini-2.5-flash',
    detail: { applicant_id: 'APP-8821', score_band: 'A' },
  }),
})

const { entry_hash } = await res.json()
console.log(`Hash: ${entry_hash}`)

Response 201 Created

{ "id": "f47ac10b-58cc-4372-a567-0e02b2c3d479", "entry_hash": "a3f7b2c1d4e5f609...c8d9e0f1", // 64-char hex, SHA-256 "prev_hash": "GENESIS", // or previous entry_hash "written_at": "2026-07-13T06:05:00.000Z" }
entry_hash Save this. You'll use it to verify the record and link it to an audit trail or evidence bundle.

entry_type accepts: pass · flag · block · escalate


Required and optional fields:

Field Description
pipeline_id requiredYour pipeline or process identifier
entry_type requiredpass · flag · block · escalate
stage_slug requiredThe pipeline stage (e.g. credit-check)
summary requiredHuman-readable description of the decision
trust_score optional0.0 – 1.0 confidence float
model_version optionalModel identifier string
data_sources optionalArray of source identifiers
detail optionalArbitrary JSON — stored verbatim
input_payload optionalThe input that drove the decision
system_state optionalSnapshot of relevant system state
03

Verify a record

Anyone can check a record by its entry_hash without credentials, and gets the public view: that the entry exists, when it was written, and whether an anchor covers it. The record's content stays private to your organisation. Send your API key to get the full record back. Auditors confirm a record they already hold by recomputing its hash from their copy.

$ curl -s https://kaironull.com/api/v1/verify/a3f7b2c1d4e5f609...c8d9e0f1
entry_hash = record["entry_hash"]

resp = requests.get(
    f"https://kaironull.com/api/v1/verify/{entry_hash}"
)
result = resp.json()

if result["found"]:
    print("✓ Record verified on-chain")
    if result["anchor"]["anchored"]:
        print(f"  Anchored at {result['anchor']['anchored_at']}")
else:
    print("✗ Hash not found")
const vRes = await fetch(
  `https://kaironull.com/api/v1/verify/${entry_hash}`
)
const { found, anchor } = await vRes.json()

if (found) {
  console.log('✓ Record verified on-chain')
  if (anchor.anchored)
    console.log(`  RFC3161 anchor: ${anchor.anchored_at}`)
} else {
  console.error('✗ Hash not found')
}

Response 200 OK — verified and anchored

{ "found": true, "visibility": "public", "record": { "entry_hash": "a3f7b2c1...", "prev_hash": "GENESIS", "written_at": "2026-07-13T06:05:00.000Z" }, "anchor": { "anchored": true, "anchored_at": "2026-07-13T07:05:03Z", // from FreeTSA RFC3161 "root_hash": "d9e8f7a6...", "scope": "tenant" } }
anchor.anchored will be false until the next hourly anchor run completes. Records are in the ledger immediately; the RFC3161 timestamp is applied within the hour.

Response — not found

{ "found": false }
04

Check chain status

A public endpoint returns the current ledger tip and last anchor. Use it in dashboards, uptime monitors, or compliance checks.

$ curl -s https://kaironull.com/api/v1/chain/status | jq
{ "chain_height": 1, "latest_entry_hash": "a3f7b2c1...", "latest_written_at": "2026-07-13T06:05:00.000Z", "last_anchor": { "root_hash": "d9e8f7a6...", "anchored_at": "2026-07-13T07:05:03Z", "entry_count": 1 }, "healthy": true }
healthy: true — the chain tip is within 10 minutes of now
healthy: false — no recent write; check your ingestion pipeline
05

How the chain works

Each record is linked to the one before it. Altering any record breaks every hash that follows — making the chain tamper-evident by construction.

Entry 1
prev: GENESIS
hash: a3f7b2c1…
→
Entry 2
prev: a3f7b2c1…
hash: 9d2e4f8a…
→
RFC3161 Anchor
root: SHA-256 of all hashes
FreeTSA timestamp token

Every hour, an anchor job runs:

  1. All entry_hash values are concatenated in chronological order
  2. A SHA-256 root hash is computed over the concatenated bytes
  3. A DER-encoded RFC3161 TimeStampReq is submitted to FreeTSA
  4. The signed timestamp token is stored alongside the root hash
The ledger is append-only. Database triggers block any UPDATE or DELETE on umbra_ledger. Records are permanent from the moment they land.
06

Next steps