Skip to content

Emit audit events

Record an event from your application code. The smplkit SDK is fire-and-forget by default — calls return immediately, the SDK buffers in memory, flushes periodically, retries with backoff, and de-duplicates on idempotency key.

SDK

python
from smplkit import SmplClient

with SmplClient(environment="production", service="checkout") as client:
    client.audit.events.create(
        event_type="order.placed",
        resource_type="order",
        resource_id="o-9876",
        data={
            "snapshot": {
                "customer_id": "c-1234",
                "total_cents": 8990,
            },
            "ip": request.remote_addr,
        },
    )

The same surface is exposed in every smplkit SDK. See your SDK's README for per-language idioms.

The event is recorded in the environment the client is configured for — environment="production" above. The SDK sends that environment on every recording call (in the request body's environment field) so you never set it on the event itself; environment comes back as the resolved environment on read. A credential scoped to a single environment doesn't need the client environment at all — it's implied. See Environment scoping for the full resolution rules.

The event has a single data field for whatever JSON payload you want to attach. There is no separate snapshot field — to record a snapshot of the resource's state, place it inside data (smplkit's own services use data.snapshot for consistency, but the shape is unconstrained — pick whatever convention fits your data).

Severity and category

Both are optional. They give you two cheap, query-friendly axes for triaging the audit stream without inventing your own conventions inside data.

python
client.audit.events.record(
    event_type="user.login_failed",
    resource_type="user",
    resource_id="u-9876",
    severity="WARN",
    category="auth",
    data={"ip": "203.0.113.42"},
)

severity accepts one of TRACE, DEBUG, INFO, WARN, ERROR, FATAL. Anything else is rejected with 400 Bad Request. Omitting severity records the event at INFO; the field is always present on read.

category is free-form — anything string-shaped. Use it to bucket events (auth, billing, config-change, data-export) so the Events page filter dropdown stays meaningful for your team. Distinct categories are surfaced by GET /api/v1/categories for picker UIs. Omit when you have nothing to put there; the field round-trips as null.

Both are exposed as exact-match filters on the read endpoint:

GET /api/v1/events?filter[severity]=ERROR
GET /api/v1/events?filter[category]=auth&filter[severity]=ERROR

If you're forwarding events to a SIEM, the default per-vendor transform already maps severity and category to each destination's native shape (e.g. Datadog's status, Elastic's log.level, Splunk's per-event severity).

Slug rules

event_type and resource_type are slugs — they're surfaced in the Activity tab dropdowns, in URLs, and in your SIEM-side searches. The audit service rejects any value that isn't slug-shaped at write time so the dropdowns stay clean.

The rules:

  • 1 to 100 characters.
  • Lowercase letters, digits, dots, hyphens, and underscores only — [a-z0-9._-]+.
  • Cannot start or end with . or -. Underscores at the boundaries are fine.
  • The smpl. prefix is reserved for smplkit-emitted events. Customer credentials writing a resource_type that begins with smpl. get a 403.

Valid:

order
order.placed
api-key.rotated
user.login_failed
config_item.updated

Rejected (400 Bad Request):

Order              # uppercase
order placed       # whitespace
.order             # leads with a dot
order-             # ends with a hyphen
                   # over 100 chars

The error response identifies which attribute failed and why, so a confused caller can map back to the call site quickly.

Idempotency

Pass idempotency_key to safely retry without recording duplicates:

python
client.audit.events.create(
    event_type="order.shipped",
    resource_type="order",
    resource_id="o-9876",
    idempotency_key="order-9876-shipped",
)

A retry with the same key returns the original event. Useful when you have a natural idempotency key in your domain (an order id with a status, a webhook event id) — cleaner than relying on the auto-generated content hash.

REST

If you can't use an SDK, post directly. A single-environment API key implies the environment; a multi-environment or unrestricted credential must name the target environment in the request body's environment field (the SDK sets this for you):

bash
curl -X POST https://audit.smplkit.com/api/v1/events \
  -H "Authorization: Bearer $SMPLKIT_API_KEY" \
  -H "Content-Type: application/vnd.api+json" \
  -d '{
    "data": {
      "type": "event",
      "attributes": {
        "environment": "production",
        "event_type": "order.placed",
        "resource_type": "order",
        "resource_id": "o-9876",
        "severity": "INFO",
        "category": "checkout",
        "data": { "snapshot": { "customer_id": "c-1234", "total_cents": 8990 } }
      }
    }
  }'

Returns 201 the first time, 200 on a duplicate matched by idempotency key. See API Reference — Audit for the full schema, query parameters, and pagination.