Reading the tenant audit log
An admin reviews tenant security events; filterable + cursor-paginated.
- GET /v1/audit — events for the tenant (filter by event / userId / from / to)
/v1/auditadminRead tenant audit logScoped to the caller's tenant. Includes operator ACT-AS actions performed inside the tenant, attributed to the operator via actOperatorId / actReason — the cross-profile hop is scenario 37. The Enhancement 4 event codes listed in scenario 38 are visible here too: device_trust_failed and login_challenge_failed are the ones a tenant admin will care about when a member reports trouble signing in. Those events are written BEFORE any tenant is resolved — a device challenge is issued while the user is still proving who they are — so their tenant_id is NULL, and a read filtering on tenant_id alone would hide exactly the signal the admin needs from the only person positioned to act on it. The read therefore ALSO returns identity-plane events (NULL tenant_id) for users who are members of this tenant. Nothing scoped to another tenant can appear: any tenant-scoped event carries a non-NULL tenant_id and is excluded unless it is this one. What an admin additionally sees is their own member's authentication events, which are identity-plane facts by design — device trust deliberately spans every tenant a member belongs to (scenario 48).
Field guide — what each value means & where it comes from6 fields
No request body — all inputs are optional query filters. Admin-only and tenant-scoped; still requires the tester's Authorization (access token) and gateway context, which the tester and gateway supply.
eventquerystringoptionalyou chooseuserIdqueryUUIDoptionalfrom a responsefromqueryISO-8601optionalyou choosetoqueryISO-8601optionalyou chooselimitqueryintegeroptionalyou choosecursorquerystringoptionalfrom a responseGET https://api.kerja.team/v1/audit?event=login_succeeded&limit=20Response guide — what comes back & what each value means16 fields
200 OK with the standard { data, meta } envelope. data is an ARRAY of audit-log event objects (cursor-paginated); meta.page carries the limit and the opaque nextCursor. Response is no-store; no Set-Cookie. SCOPE — an event belongs to this log if it is stamped with the caller's tenant OR is an IDENTITY-PLANE event (tenant_id NULL) about somebody who is a member of it. The second half exists because authentication events happen BEFORE any tenant is resolved: a device challenge is issued while the user is still proving who they are, so device_challenge_issued / device_trust_failed / login_challenge_failed / registration_resumed / login_mode_changed carry no tenant. Filtering on tenant_id alone hid device_trust_failed — a correct password followed by repeated device-challenge failures, the fingerprint of credential stuffing landing on a real account — from the only person positioned to act on it. Nothing from another tenant can leak: anything tenant-scoped carries a non-NULL tenant_id and is excluded unless it is this one.
dataarrayalwaysdata[].idstringalwaysdata[].eventstringalwaysdata[].userIdUUIDalwaysdata[].sessionIdstringalwaysdata[].outcomeenumalwayssuccess— The audited action completed successfully.failure— The audited action was attempted but did not succeed.
data[].reasonstringalwaysdata[].ipstringalwaysdata[].traceIdstringalwaysdata[].actOperatorIdUUIDalwaysdata[].actReasonstringalwaysdata[].occurredAtISO-8601alwaysmetaobjectalwaysmeta.pageobjectalwaysmeta.page.limitintegeralwaysmeta.page.nextCursorstringalways