Admin API
The Admin API manages collection configuration, webhook rules, and the dead-letter queue. It requires a token with the admin scope.
Authorization: Bearer <api-key> # must have admin scope
Collection configuration
Get collection config
GET /api/v1/collections/{collection}/config
Returns the collection’s current configuration.
Response:
{
"collection": "crm.deals",
"reliability_mode": "durable",
"auto_create": true,
"snapshot_every": 100,
"first_event_op": "create",
"plugins": ["hash_chain"],
"hash_chain": {
"enabled": true
}
}
Update collection config
PUT /api/v1/collections/{collection}/config
Updates the collection configuration. Fields not specified are left unchanged.
{
"reliability_mode": "strict",
"snapshot_every": 50,
"plugins": ["hash_chain"]
}
| Field | Type | Description |
|---|---|---|
reliability_mode |
string | Default mode for writes: strict, durable, fast |
snapshot_every |
integer | Snapshot interval in events (default 100) |
first_event_op |
string | Op assigned to the first event: create (default) or update |
plugins |
string[] | List of plugins to enable (e.g., ["hash_chain"]) |
Rules
Rules define conditions under which webhooks are fired. Each rule has a filter expression that is evaluated against every incoming event.
List rules
GET /api/v1/collections/{collection}/rules
Create a rule
POST /api/v1/collections/{collection}/rules
{
"name": "notify-on-stage-change",
"filter": "changes[?path=='stage']",
"webhook": {
"url": "https://example.com/hooks/letopis",
"secret": "my-signing-secret",
"timeout_ms": 5000,
"max_retries": 5
},
"enabled": true
}
| Field | Type | Description |
|---|---|---|
name |
string | Human-readable rule name |
filter |
string | JMESPath expression; rule fires when the expression is truthy |
webhook.url |
string | Target URL |
webhook.secret |
string | Name of a signing secret from webhooks.secrets config |
webhook.timeout_ms |
integer | Per-attempt timeout in milliseconds (default 5000) |
webhook.max_retries |
integer | Maximum delivery attempts (default 5) |
enabled |
boolean | Whether the rule is active |
Update a rule
PATCH /api/v1/collections/{collection}/rules/{ruleId}
Delete a rule
DELETE /api/v1/collections/{collection}/rules/{ruleId}
Webhooks
Webhooks are fired by rules. The payload is a JSON object containing the event and the collection/entity context.
Webhook payload
{
"event_type": "letopis.event.stored",
"collection": "crm.deals",
"entity_id": "deal-1",
"version": 4,
"op": "update",
"author_id": "user-42",
"source": "crm-backend",
"ts_stored": "2026-06-02T09:00:01Z",
"changes": [
{"path": "stage", "op": "change", "old": "prospect", "new": "qualified"}
]
}
Signature
Every webhook delivery includes an X-Letopis-Signature header:
X-Letopis-Signature: sha256=<hmac_hex>
The HMAC is computed over the raw request body using the secret named in the rule’s webhook.secret. Validate it on your receiving side to verify authenticity.
Dead-letter queue
Failed webhook deliveries are moved to the DLQ after all retries are exhausted.
List DLQ entries
GET /api/v1/dlq
Query parameters: collection (filter by collection), rule_id, limit (default 100), cursor.
Replay a DLQ entry
POST /api/v1/dlq/{entryId}/replay
Re-attempts delivery of a failed webhook. The entry is removed from the DLQ and re-enqueued as if it were a new delivery.
Delete a DLQ entry
DELETE /api/v1/dlq/{entryId}
Permanently removes the DLQ entry without replaying.
Purge an entity (GDPR)
DELETE /api/v1/collections/{collection}/entities/{entityId}
Physically removes all events, snapshots, and current-state documents for the entity. A tombstone is written to ev__system for audit purposes.
Caution: This is irreversible. If hash-chain integrity was enabled, the chain is destroyed for this entity; other entities are unaffected.
System info
GET /version
Returns build information:
{
"version": "v1.2.3",
"commit": "abc1234",
"date": "2026-06-01T00:00:00Z"
}