Audit Logs

The audit trail (AuditLogController) exposes a single read-only endpoint over activity_log, backed by spatie/laravel-activitylog. It has no write endpoints of its own — entries are written implicitly by model LogsActivity hooks and explicit activity() calls elsewhere in the codebase whenever a money-path mutation, role change, or user/institution management action occurs.


Endpoint

GET /api/v1/audit-logs

Returns a paginated list of activity_log entries, scoped by tenant and gated by permission.


Permission Gate

The route carries ->middleware('permission:view audit logs'). Per RolePermissionSeeder, only two roles hold this permission:

  • system_admin
  • institution_admin

committee_member and donor do not hold view audit logs — they receive 403 Forbidden at the middleware layer, before any controller logic (including tenant scoping) runs.


Query Parameters

ParameterTypeDescription
institution_idintegersystem_admin only — filter to a specific institution. Ignored for institution_admin (their own institution_id is forced).
eventstringFilter by the activity event column (e.g. created, updated, roles_updated).
subject_typestringFilter by the fully-qualified model class of the audited subject (e.g. App\Models\Donation).
per_pageintegerResults per page (default: 20, max: 100).

Who Sees What

RoleVisibility
system_adminAll institutions. May optionally filter by institution_id.
institution_adminForced to their own institution_id. If their user record has no institution_id, the query fails closed to an empty result set — not an error, and not all institutions.
committee_member403 Forbidden — no view audit logs permission, never reaches the controller.
donor403 Forbidden — no view audit logs permission, never reaches the controller.

Response Shape

// Response (200 OK)
{
  "success": true,
  "data": {
    "current_page": 1,
    "data": [
      {
        "id": 1042,
        "log_name": "default",
        "description": "updated",
        "event": "updated",
        "subject_type": "App\\Models\\Donation",
        "subject_id": 88,
        "causer_type": "App\\Models\\User",
        "causer_id": 5,
        "institution_id": 2,
        "properties": {
          "old": { "status": "pending" },
          "attributes": { "status": "completed" }
        },
        "batch_uuid": null,
        "created_at": "2026-08-11T14:32:10.000000Z",
        "updated_at": "2026-08-11T14:32:10.000000Z",
        "causer": { "id": 5, "first_name": "Jane", "last_name": "Cruz" },
        "subject": { "id": 88, "status": "completed", "amount": "5000.00" }
      }
    ],
    "per_page": 20,
    "total": 137
  }
}

Error Codes

HTTP StatusError ScenarioResponse Payload Summary
403 ForbiddenActor lacks the view audit logs permission (committee_member, donor){"message": "This action is unauthorized."}
200 OK (empty result)institution_admin with no institution_id on their own user recorddata.data is an empty array — fails closed, never falls back to showing all institutions

Was this page helpful?