HTTP Admin API
Complete reference for the Chronicle admin API — 21 endpoints.
The admin API is served by handler.New(deps, router). All routes are mounted under /v1. Requests and responses use JSON. All requests require an AppID in the context; missing AppID returns 401 Unauthorized.
Setup
import "github.com/xraph/chronicle/handler"
api := handler.New(handler.Dependencies{
AuditStore: myStore,
VerifyStore: myStore,
ErasureStore: myStore,
RetentionStore: myStore,
ReportStore: myStore,
Compliance: complianceEngine,
Retention: retentionEnforcer,
Logger: slog.Default(),
}, mux)
api.RegisterRoutes(mux)When using the Forge extension, routes are registered automatically unless WithDisableRoutes(true) is set.
Error format
{"error": "chronicle: event not found"}| Code | Condition |
|---|---|
400 | Invalid request body or query parameters |
401 | Missing AppID |
404 | Entity not found |
500 | Internal error |
Events
List events
GET /v1/eventsQuery parameters:
| Parameter | Type | Description |
|---|---|---|
category | string | Filter by event category |
action | string | Filter by action verb |
severity | string | info, warning, or critical |
outcome | string | success, failure, or denied |
from | RFC3339 | Start time |
to | RFC3339 | End time |
limit | int | Page size (default 20) |
offset | int | Page offset |
order | string | asc or desc (by timestamp) |
Response 200 OK: audit.QueryResult
{
"events": [
{
"id": "audit_01j9vk...",
"timestamp": "2025-01-15T10:00:00Z",
"sequence": 42,
"hash": "abc123...",
"prev_hash": "def456...",
"stream_id": "stream_01j9vk...",
"app_id": "myapp",
"tenant_id": "tenant-1",
"user_id": "user-42",
"action": "login",
"resource": "session",
"category": "auth",
"resource_id": "sess-001",
"outcome": "success",
"severity": "info"
}
],
"total": 1
}Get event
GET /v1/events/:idResponse 200 OK: Single audit.Event.
Response 404 Not Found
Events by user
GET /v1/events/user/:userIdQuery parameters: from, to (RFC3339), limit, offset.
Response 200 OK: audit.QueryResult
Aggregate events
POST /v1/events/aggregateRequest body: audit.AggregateQuery
{
"group_by": "category",
"from": "2025-01-01T00:00:00Z",
"to": "2025-01-31T23:59:59Z"
}Response 200 OK: audit.AggregateResult
{
"buckets": [
{"name": "auth", "count": 142},
{"name": "billing", "count": 38}
]
}Verification
Verify hash chain
POST /v1/verifyRequest body:
{
"stream_id": "stream_01j9vk...",
"from_seq": 0,
"to_seq": 0
}from_seq and to_seq default to 0 (full chain). stream_id is optional if app_id and tenant_id are in context.
Response 200 OK: verify.Report
{
"valid": true,
"verified": 42,
"gaps": [],
"tampered": [],
"first_event": 1,
"last_event": 42
}Erasure
Request erasure
POST /v1/erasuresRequest body:
{
"subject_id": "user-42",
"reason": "GDPR Article 17",
"requested_by": "dpo@company.com"
}Response 201 Created: erasure.Result
{
"id": "erasure_01j9vk...",
"subject_id": "user-42",
"events_affected": 5,
"key_destroyed": true
}List erasures
GET /v1/erasuresQuery parameters: limit, offset.
Response 200 OK: []*erasure.Erasure
Get erasure
GET /v1/erasures/:idResponse 200 OK: erasure.Erasure
Response 404 Not Found
Retention
List policies
GET /v1/retentionResponse 200 OK: []*retention.Policy
Save policy
POST /v1/retentionRequest body:
{
"category": "auth",
"duration": "2160h",
"archive": true
}Response 201 Created: retention.Policy
Delete policy
DELETE /v1/retention/:idResponse 204 No Content
Enforce retention
Immediately runs all retention policies once.
POST /v1/retention/enforceResponse 200 OK: retention.EnforceResult
{
"archived": 150,
"purged": 150,
"retained": 8420
}List archives
GET /v1/retention/archivesResponse 200 OK: []*retention.Archive
Reports
List reports
GET /v1/reportsQuery parameters: limit, offset.
Response 200 OK: []*compliance.Report
Generate SOC2 report
POST /v1/reports/soc2Request body: compliance.SOC2Input
{
"period": {"from": "2025-01-01T00:00:00Z", "to": "2025-03-31T23:59:59Z"},
"app_id": "myapp",
"tenant_id": "tenant-1",
"generated_by": "admin@company.com"
}Response 201 Created: compliance.Report
Generate HIPAA report
POST /v1/reports/hipaaRequest body: compliance.HIPAAInput (same shape as SOC2Input).
Response 201 Created: compliance.Report
Generate EU AI Act report
POST /v1/reports/euaiactRequest body: compliance.EUAIActInput.
Response 201 Created: compliance.Report
Generate custom report
POST /v1/reports/customRequest body: compliance.CustomInput
{
"period": {"from": "2025-01-01T00:00:00Z", "to": "2025-01-31T23:59:59Z"},
"app_id": "myapp",
"title": "Q1 Security Review",
"categories": ["auth", "billing"],
"generated_by": "admin@company.com"
}Response 201 Created: compliance.Report
Get report
GET /v1/reports/:idResponse 200 OK: compliance.Report
Response 404 Not Found
Export report
GET /v1/reports/:id/export/:format:format is one of: json, csv, markdown, html.
Response 200 OK: Report content in the requested format (Content-Type varies).
Stats
Chronicle stats
GET /v1/statsResponse 200 OK:
{
"total_events": 8420,
"events_by_severity": {
"info": 7800,
"warning": 580,
"critical": 40
},
"events_by_outcome": {
"success": 8100,
"failure": 250,
"denied": 70
}
}