Skip to content

Smpl Audit

Smpl Audit is an append-only, permanent record of "things that happen" — events your application emits to a small, RESTful API for compliance, security review, customer-support investigations, or any other reason you need a tamper-evident log of who did what and when.

You write events with a single API call. You query them later by actor, resource, event type, time range, or any combination.

What an event looks like

Each event carries:

FieldDescription
event_typeWhat happened, in {resource_type}.{verb} form. Example: order.placed, user.login_failed, payment.refunded.
resource_typeThe kind of thing the event acts on (order, user, payment).
resource_idIdentifier of the affected resource. Any text — your own domain identifiers, not constrained to UUIDs.
descriptionOptional free-text description of the event. Included alongside resource_id in the filter[search] substring target.
actor_typeFree-form string identifying the kind of actor — for example USER, API_KEY, SYSTEM, or any custom value (EXTERNAL_SERVICE, WEBHOOK, ...). Optional; the audit service does not backfill it.
actor_idFree-form identifier of the actor. Any string scheme works — UUIDs, email addresses, opaque tokens — not constrained to UUIDs. Optional.
actor_labelDisplay string captured at write time (e.g. alice@example.com). Doesn't change if the actor is later renamed or removed. Optional.
occurred_atWhen the event happened in your application. Defaults to event-creation time if not supplied.
idempotency_keyAuto-generated from event content; supply your own to deduplicate retries on a stable key (e.g. an order id with a status).
dataFree-form JSON. The single payload field on every event — record snapshots, request IDs, IP addresses, deploy SHAs, and any other contextual detail you want preserved with the event. See Forensic detail below.

A representative event:

json
{
  "event_type": "order.placed",
  "resource_type": "order",
  "resource_id": "o-9876",
  "description": "Alice placed order o-9876 ($89.90, 2 items).",
  "actor_type": "USER",
  "actor_id": "8a1c5e3a-2b9f-4d12-9e76-1d3c8b7a4e5f",
  "actor_label": "alice@example.com",
  "occurred_at": "2026-05-08T14:22:18Z",
  "data": {
    "snapshot": {
      "id": "o-9876",
      "customer_id": "c-1234",
      "items": [
        { "sku": "shirt-md-blue", "qty": 1, "price_cents": 4995 },
        { "sku": "hat-onesize",   "qty": 1, "price_cents": 3995 }
      ],
      "total_cents": 8990
    },
    "ip": "203.0.113.42",
    "request_id": "req-d4f8a1c0"
  }
}

Events are immutable. Once written, an event row stays — there is no PUT, PATCH, or DELETE on the events endpoint. Retention sweeps eventually drop events that exceed your tier's retention window, but no one can rewrite history within that window.

Querying events

The query API supports filtering on every event field. Common patterns:

  • By actor. Every event a specific user took, or every event type a particular API key performed.
  • By resource. The full history of one record — every change to one order, one user, one configuration item.
  • By resource search. A case-insensitive substring match on resource_id or description via filter[search] — useful for finding events without knowing the exact identifier.
  • By event type. Every login failure across the account, or every refund.
  • By time range. This month's events, or yesterday's, bounded as tightly as you need.

GET /api/v1/events accepts calls with no parameters — that returns the account's most recent events, paginated. Two filter-combination rules to be aware of:

  • filter[resource_id] must be accompanied by filter[resource_type] (the underlying index is keyed on the pair).
  • filter[search] must be accompanied by either filter[occurred_at] or filter[resource_type] + filter[resource_id] (substring matching has no index, so an unbounded substring scan is rejected).

filter[occurred_at] is otherwise unbounded — any span is allowed; pagination is what caps the response.

Pagination is cursor-based; page[size] defaults to 1000 and must not exceed 1000. See API Reference — Audit for the exact filter syntax.

The smplkit console's Events page is a UI front-end on the same query API. Its Resource type and Event type filter dropdowns are populated from GET /api/v1/resource_types and GET /api/v1/event_types — small, fast endpoints that return the distinct slugs your account has actually emitted, sorted alphabetically and cursor-paginated. The dropdowns also support a cascading filter: passing ?filter[resource_type]=order to /api/v1/event_types returns only the event types you've recorded under order.

Wiping an account

Audit data is cleared as part of the platform-level account wipe — POST /api/v1/accounts/current/actions/wipe on the app service. That action wipes every per-account resource across all four product services in a single transaction, including the entire audit trail (events, quota counters, forwarders, deliveries, and the side tables that back the Events page filter dropdowns). There is no audit-only wipe endpoint; the operation is intentionally only initiated through the platform's confirmation flow.

The wipe is irreversible. The console renders a confirmation dialog before submitting the action.

Forensic detail

The data field is unconstrained JSON — anything that helps your future self reconstruct what happened. To record the post-save state of a domain object, smplkit's own services use data.snapshot, but the convention is yours to set; pick the shape that fits your data. Snapshots are full state, not diffs — diffs are computed at read time when you need them. Common uses: capture the post-save state of a domain object so you can answer "what did this look like at the time?" later, attach the input that triggered an event for replay, or record a multi-resource view that doesn't fit into the primary resource_type/resource_id pair.

Retention and quota

Each plan publishes a per-month event quota and a retention window. Both vary by plan; once an event passes the retention window it's removed automatically.

Your current plan, quota, and usage are visible under Account → Subscriptions in the smplkit console.

SIEM streaming

Events are also forwardable to your SIEM (Splunk, Datadog, Sumo Logic) or any HTTP endpoint as they're recorded. See SIEM streaming.