Getting Started

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 gettraceai

Log 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 gettraceai

Log 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 Reference

API Endpoints

All endpoints (except health) require an X-API-Key header with your API key. The base URL is your deployed API instance.

MethodPathAuthPurpose
POST/api/decisions/ingestAPI keyLog a decision (dashboard endpoint)
POST/v1/decisionsAPI keyLog a single decision
POST/v1/decisions/batchAPI keyLog up to 100 decisions
GET/v1/decisionsAPI keyList, filter, and paginate decisions
GET/v1/decisions/:idAPI keyGet full decision detail
GET/v1/decisions/exportAPI keyCSV export (max 10k records)
GET/v1/decisions/:id/verifyAPI keyVerify hash chain integrity
GET/v1/statsAPI keyUsage statistics
GET/v1/healthNoneHealth 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.csv

Verify 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"
Data Model

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_type

Category of the decision (e.g. cv_screening, interview_scoring). Used for filtering and reporting.

inputs

The data your model received. Stored as JSONB — log whatever is relevant to your pipeline.

output

What the model decided. Include score, decision label, and reasoning if available.

model

Which model made the decision: name, version, provider. Useful when you change models over time.

actor

Who triggered the decision: user ID, role, authority level. Critical for accountability.

human_override

If 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.

Dashboard

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

PlanRequests/minDecisions/month
Starter1005,000
Professional50050,000
Enterprise2,000Unlimited

Need help? Contact us