---
title: Audit chain
description: An append-only, hash-chained record of every tool call and money movement. Exactly-once, tamper-evident, and exportable for compliance.
---

import { Callout } from "fumadocs-ui/components/callout";

# Audit chain

<Callout title="Why it exists" type="info">
Agents move money. The audit chain is the **CFO-grade record** of everything they did: every tool call, every payment, every KYC check, written append-only and hash-chained so it can be proven untampered after the fact.
</Callout>

Every governed action in CodeSpar appends an event to a per-tenant audit chain:

- **Append-only.** Events are never updated or deleted. Corrections are new events that reference the original.
- **Hash-chained.** Each event carries an `entry_hash` over its contents plus the `prev_hash` of the event before it, so any retroactive edit breaks the chain and is detectable.
- **Exactly-once.** An action is attested once and only once, whether it was dispatched through `session.execute()`, the chat-loop `session.send()`, or a raw `proxy_execute`. Client-SDK tool calls are attested with `attested_by: client_sdk`; server-side dispatch with the server attestor.
- **Self-auditing exports.** Reading the chain out through the export path is itself an audited event.

## What gets recorded

Meta-tool calls, raw provider calls, money movement (charge / pay / payout settlement), KYC dispositions, mandate spends, and policy decisions, each with its `tool_call_id`, resolved rail, idempotency key, and outcome. Completed tool calls land as `tool_call.succeeded` or `tool_call.failed` events with the same names and shape on every dispatch path.

## Reading the chain

```
GET /v1/audit/events
```

A browse-only, paginated listing of your org's chain events. Each event carries `sequence_number`, `event_type`, `happened_at`, `payload`, `prev_hash`, and `entry_hash`. Filters:

| Query param | Behavior |
|---|---|
| `event_type` | Exact match, or prefix match when it ends with a dot: `tool_call.` matches both `tool_call.succeeded` and `tool_call.failed`. |
| `from` / `to` | ISO 8601 window. Defaults to the last 7 days. |
| `limit` | 1 to 200, default 50. |
| `before_sequence` | Cursor for older-than pagination. Pass the `next_before_sequence` from the previous page to walk back. |

Browsing is read-only and does not append an export event; it exists so you (and the **/dashboard/audit** page) can inspect recent activity without dumping the full chain.

## Anchors

A background job periodically signs the chain head, the tuple of org, head sequence, and head hash, with HMAC-SHA256 and delivers that anchor record to a configured target outside the database. Anchors are what make tampering provable rather than merely detectable: the chain proves internal consistency, the anchor pins it to a point in time held elsewhere.

| Endpoint | Purpose |
|---|---|
| `GET /v1/audit/anchors` | List your org's anchors, newest first, with delivery status. |
| `POST /v1/audit/anchors/verify` | Post an anchor record you hold (for example, fetched from your webhook target's storage). The backend recomputes the HMAC signature and cross-checks the (org, sequence, hash) tuple against the row persisted at emit time. |

The verify response carries a `verdict`: `verified`, `signature_ok_but_no_local_record`, `local_record_diverges`, or `signature_invalid`. A valid signature with a diverging or missing local record is provable tampering on one side or the other.

## Export

An org-level export endpoint streams a slice of the chain with a signed manifest for compliance and archival; the export itself appends an `audit_export` event to the chain.

Audit events also drive the incident lifecycle: anomalous or policy-flagged events can be opened, triaged, and resolved as incidents from **/dashboard/audit**.

## See also

- [Guardrails](/docs/concepts/guardrails): the policy decisions that the chain records
- [Wallets](/docs/concepts/wallets): programmable spend, every movement attested
- [Test mode](/docs/concepts/test-mode): audit events fire on mocked calls too
