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
The emit call is audit.events.record(...) in every smplkit SDK — the first three arguments (event_type, resource_type, resource_id) are required; everything else is optional. See the per-language SDK guides for install and client setup.
from smplkit import SmplClient
with SmplClient(environment="production", service="checkout") as client:
client.audit.events.record(
event_type="order.placed",
resource_type="order",
resource_id="o-9876",
data={
"snapshot": {"customer_id": "c-1234", "total_cents": 8990},
},
)record(...) is fire-and-forget: it enqueues the event and returns immediately, and a background worker delivers it with retry. When the event must be durable before the process exits — CLI tools, tests, a request that's about to terminate — force a synchronous flush (flush=True / flush: true on the call, or client.audit.events.flush(...) afterward).
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 query-friendly axes for triaging the audit stream without inventing your own conventions inside data. The SDK's record(...) sets both — pass category and severity as optional arguments.
client.audit.events.record(
event_type="user.login_failed",
resource_type="user",
resource_id="u-9876",
category="auth",
severity="WARN",
data={"ip": "203.0.113.42"},
)severity is one of TRACE, DEBUG, INFO, WARN, ERROR, FATAL (anything else is rejected with 400 Bad Request). Omit it and the event is recorded 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]=ERRORIf 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 aresource_typethat begins withsmpl.get a 403.
Valid:
order
order.placed
api-key.rotated
user.login_failed
config_item.updatedRejected (400 Bad Request):
Order # uppercase
order placed # whitespace
.order # leads with a dot
order- # ends with a hyphen
# over 100 charsThe 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:
client.audit.events.record(
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):
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.
Related
- SDK guides — install + client setup for each language
- Smpl Audit overview
- SIEM streaming
- API Reference — Audit

