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-1is 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.