Overview
Unlike the/runs endpoints which are hierarchical (Run → Actions), the ledger provides a flat, chronological stream of all actions with advanced filtering and search capabilities.
Key Use Cases
- Compliance Audits: “Show me all high-risk actions in Q4 2024”
- Debugging: “Find all failed
database_queryactions” - Cost Analysis: “What are my most expensive actions?”
- Security: “Show all actions by
prod-agent-3that were blocked” - Organizational Memory: “What did our agents do last week?”
Endpoints
GET /api/v1/ledger
Query the activity ledger with filtering, sorting, and pagination.Query Parameters
Response
Example: Find Failed Actions
Example: Search Actions
Example: Date Range Query
GET /api/v1/ledger/stats
Get aggregate statistics for the activity ledger.Query Parameters
Response
Example: Monthly Stats
GET /api/v1/ledger/export
Export ledger data for compliance audits and offline analysis.Query Parameters
Response
File download in requested format.Example: Export as JSONL
Example: Export Failed Actions as CSV
GET /api/v1/ledger/verify
Re-derive an organization’s row hash chain from stored data and report whether it’s intact.Query Parameters
Non-superusers may only verify their own active organization’s chain; requesting a different
organization_id returns 403.
Response
valid is true only when every check passes. first_bad_seq is the earliest seq whose stored row_hash no longer matches what’s recomputed from its current fields and prev_hash — evidence that row (or an earlier one) was altered or deleted after it was chained. signatures_checked counts the signed rows whose Ed25519 signature was verified against the platform public key (unsigned pre-signing rows are skipped), and first_bad_signature_seq is the earliest signed row whose signature does not verify over its stored row_hash. head_seq is where the organization’s signed ledger head says the chain ends, and head_matches is false when the chain’s last row isn’t that head (rows were deleted from the end), the head is missing, or the head’s signature doesn’t verify. Both are null for a ranged check (to_seq given), which stops before the tail by design and does not consult the head. See Integrity vs. authenticity.
Example
Hash Chain & Signing
Every ledger row is chained to the previous row written for its organization, and optionally Ed25519-signed:seq— gap-free, per-organization sequence number. Concurrent ingest batches to the same organization can’t produce duplicate or gapped values.prev_hash— the previous row’srow_hash(nullfor the first row in the chain).row_hash—sha256of the row’s immutable fields (everything set at ingest time, excludingcompliance_metadata) plusprev_hash.signature/key_id— Ed25519 signature ofrow_hashand the signing key used. Rows written before signing was enabled stay permanently unsigned (“pre-signing”,null) — enabling signing does not retroactively sign history. See Compliance.compliance_metadata.log_hash/tamper_seal— mirrorrow_hash/signature, for tooling that only readscompliance_metadata.
prev_hash stops matching, and GET /ledger/verify reports the first broken seq. Deleting the newest rows leaves the remaining chain intact, so the platform also keeps a signed ledger head, described below.
Ledger head
The platform records each organization’s chain head (the lastseq and its row_hash) separately from the chain and signs it. A full verification (no to_seq) compares the chain’s last row with the head and reports the result as head_seq and head_matches. The chain is reported invalid when:
- rows were removed from the end, so the last row no longer matches the head;
- the chain has rows but no head;
- the head is unsigned or its signature does not verify.
Integrity vs. authenticity
Verification makes two independent guarantees, reported separately:- Chain integrity (
first_bad_seq) — no row was altered or removed without breaking the links. This needs no key: anyone can recompute the hashes. - Authenticity (
first_bad_signature_seq) — the platform key signed each storedrow_hash. Because the hash chain alone is recomputable, someone with database access could edit a row and re-hash it (and every later row) so the chain still links up. They cannot re-sign those hashes without the private key, so the signature check catches the edit even when the chain is intact.
valid is true only when both pass. Pre-signing rows (signature: null) are skipped by the signature check, not failed — they verify on the chain alone, and signatures_checked counts only signed rows. Only null marks a pre-signing row: any non-null signature, including an empty string, is verified and fails if it does not match. Signed rows cannot be authenticated without the public key: if the platform has no key to verify against, every signed row is reported as bad rather than silently passed.
Response Schema
LedgerEntry
Actor / Counterparty
Every ledger row is self-describing:actor and counterparty record who did what without requiring a join through /runs. This is the same identity shape used across Agent Sentinel’s governance tables (agent id, principal, harness, key id, mandate reference), so it stays compatible with A2A agent cards and AP2/TAP mandate references.
actor is derived server-side from the verified API key/JWT plus the SDK’s X-Sentinel-* identity headers — it cannot be spoofed by the request body. counterparty is optional and comes from a counterparty field on the SDK’s ingest entry, for actions performed against or on behalf of another party (e.g. a buyer agent in an AP2 transaction).
ComplianceMetadata (Enterprise Tier)
Common Patterns
1. Debugging Failed Actions
2. Cost Analysis by Agent
3. Compliance Audit Export
4. Real-Time Monitoring
Authentication
All ledger endpoints require authentication via:-
JWT Bearer Token
-
API Key (recommended for programmatic access)
Access Control
- Users can only see actions from their own runs
- Superusers can see all actions across all users
- Organization admins can see actions from their organization’s runs
Rate Limits
- Query Endpoints: 1000 requests/hour
- Export Endpoint: 100 requests/hour
- Stats Endpoint: 600 requests/hour
Differences from /runs Endpoints
When to use
/runs:
- Inspecting a specific run’s execution flow
- Debugging a single agent workflow
- Viewing run-level metadata
/ledger:
- Compliance audits across all activity
- Finding patterns across multiple runs
- Cost analysis by action type
- Security monitoring
Best Practices
1. Use Pagination for Large Results
2. Use Search for Flexible Queries
3. Filter by Date Range for Performance
4. Use Stats Endpoint for Aggregates
Troubleshooting
Empty Results
Problem: Query returns 0 results Solutions:- Check filters - they may be too restrictive
- Verify date range includes expected data
- Ensure authentication is correct (not seeing another user’s data)
- Check that agents have actually executed actions
Slow Queries
Problem: Queries take >5 seconds Solutions:- Reduce page size (100 instead of 1000)
- Add date range filters to limit data scanned
- Avoid search queries on large datasets
- Use stats endpoint for aggregates instead of fetching all data
Export Limits
Problem: “Export limit exceeded” error Solutions:- Reduce date range or add more filters
- Export in batches using pagination
- Contact support for bulk export access
Related Documentation
- Runs API - Hierarchical run/action queries
- Ingest API - How SDK sends action data
- Authentication - API keys and JWT tokens
- Compliance - Enterprise compliance features