Skip to content

Event logs

HappyView logs system events: lexicon changes, record operations, script errors, user actions, and more. See the Event logs guide for details on event types and retention.

const TOKEN = "hv_..."; // your API key
const headers = { Authorization: `Bearer ${TOKEN}` };
GET /admin/events
interface EventLog {
id: string;
event_type: string;
severity: string;
actor_did: string;
subject: string;
detail: Record<string, unknown>;
created_at: string;
}
interface EventLogResponse {
events: EventLog[];
cursor?: string;
}
const response = await fetch(
"http://127.0.0.1:3000/admin/events?severity=error&limit=10",
{ headers },
);
const data: EventLogResponse = await response.json();
ParamTypeRequiredDescription
event_typestringnoFilter by exact event type (e.g. script.error)
categorystringnoFilter by category prefix (e.g. lexicon matches all lexicon events)
severitystringnoFilter by severity: info, warn, or error
subjectstringnoFilter by subject (lexicon ID, record URI, admin DID, etc.)
afterstringnoOnly events at or after this RFC 3339 time
beforestringnoOnly events before this RFC 3339 time
cursorstringnoPagination cursor: the cursor from a previous response
limitnumbernoResults per page (default 50, max 100)

Response: 200 OK

{
"events": [
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"event_type": "script.error",
"severity": "error",
"actor_did": "did:plc:abc123",
"subject": "com.example.feed.like",
"detail": {
"error": "attempt to index nil value",
"script_source": "function handle(input, ctx) ... end",
"input": { "status": "hello" },
"caller_did": "did:plc:abc123",
"method": "com.example.feed.like"
},
"created_at": "2026-03-01T12:00:00Z"
}
],
"cursor": "2026-03-01T11:59:00Z"
}

Events are returned in reverse chronological order (newest first). Pass the cursor value from the response to fetch the next page; a response with no more pages has no cursor key. An empty parameter counts as unset, and an unreadable after or before is a 400.

Permission: events:read

GET /admin/events/count

Counts the events that match the same filters as List event logs: event_type, category, severity, subject, after and before. cursor and limit are ignored.

Permission: events:read

Response: 200 OK

{ "count": 1284 }
POST /admin/events/purge

Deletes the events that match a filter, in a background job. The body takes the same filters as the list, all optional:

{ "category": "record", "before": "2026-09-01T00:00:00Z" }

Permission: events:purge

Response: 202 Accepted

{ "job_id": "550e8400-e29b-41d4-a716-446655440000" }

The job is a happyview.purge-event-logs job; watch it there. The purge itself is logged as an event_logs.purged event. An unreadable after or before is a 400.