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_admininstitution_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
| Parameter | Type | Description |
|---|---|---|
institution_id | integer | system_admin only — filter to a specific institution. Ignored for institution_admin (their own institution_id is forced). |
event | string | Filter by the activity event column (e.g. created, updated, roles_updated). |
subject_type | string | Filter by the fully-qualified model class of the audited subject (e.g. App\Models\Donation). |
per_page | integer | Results per page (default: 20, max: 100). |
Who Sees What
| Role | Visibility |
|---|---|
system_admin | All institutions. May optionally filter by institution_id. |
institution_admin | Forced 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_member | 403 Forbidden — no view audit logs permission, never reaches the controller. |
donor | 403 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 Status | Error Scenario | Response Payload Summary |
|---|---|---|
403 Forbidden | Actor 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 record | data.data is an empty array — fails closed, never falls back to showing all institutions |