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
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:
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"
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
entry_type accepts: pass · flag · block · escalate
Required and optional fields:
| Field | Description |
|---|---|
| pipeline_id required | Your pipeline or process identifier |
| entry_type required | pass · flag · block · escalate |
| stage_slug required | The pipeline stage (e.g. credit-check) |
| summary required | Human-readable description of the decision |
| trust_score optional | 0.0 – 1.0 confidence float |
| model_version optional | Model identifier string |
| data_sources optional | Array of source identifiers |
| detail optional | Arbitrary JSON — stored verbatim |
| input_payload optional | The input that drove the decision |
| system_state optional | Snapshot of relevant system state |
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
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
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
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.
Every hour, an anchor job runs:
- All
entry_hashvalues are concatenated in chronological order - A SHA-256 root hash is computed over the concatenated bytes
- A DER-encoded RFC3161 TimeStampReq is submitted to FreeTSA
- The signed timestamp token is stored alongside the root hash
umbra_ledger. Records are permanent from the moment they land.
Next steps
Once your first records are flowing, use the reports endpoint to produce a signed evidence bundle — a self-contained JSON package suitable for auditors or regulators.
# Download a full evidence bundle for your org $ curl -s \ -H "Authorization: Bearer $UTP_API_KEY" \ "https://kaironull.com/api/v1/reports?limit=100" \ -o evidence-bundle.json