UptimeHunt Docs
Organizations

Organization Audit Log

Tamper-resistant audit trail for team organizations with complete event catalog, filtering, and CSV export.

Organization Audit Log

Overview

Every team organization gets a tamper-resistant, organization-wide audit trail covering authentication, SSO, membership, configuration, token, and monitoring-resource events. It is designed to satisfy SOC2-style evidence requirements: who did what, to which resource, from where, and when.

Viewing the organization audit log requires the audit.view capability (Admin and Owner — see Roles & Permissions) and the Enterprise plan. Below Enterprise the endpoints return 403 with {"code": "AUDIT_LOG_NOT_IN_PLAN"}. Events are always recorded regardless of plan — the gate is on viewing, so upgrading to Enterprise exposes the full history.

Personal activity log

Your personal activity view (your own actions, available to every account whose active workspace's plan includes the audit log) is separate from the organization-wide log described here.

What Is Recorded

Each event captures: timestamp, organization, actor (with a snapshot label that survives account deletion and identifies the actor's identity realm), actor IP address and user agent, a dotted event type, the affected resource (type, ID, label), and structured details — including old/new values for configuration changes.

Event catalog

DomainEvents
Authenticationauth.login.success, auth.login.failure, auth.logout, auth.register, auth.email_verified, auth.password.changed, auth.password_reset.requested, auth.password_reset.completed, auth.profile.updated, auth.token.refreshed
SSOsso.login.success, sso.login.failure, sso.user.provisioned, sso.config.created, sso.config.updated, sso.config.deleted, sso.enforced.enabled, sso.enforced.disabled, sso.enforced.refused (a readiness guard blocked enabling enforcement; blocker codes in details)
Organizationorg.created, org.updated (with per-field old/new values), org.converted, org.deleted, org.domain.added, org.domain.verified, org.domain.removed
Membershipmember.invited, member.invite_revoked, member.joined, member.role_changed (old/new role in details), member.removed
GitHub team mappinggithub.team_mapping.updated (the team→role mapping or its unmapped-member policy was changed; old/new values in details.changed), github.team_role.applied (a sign-in re-synced a member's role from their GitHub-team membership; previous_role and new_role always in details, plus team_slug — the matched rule's team slug whenever a team rule decided the role (new join or re-sync alike), null only when the unmapped-members policy — not a rule match — provided the role), github.team_role.denied (a deny-policy mapping refused the sign-in/join), github.team_role.lookup_failed (GitHub's teams API could not be read at sign-in; path always in details, with three shapes: an existing member who keeps their role records path + error (the lookup-failure class), no jit; a new just-in-time sign-in refused under the Refuse sign-in policy records only path + jit on the dedicated-accounts flow (path: 'sso', no error) — while on the platform path (explicit join) the same JIT deny records path + error, no jit; a new just-in-time member provisioned with the default role under a non-deny policy when teams were unreadable records path: 'sso', jit: true, error (the lookup-failure class), and role (the granted role))
Resourcesproject.created/.updated/.deleted, service.* (including service.paused/service.resumed), integration.*, alert_rule.*, service.expectations_updated
Tokenstoken.created, token.updated, token.revoked (revoker may differ from the token owner — token oversight), oauth.grant_created, oauth.grant_revoked
Authorizationauthz.denied — rejected write attempts, e.g. grant-ceiling violations

Notes:

  • Failed sign-ins are attributed to your organization via the targeted account's membership (and the targeted IdP for SSO failures), so Owners and Admins can review attacks against their members.
  • High-frequency login failures from the same source against the same account are coalesced into a single event with an attempt counter in the details, keeping floods reviewable.

Viewing and Filtering

UI: Organization → Audit Log — filter by event domain, actor, resource type, and time range.

API:

curl "https://app.uptimehunt.io/api/v1/orgs/acme/audit-log?event_type=member.&from=2026-05-01T00:00:00Z&to=2026-06-01T00:00:00Z" \
  -H "Authorization: Bearer {access_token}"
ParameterDescription
event_typeExact event type (e.g. member.removed), or a domain prefix ending with a dot — member. matches all membership events, sso.config. only SSO configuration changes
actorFilter by member (user ID)
resource_typeFilter by resource type (e.g. service)
from / toISO 8601 time range
limit / offsetPagination (default 50)

Response (200 OK):

{
  "data": [
    {
      "id": "0d4f9a4e-2b7c-4f4e-9a31-8f2f6f3e9c1a",
      "timestamp": "2026-05-14T09:21:33.481920+00:00",
      "event_type": "member.role_changed",
      "actor": {"id": 12, "label": "owner@acme.example (password)"},
      "actor_ip": "203.0.113.7",
      "resource_type": "membership",
      "resource_id": "31",
      "resource_label": "alex@acme.example",
      "details": {"role": ["member", "admin"]}
    }
  ],
  "meta": {"total": 1, "limit": 50, "offset": 0}
}
FieldDescription
idEvent UUID (string)
timestampISO 8601 event time
event_typeDotted event type (see the catalog)
actorA nested object — id (the actor's user ID, null for system events) and label (the snapshot label including the identity realm, e.g. alex@acme.example (sso:acme))
actor_ipClient IP address (null when unavailable)
resource_type / resource_id / resource_labelThe affected resource; resource_id is always a string, the label is a write-time snapshot
detailsStructured event context (JSON object), e.g. old/new values for configuration changes

The actor's user agent is recorded with each event but is not part of the JSON or CSV serialization; the organization is implicit in the endpoint path.

CSV Export

For compliance evidence packages, request the same endpoint with a CSV Accept header (or ?format=csv):

curl "https://app.uptimehunt.io/api/v1/orgs/acme/audit-log?from=2026-01-01T00:00:00Z" \
  -H "Authorization: Bearer {access_token}" \
  -H "Accept: text/csv" \
  -o audit-export.csv

The same filters apply; the export is unpaginated (every matching event) and downloads as {org-slug}-audit-log.csv. Columns, in order:

id, timestamp, event_type, actor_id, actor_label, actor_ip,
resource_type, resource_id, resource_label, details

The JSON response's nested actor object flattens into the actor_id and actor_label columns; details is serialized as a JSON string (keys sorted); actor_id and actor_ip are empty strings when the JSON value would be null.

Integrity and Retention

  • Append-only at the database level. The application's database role is denied UPDATE and DELETE on the audit table — events cannot be altered or removed through the application, by any role, including Owners.
  • Snapshot labels. Actor and resource labels are snapshotted at write time, so the trail stays readable after users or resources are deleted.
  • Retention: at least 15 months — covering a full SOC2 Type II 12-month observation window with margin. Export to CSV periodically if your compliance program needs longer retention on your side.
  • Audit-write failures are never silently ignored — they are logged and alarmed operationally.

On this page