Admin audit-log search
Admin
Admin audit-log search
Role-scoped read of the append-only admin audit trail with cursor pagination. Every read is itself meta-audited.
GET
Admin audit-log search
Overview
Theaudit_logs collection is the append-only record of every consequential action performed by an admin, an automated system actor, or (for high-stakes user actions) a user. This endpoint exposes a paginated, filterable read of that trail.
Authorization is role-scoped at the service layer, not the middleware. Any admin role (SUPER, MODERATOR, FINANCE) passes the identity gate, but the query itself must be anchored unless the caller is SUPER:
| Role | Allowed queries |
|---|---|
SUPER | Any query, including no filters at all (full feed). |
MODERATOR | Must be anchored to actorId === self OR include a targetId. |
FINANCE | Same as MODERATOR — actorId === self OR a targetId. |
SUPER admin issuing a broad, unanchored query receives 403 FORBIDDEN. This prevents a moderator from trawling the trail; they can ask “what did I do” or “what happened to this user/listing” but not “what did everyone do today.”
Authentication
Bearer <accessToken> with scope: 'admin' required (requireAdmin). The role-scoping above is enforced by the service after identity is established.
Path parameters
None.Query parameters
All filters are optional except where the role-scoping rule kicks in (see overview). Multiple filters are combined with AND.| Name | Type | Required | Notes | Example |
|---|---|---|---|---|
actorId | string | conditional | Filter by acting principal id (admin id, user id, or null-string for SYSTEM). 1..64 chars. Non-SUPER admins typically set this to their own admin id. | 66400a8f1c2b4d5e6f7a8b01 |
action | string | no | Namespaced action key, e.g. user.banned, tenancy.approved, admin.login.mfa-complete. 1..128 chars, must match ^[a-z][a-z0-9._-]+$. | user.banned |
targetType | string | no | The kind of target (user, listing, tenancy, conversation, audit-log, …). 1..64 chars. | user |
targetId | string | conditional | The target’s id. 1..64 chars. Non-SUPER admins can use this to scope by “what happened to X”. | 66400a8f1c2b4d5e6f7a8b02 |
from | string | no | Inclusive lower bound on createdAt, ISO 8601 with timezone offset (Z or +00:00). | 2026-05-20T00:00:00Z |
to | string | no | Inclusive upper bound on createdAt, ISO 8601 with timezone offset. | 2026-05-23T23:59:59Z |
cursor | string | no | Opaque base64url pagination cursor returned in nextCursor on the previous page. 1..512 chars. | eyJjcmVhdGVkQXQ… |
limit | integer | no | Page size, 1..100. Default 25. Accepts a string that parses as an integer ("50"). | 50 |
Allowed query examples
Request body
None.Response — 200 OK
| Field | Type | Notes |
|---|---|---|
items | array | Audit-log entries (below), most-recent first by createdAt. |
nextCursor | string | null | Cursor for the next page, or null on the last page. |
Audit-log entry
| Field | Type | Notes | Example |
|---|---|---|---|
id | string | The audit_logs document _id, as a string. | 66400a8f1c2b4d5e6f7af000 |
actorType | enum | USER | ADMIN | SYSTEM. The kind of principal that did the action. | ADMIN |
actorId | string | null | The acting principal’s id, or null for SYSTEM actors. | 66400a8f1c2b4d5e6f7a8b01 |
action | string | Namespaced action key. Stable across releases. | user.banned |
targetType | string | null | The kind of target acted on (user, listing, tenancy, audit-log, …), or null if not applicable. | user |
targetId | string | null | The target’s id, or null if not applicable. | 66400a8f1c2b4d5e6f7a8b02 |
payload | object | Free-form, action-specific context. Always an object (never null). Examples: { reason: "spam" } for bans, { filters: { ... } } for audit-log.read. | { "reason": "Repeated harassment reports" } |
ip | string | null | Best-effort source IP. | 203.0.113.42 |
userAgent | string | null | Best-effort UA. | Swappr-Admin/1.0 |
createdAt | string | ISO 8601 UTC of when the row was appended. | 2026-05-22T15:08:11.412Z |
Pagination follows the cursor convention. The cursor is opaque — never decode it client-side. Items within a page are ordered most-recent-first; a row appended mid-pagination will surface on subsequent pages without disrupting the cursor.
Error responses
| Status | Code | Meaning |
|---|---|---|
| 400 | VALIDATION_FAILED | A field failed schema validation (e.g. limit out of 1..100, action does not match the ^[a-z][a-z0-9._-]+$ pattern, from/to not ISO 8601 with offset). |
| 401 | UNAUTHENTICATED | Missing, malformed, expired, or non-admin-scope token. |
| 403 | FORBIDDEN | Non-SUPER admin issued an unscoped query — neither actorId === self nor targetId was provided. |
Example error — 403 FORBIDDEN
Side effects
- Meta-audit row written. Each successful read appends an
audit-log.readrow with the requesting admin asactorId,targetType: 'audit-log', and the requested filters echoed intopayload.filters. The read is loggable retroactively.
See also
- Admin auth and MFA — how an admin gets the token used here.
- Ban user — writes a
user.bannedrow. - Approve tenancy / Reject tenancy — write
tenancy.approved/tenancy.rejected. - Pagination — cursor format and stability guarantees.
curl
Postman
Seedocs/postman/swappr.postman_collection.json → Admin → Audit log → Search.