Quick Start
Get audit logging running in your AI pipeline in under 5 minutes. You need an API key — sign up at /signup to get one, or find it in Settings.
Ingest Endpoint
POST /api/decisions/ingest — Send a decision record directly to your dashboard. No SDK needed — just an HTTP POST with your API key.
Copy-paste ready
Replace your-dashboard-url with your deployed dashboard URL and sk_live_your_key_here with your API key from Settings.
curl
curl -X POST https://your-dashboard-url/api/decisions/ingest \
-H "Content-Type: application/json" \
-H "X-API-Key: sk_live_your_key_here" \
-d '{
"decision_type": "cv_screening",
"inputs": {
"candidate_id": "c_abc123",
"cv_text": "Senior engineer with 8 years experience..."
},
"output": {
"score": 0.82,
"decision": "shortlist",
"reasons": ["relevant experience", "skill match"]
},
"model": { "name": "gpt-4", "version": "2025-01" },
"actor": { "user_id": "recruiter_42", "role": "hiring_manager" },
"confidence": 0.82
}'JavaScript / TypeScript
// JavaScript / TypeScript — zero dependencies, uses native fetch
const response = await fetch("https://your-dashboard-url/api/decisions/ingest", {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-API-Key": "sk_live_your_key_here",
},
body: JSON.stringify({
decision_type: "cv_screening",
inputs: {
candidate_id: "c_abc123",
cv_text: "Senior engineer with 8 years experience...",
},
output: {
score: 0.82,
decision: "shortlist",
reasons: ["relevant experience", "skill match"],
},
model: { name: "gpt-4", version: "2025-01" },
actor: { user_id: "recruiter_42", role: "hiring_manager" },
confidence: 0.82,
}),
});
const result = await response.json();
console.log(result);
// → { id: "...", hash: "a1b2c3...", status: "logged", created_at: "..." }Python
import requests
response = requests.post(
"https://your-dashboard-url/api/decisions/ingest",
headers={
"Content-Type": "application/json",
"X-API-Key": "sk_live_your_key_here",
},
json={
"decision_type": "cv_screening",
"inputs": {
"candidate_id": "c_abc123",
"cv_text": "Senior engineer with 8 years experience...",
},
"output": {
"score": 0.82,
"decision": "shortlist",
"reasons": ["relevant experience", "skill match"],
},
"model": {"name": "gpt-4", "version": "2025-01"},
"actor": {"user_id": "recruiter_42", "role": "hiring_manager"},
"confidence": 0.82,
},
)
print(response.json())
# → {"id": "...", "hash": "a1b2c3...", "status": "logged", "created_at": "..."}Response examples
// 201 Created
{
"id": "d_abc123-...",
"hash": "a1b2c3d4e5f6...",
"previous_hash": "9f8e7d6c5b4a...",
"created_at": "2026-03-11T14:30:00.000Z",
"decision_type": "cv_screening",
"status": "logged"
}
// 400 Validation Error
{
"error": "Validation failed.",
"details": [
"decision_type: decision_type is required",
"inputs: inputs must not be empty"
],
"expected_schema": {
"decision_type": "string (required)",
"inputs": "object (required)",
"output": "object (required)",
"confidence": "number 0–1 (optional)",
...
}
}
// 401 Unauthorized
{
"error": "Missing API key.",
"hint": "Include an X-API-Key header with your API key."
}Required fields
decision_type — a string label like "cv_screening" or "interview_ranking"
inputs — an object with the data your model received (must have at least one key)
output — an object with what the model decided (include a "decision" key for best dashboard integration)
Optional fields
model — {name, version, provider}
actor — {user_id, role, authority_level}
confidence — number between 0 and 1
human_override — object if a human overrode the AI decision
metadata — any extra context you want to attach
Authentication
Every request must include an X-API-Key header. Find your key in Settings → API Key.
Keys use the format sk_live_{ uuid }. Keep it secret — it grants write access to your audit trail.
Python SDK
Install from PyPI:
pip install gettraceaiLog your first decision:
from gettraceai import TraceAI
trace = TraceAI(api_key="sk_live_your_key_here")
trace.log(
decision_type="cv_screening",
inputs={"candidate_id": "c_abc123", "cv_text": "Senior engineer..."},
output={"score": 0.82, "decision": "shortlist"},
model={"name": "gpt-4", "version": "2025-01"},
actor={"user_id": "recruiter_42", "role": "hiring_manager"},
)silent=True (default) — errors are logged to stderr but never crash your pipeline.
silent=False — raises exceptions, useful for development and testing.
5xx errors are retried up to 3 times with exponential backoff.
Node.js SDK
Install from npm (zero dependencies, uses native fetch):
npm install gettraceaiLog your first decision:
const { TraceAI } = require("gettraceai");
const trace = new TraceAI({ apiKey: "sk_live_your_key_here" });
await trace.log({
decisionType: "cv_screening",
inputs: { candidateId: "c_abc123", cvText: "Senior engineer..." },
output: { score: 0.82, decision: "shortlist" },
model: { name: "gpt-4", version: "2025-01" },
actor: { userId: "recruiter_42", role: "hiring_manager" },
});API Endpoints
All endpoints (except health) require an X-API-Key header with your API key. The base URL is your deployed API instance.
| Method | Path | Auth | Purpose |
|---|---|---|---|
| POST | /api/decisions/ingest | API key | Log a decision (dashboard endpoint) |
| POST | /v1/decisions | API key | Log a single decision |
| POST | /v1/decisions/batch | API key | Log up to 100 decisions |
| GET | /v1/decisions | API key | List, filter, and paginate decisions |
| GET | /v1/decisions/:id | API key | Get full decision detail |
| GET | /v1/decisions/export | API key | CSV export (max 10k records) |
| GET | /v1/decisions/:id/verify | API key | Verify hash chain integrity |
| GET | /v1/stats | API key | Usage statistics |
| GET | /v1/health | None | Health check |
Log a Decision
POST /v1/decisions — Log a single AI decision with all relevant context.
curl -X POST https://your-api-url/v1/decisions \
-H "Content-Type: application/json" \
-H "X-API-Key: sk_live_your_key_here" \
-d '{
"decision_type": "cv_screening",
"inputs": {"candidate_id": "c_abc123"},
"output": {"score": 0.82, "decision": "shortlist"},
"model": {"name": "gpt-4"},
"actor": {"user_id": "recruiter_42"}
}'Returns the created decision record including its id and hash.
Batch Log
POST /v1/decisions/batch — Log up to 100 decisions in a single request. Same schema as single, wrapped in a decisions array.
curl -X POST https://your-api-url/v1/decisions/batch \
-H "Content-Type: application/json" \
-H "X-API-Key: sk_live_your_key_here" \
-d '{
"decisions": [
{
"decision_type": "cv_screening",
"inputs": {"candidate_id": "c_001"},
"output": {"decision": "shortlist"}
},
{
"decision_type": "cv_screening",
"inputs": {"candidate_id": "c_002"},
"output": {"decision": "reject"}
}
]
}'List Decisions
GET /v1/decisions — Paginated list with optional filters.
# List decisions with filters
curl "https://your-api-url/v1/decisions?decision_type=cv_screening&limit=20&page=1" \
-H "X-API-Key: sk_live_your_key_here"Query parameters:
decision_type — filter by type (e.g. cv_screening)
from / to — ISO date range
outcome — filter by output.decision value
page / limit — pagination (default: page 1, limit 50, max 200)
sort / order — sort field and direction (asc/desc)
Get Decision
GET /v1/decisions/:id — Full detail for a single decision including all JSONB fields.
# Get a single decision by ID
curl "https://your-api-url/v1/decisions/DECISION_ID" \
-H "X-API-Key: sk_live_your_key_here"Export CSV
GET /v1/decisions/export — Download decisions as a CSV file. Supports the same filters as the list endpoint. Maximum 10,000 records per export.
# Export up to 10,000 records as CSV
curl "https://your-api-url/v1/decisions/export?from=2026-01-01&to=2026-03-31" \
-H "X-API-Key: sk_live_your_key_here" \
-o decisions.csvVerify Hash Chain
GET /v1/decisions/:id/verify — Checks that a decision's hash is valid and its chain to the previous record is intact. Use this to prove records haven't been tampered with.
# Verify a decision's hash chain integrity
curl "https://your-api-url/v1/decisions/DECISION_ID/verify" \
-H "X-API-Key: sk_live_your_key_here"
# Response:
# {
# "id": "...",
# "hash_valid": true,
# "chain_valid": true,
# "verified_at": "2026-03-09T12:00:00.000Z"
# }hash_valid — the record's own hash matches its contents
chain_valid — the record correctly chains to the previous hash
Usage Stats
GET /v1/stats — Returns total decisions, today's count, monthly usage, and breakdown by decision type.
curl "https://your-api-url/v1/stats" \
-H "X-API-Key: sk_live_your_key_here"What Gets Logged
Every decision record captures the full context of an AI decision. Here's the complete payload with all fields:
{
"decision_type": "cv_screening", // Required — what kind of decision
"inputs": { // Required — data the model received
"candidate_id": "c_abc123",
"cv_text": "Senior engineer with 8 years..."
},
"output": { // Required — what the model decided
"score": 0.82,
"decision": "shortlist",
"reasons": ["relevant experience", "skill match"]
},
"model": { // Optional — which model made it
"name": "gpt-4",
"version": "2025-01",
"provider": "openai"
},
"actor": { // Optional — who triggered it
"user_id": "recruiter_42",
"role": "hiring_manager",
"authority_level": "senior"
},
"confidence": 0.82, // Optional — 0 to 1
"human_override": { // Optional — if a human overrode it
"original_decision": "reject",
"override_decision": "shortlist",
"reason": "Candidate has domain expertise",
"overridden_by": "manager_7"
},
"metadata": { // Optional — anything else
"pipeline_version": "2.1",
"job_id": "j_456"
}
}decision_typeCategory of the decision (e.g. cv_screening, interview_scoring). Used for filtering and reporting.
inputsThe data your model received. Stored as JSONB — log whatever is relevant to your pipeline.
outputWhat the model decided. Include score, decision label, and reasoning if available.
modelWhich model made the decision: name, version, provider. Useful when you change models over time.
actorWho triggered the decision: user ID, role, authority level. Critical for accountability.
human_overrideIf a human overrode the AI decision, capture the original vs. override with a reason.
Hash Chain (Tamper Evidence)
Every record includes a SHA-256 hash computed from the previous hash, customer ID, decision type, canonically-serialised inputs, output, and timestamp. This creates an append-only chain — if any record is altered or deleted, the chain breaks and verification fails.
// Hash computation:
hash = SHA256(
previous_hash +
customer_id +
decision_type +
canonicalJson(inputs) +
canonicalJson(output) +
created_at.toISOString()
)
JSON is serialised with sorted keys because PostgreSQL JSONB reorders keys alphabetically. Timestamps are normalised to UTC Z-suffix format before hashing.
Using the Dashboard
The compliance dashboard gives your team a read-only view of all logged decisions. Sign in with your email at /login.
Dashboard Overview
See total decisions, today's count, active decision types, a 30-day chart, and recent decisions at a glance.
Decisions List
Browse all decisions with filters for type, date range, and outcome. Click any row to see full detail including inputs, output, model, actor, and hash.
Decision Detail
View the complete record for any decision. Verify its hash chain integrity directly from the detail page.
Export
Export decisions as CSV with date range and type filters. Exports include all fields and the hash chain — ready for regulators or tribunal proceedings.
Settings
View and copy your API key, check usage against your plan limits, and manage team members. Admins can invite viewers.
Rate Limits
| Plan | Requests/min | Decisions/month |
|---|---|---|
| Starter | 100 | 5,000 |
| Professional | 500 | 50,000 |
| Enterprise | 2,000 | Unlimited |
Need help? Contact us