Audit Logs
Audit Logs record activity and changes across your organization for security, compliance, and troubleshooting. Each entry captures who did what, to which record, and when — including the before/after values for updates.
Overview
The Audit Logs page lets you:
- Browse a paginated, time-ordered list of organization activity (newest first)
- Filter entries by action type, entity type, and date range
- Open any entry to see the full change detail, including before/after values
- See the acting user (or System for automated actions), the source IP address, and the browser user agent
Navigate to Audit Logs
Go to Admin → Audit Logs (/admin/audit-logs). This page is restricted to the Owner and Admin roles. Other roles receive a permission error.
Reading the log list
The log table shows the following columns:
| Column | Description |
|---|---|
| Timestamp | Relative time (e.g. "2 hours ago") plus the time of day |
| User | The person who performed the action (name and email), or System for automated/background actions |
| Action | The action performed, shown as a colored badge with an icon |
| Entity | The record type affected (e.g. Ticket, Client), with the record's name when available |
| IP Address | The source IP of the request, when recorded |
| Actions | A Details button that opens the full entry |
The card header shows the total number of matching entries, and pagination controls (Previous / Next) appear below the table when there is more than one page.
Filtering
Filters appear above the table. Adjusting any filter resets the list to the first page.
| Filter | Options |
|---|---|
| Action Type | All Actions, Create, Update, Delete, Login, Logout |
| Entity Type | All Types, Client, Contact, Ticket, Invoice, Payment, Asset, User, Organization, Integration |
| Start Date | Earliest date to include |
| End Date | Latest date to include |
Use Clear Filters to reset all filters at once. The current filters are kept in the page URL, so a filtered view can be bookmarked or shared with another admin.
Action types
Each entry has an action. The most common actions appear with a dedicated badge:
| Action | Meaning |
|---|---|
| Create | A record was created |
| Update | A record was modified |
| Delete | A record was removed |
| Login | A user signed in |
| Logout | A user signed out |
| View | A record was accessed |
| Reveal | A credential's secret (password / OTP secret / live 2FA code) was revealed to a user — distinct from a generic view so credential reveals are directly answerable. The secret value itself is never stored in the log. |
| Sync | Data was synchronized (e.g. an integration) |
| Purge | Entries older than the retention window were archived and removed (see Retention policy) |
Other action values are also recorded by the system — including archive, restore, failed login, export, import, access, and permission changes — and display with a generic badge using the raw action name.
Entity details
The Entity column identifies the type of record an action affected. Audit entries can reference many record types, including clients, contacts, tickets, invoices, payments, assets, users, the organization itself, integrations, contracts, projects, documents, domains, certificates, credentials, software, vendors, locations, networks, products, tags, racks, quotes, and opportunities. When the affected record still exists, its name (or number, for invoices and quotes) is shown; otherwise the entry shows a shortened record ID.
Entry detail view
Click Details on any row to open the full entry. The detail dialog shows:
| Field | Description |
|---|---|
| Timestamp | The exact date and time of the action |
| Action | The action badge |
| Entity | The affected record's type and name (or ID) |
| User | The acting user's name and email, or System |
| IP Address | Source IP, when recorded |
| User Agent | The browser/client string, when recorded |
| Changes | A field-by-field Before / After comparison for the action |
The Changes section only lists fields whose values actually changed. To protect sensitive information, values are cleaned up before an entry is recorded, so they are never exposed in full in the before/after comparison:
- Secrets — passwords, MFA secrets, API keys, and encrypted values are fully redacted and shown as
[REDACTED]. - Binary data — file contents and similar binary values are replaced with
[BINARY DATA]. - Personal data — fields such as email addresses, phone numbers, government identifiers (for example SSN, tax/VAT, passport), and postal/street data are masked rather than shown in full. Enough is kept to recognize that the field changed — for example an email appears as
b***@example.comand a phone number as***-4567— without storing the complete personal detail. Security-relevant fields such as the source IP address and user agent are kept in full.
Exporting audit logs
Admins can download a copy of the organization's audit log — for example, to hand to an auditor as evidence or to analyze events outside the app.
Use the Export button at the top of the Audit Logs page, then choose a format:
| Format | Best for |
|---|---|
| Export as CSV | Opening in a spreadsheet (Excel, Google Sheets) for filtering and review. One row per event with the core columns: timestamp, action, entity type, entity, the acting user (name and email), and source IP. |
| Export as JSON | Machine processing or a complete record. Includes everything in the CSV plus the browser/client user agent and the full before/after change detail for each event. |
The export honors the filters currently applied on the page. If you've set an action type, entity type, user, or a start/end date, only the matching events are included — so to export everything, clear the filters first. The downloaded file is named audit-log-<date>.csv or audit-log-<date>.json.
A single export returns up to 50,000 events in chronological order (oldest first), so it reads as a timeline. If your date range would exceed that, narrow the range (or other filters) and export in batches.
As with the on-screen detail view, sensitive fields (passwords, MFA secrets, API keys, encrypted values) are already redacted in the stored entries, so they are never present in an export.
Exports are themselves logged
Running an export is a security-relevant action, so it is recorded in the audit log as an Export event. The entry captures who performed the export, the date range and filters used, the chosen format, and how many events were included — giving you a complete, tamper-evident record of who accessed audit data and when.
Retention policy
By default Ascent keeps audit entries for 365 days (one year). To change how long they are stored — for example, to meet a data-retention or storage-limitation requirement, or to keep them forever — you can adjust the retention window.
The Retention policy card near the top of the Audit Logs page (visible to Owner and Admin roles) shows the current window and lets you change it:
| Setting | Meaning |
|---|---|
A number of days (e.g. 365) | Entries older than this many days are archived and removed from the live log. The supported range is 30–3650 days. |
0 | Retention is disabled — entries are kept forever. |
A background job runs once a day. For each organization, it takes every entry older than your window, copies it into a separate cold-storage archive, and then removes it from the live log. The archive preserves the original entries (including their tamper-evidence hash) as evidence — nothing is silently destroyed:
- The purge itself is recorded as a Purge entry in the log, capturing the cutoff date and how many entries were retired.
- Because archived entries keep their hash, the integrity check can still tell a legitimate retention purge apart from an unauthorized deletion — removing entries outside the retention policy still shows up as tampering.
Changing the retention window is itself recorded as an Update audit entry, so policy changes are traceable.
High-risk event alerts
Beyond keeping a record, Ascent can watch the audit trail for anomalous activity and notify admins the moment a signal crosses a threshold. The High-risk event alerts card on the Audit Logs page (visible to Owner and Admin roles) tunes the monitor. A master Enable high-risk event monitoring toggle turns the whole feature on or off; each signal below also has its own switch.
The defaults are conservative — chosen so the monitor is safe to leave on without flooding admins — and each threshold is a count within a rolling window (in minutes):
| Signal | What it watches | Default |
|---|---|---|
| Mass deletions | A single user deleting many records in a short burst | Alert after 20 deletes within 10 min |
| Permission/role changes | A flurry of permission or role edits | Alert after 5 changes within 10 min |
| Repeated failed sign-ins | Many failed sign-ins for one member (possible password attack) | Alert after 5 failures within 15 min |
| Audit-log integrity failures | The tamper-evidence hash chain is checked on a schedule and an alert fires if it ever fails to verify | Checked every 60 min |
A shared Re-alert cooldown (default 60 min) suppresses duplicate alerts for the same signal so a single ongoing incident doesn't page repeatedly. When a signal fires, the alert is delivered to admins through the normal notification channels (in-app and, where enabled, email) and links straight to the relevant audit entry.
Integrity verification and external anchoring
Every audit entry is part of a tamper-evidence hash chain: each row is cryptographically linked to the one before it, so a silent edit or deletion made directly in the database — bypassing the application — breaks the chain at a detectable point. The Audit-log integrity failures signal above runs this verification automatically on a schedule, and the chain can also be checked on demand through the admin-only GET /api/audit/verify-integrity endpoint, which reports whether the chain is intact and, if not, the first broken link.
For higher-assurance environments, operators can additionally enable external anchoring ("genesis trust"). When turned on (an operator sets AUDIT_ANCHOR_SINK=database; it is disabled by default), a daily job publishes each organization's current chain head to an append-only, write-once store. The integrity check then cross-checks those anchors and raises a distinct anchor-mismatch finding if a previously anchored head has vanished — the signature of a wholesale log rewrite that an internally consistent chain alone can't catch. Anchoring is defense-in-depth layered on top of the database-level append-only protections, and it is fully compatible with the retention policy — a routine purge never raises a false alarm. See the Trust & Security overview for the full audit-integrity model.
Viewing the logs is itself recorded
Looking at the audit log is a security-relevant action, so opening the Audit Logs page is recorded in the audit log as an Access event attributed to the admin who viewed it. This answers the auditor question "who looked at the logs?".
To keep the trail readable, access is recorded coarsely: paging through results or refreshing the page does not add a new entry each time — at most one Access event is written per admin per hour. To find these entries, filter the Action Type to Access (or the Entity Type to Audit Log Access). These meta-events are scoped to your own organization, just like every other entry.
What gets logged
Audit entries are written automatically as actions occur throughout the application. They are not editable, and individual entries cannot be deleted from this page — the only way entries leave the live log is the retention policy above, which archives them first. Background and integration processes (for example, email sync) are attributed to System rather than a specific user.
Payments are captured however they are recorded: manual payments entered in the app, and online card payments taken through Stripe — whether the customer paid through the public invoice link or the payment was reconciled by a Stripe webhook (such as a refund). Because online and webhook-driven payments are not tied to a signed-in user, they appear as Payment Create entries attributed to System.
Tips
- Combine the Action Type and Entity Type filters with a date range to narrow an investigation quickly — for example, Delete actions on Ticket records within a specific week.
- Use the Details view to confirm exactly which fields changed during an Update, rather than relying on the list alone.
- Because filter state lives in the URL, you can save a frequently used filtered view as a browser bookmark.
- If a record's name is missing in the Entity column, the underlying record has likely been deleted; the entry still preserves the change history.