Skip to main content

Technical reference

Receipt format specification

Decision Keep records use an open, vendor-neutral format so any auditor, regulator or counterparty can verify a receipt without our software, our account, or our trust. This page is the specification.

What is the dkr-1 receipt format, and how is a receipt structured?

Format version

dkr-1

The format identifier is part of the signed content hash, so a receipt is provably bound to the format that produced it. It is published on every record and at /docs/spec.

At a glance

  • Content hash: SHA-256 over the canonical decision.
  • Chain hash: SHA-256 binding each entry to the previous one.
  • Signature: Ed25519 over the chain hash, with your key.
  • Trusted time: optional RFC 3161 timestamp.
  • Verification: offline, trustless, no account.
  • Format: dkr-1, frozen and versioned.

Agentic workflows

Recording agentic decisions

How do I record decisions from AI agents and agentic workflows?

Decision Keep is framework-agnostic. Any agentic system - LangChain, CrewAI, AutoGen, custom - can record a decision by sending the standard fields plus an optional agent_provenance block. The block captures which agent was involved, its framework and version, the parent chain, and a step-by-step reasoning/tool-call/policy-check log. When present, it is included in the signed content hash, so the reasoning chain is tamper-evident.

Recommended agent_provenance schema

{
  "agent_provenance": {
    "agent_id": "fraud-agent-42",
    "agent_framework": "langchain",
    "agent_version": "0.2.0",
    "parent_agent_id": "triage-agent-7",
    "parent_receipt_id": "RCP-20260810-A1B2C3",
    "steps": [
      {
        "type": "reasoning",
        "description": "Assessed transaction risk against policy POL-001"
      },
      {
        "type": "tool_call",
        "tool": "credit_bureau",
        "tool_input_summary": "Score request for applicant #12345",
        "tool_output_summary": "Score 720, no adverse flags"
      },
      {
        "type": "policy_check",
        "policy_id": "POL-001",
        "policy_result": "PASS"
      },
      {
        "type": "human_oversight",
        "description": "Senior analyst reviewed and confirmed"
      }
    ]
  }
}

All fields are optional except agent_id. The steps array is ordered chronologically. Each step's type must be one of the five standard values. Summaries should be short - the raw tool payloads belong in the payload field, which is already hashed and signed.

SDK examples

The TypeScript, Python and Go SDKs all accept agent_provenance as an optional field on the decision input. Below is the same decision recorded in each language.

TypeScript

import { DecisionKeepClient } from "@decisionkeep/client";

const client = new DecisionKeepClient({
  baseUrl: "https://decisionkeep.com",
  apiKey: "YOUR_KEY",
});

client.record({
  system: "fraud-review",
  agent: "fraud-agent-v2",
  version: "2.1.0",
  decision_outcome: "APPROVED",
  agent_provenance: {
    agent_id: "fraud-agent-42",
    agent_framework: "langchain",
    parent_agent_id: "triage-agent-7",
    steps: [
      { type: "reasoning", description: "Assessed risk" },
      { type: "tool_call", tool: "credit_bureau", tool_output_summary: "Score 720" },
      { type: "policy_check", policy_id: "POL-001", policy_result: "PASS" },
    ],
  },
});

Python

from decisionkeep_client import DecisionKeepClient

client = DecisionKeepClient(
  base_url="https://decisionkeep.com",
  api_key="YOUR_KEY",
)

client.record({
  "system": "fraud-review",
  "agent": "fraud-agent-v2",
  "version": "2.1.0",
  "decision_outcome": "APPROVED",
  "agent_provenance": {
    "agent_id": "fraud-agent-42",
    "agent_framework": "langchain",
    "parent_agent_id": "triage-agent-7",
    "steps": [
      {"type": "reasoning", "description": "Assessed risk"},
      {"type": "tool_call", "tool": "credit_bureau", "tool_output_summary": "Score 720"},
      {"type": "policy_check", "policy_id": "POL-001", "policy_result": "PASS"},
    ],
  },
})

Go

client := decisionkeep.NewClient(decisionkeep.ClientOptions{
  BaseURL: "https://decisionkeep.com",
  APIKey:  "YOUR_KEY",
})

client.Record(decisionkeep.DecisionInput{
  System:          "fraud-review",
  Agent:           "fraud-agent-v2",
  Version:         "2.1.0",
  DecisionOutcome: strPtr("APPROVED"),
  AgentProvenance: &decisionkeep.AgentProvenance{
    AgentID:        "fraud-agent-42",
    AgentFramework: strPtr("langchain"),
    ParentAgentID:  strPtr("triage-agent-7"),
    Steps: []decisionkeep.AgentProvenanceStep{
      {Type: "reasoning", Description: strPtr("Assessed risk")},
      {Type: "tool_call", Tool: strPtr("credit_bureau"), ToolOutputSummary: strPtr("Score 720")},
      {Type: "policy_check", PolicyID: strPtr("POL-001"), PolicyResult: strPtr("PASS")},
    },
  },
})

Construction

How a receipt is constructed

How is a receipt constructed, and what does each cryptographic part prove?

1. Content hash - SHA-256

A deterministic fingerprint of the canonical decision. Keys are sorted, arrays are order-preserving, and fields with no value are omitted (never coerced to null), so the hash is stable and reproducible by any implementation.

  • receipt_id- Public handle used to verify, e.g. RCP-20260710-1A2B3C.
  • system / agent / version- Origin platform, model/agent, and version.
  • received_at- RFC 3339 timestamp the decision was received.
  • payload- The decision content. Send references, not raw PII; only its hash is published.
  • parents- Upstream receipt ids - chain of custody for derived decisions.
  • AI-governance capture- reference_db_state, actor_id/type, confidence, tokens, risk, routing, human_verifier_id.
  • format- Receipt format version (dkr-1). Bound into the content hash.

2. Chain hash - SHA-256

Binds each entry to the one before it: SHA-256(prev_hash | content_hash | receipt_id | org_id). The first entry anchors to the constant decisionkeep-genesis-v1. Altering any prior line breaks the link for every later entry.

3. Signature - Ed25519

The organisation signs the chain hash with its own Ed25519 key. Verification needs only the published public key at /.well-known/record-public-key?org=<id>.

4. Optional trusted time - RFC 3161

An independent timestamp authority anchors exactly when the decision was signed, outside your control and outside ours.

Stability

Stability & migration commitment

How stable is the receipt format, and what happens if it changes?

A receipt is evidence that may be challenged years later, so the format is stabilised:

  • The format is versioned. dkr-1 is the current, frozen specification.
  • Any breaking change ships as a new version (dkr-2, …) with a documented, backward-compatible migration.
  • Receipts recorded under an older version remain verifiable forever by the versioned verifier - the API, the public /verify tool, and the offline scripts/verify-ledger.mjs.
  • The verifier and this specification are open. No proprietary format, no vendor lock-in, no account required to check a receipt.

Verification

Verify anything, anywhere

Auditors verify a receipt at /verify with no account, or run the offline verifier against the exported ledger and published key. Exit code is non-zero on any failure - hand it to counsel.

See the Forensic Witness on your stack

Book a personalised demo and we'll map Decision Keep to your automated-decision obligations and show the evidence trail end to end.