Organization Audit Logs API

Comprehensive API for accessing organization audit logs with detailed tracking of administrative actions for compliance, security, and governance.

Updated Nov 15, 2025
Edit on GitHub
audit-logs compliance security governance

Organization Audit Logs

Comprehensive API for accessing organization audit logs, providing detailed tracking of all administrative actions for compliance, security, and governance.

Overview

Organization audit logs track all administrative actions within an organization, providing a complete audit trail for:

  • Compliance: Meet regulatory requirements (SOC 2, GDPR, HIPAA)
  • Security: Detect and investigate suspicious activities
  • Governance: Monitor who did what and when
  • Debugging: Troubleshoot configuration changes and issues
  • Accountability: Maintain transparency in team operations

Each audit log entry includes:

  • Actor: User who performed the action
  • Action: Type of event (e.g., service.created, user.invited)
  • Target: Resource affected (e.g., service, user, organization)
  • Timestamp: When the action occurred
  • Details: Additional context (JSON)
  • Success: Whether the action succeeded
  • IP Address: Client IP (if available)
  • User Agent: Client browser/tool (if available)

Data Models

Audit Log Entry

{
  "id": "uuid",
  "org_id": "uuid",
  "actor_user_id": "uuid",
  "actor_email": "admin@acme.com",
  "action": "service.created",
  "target_type": "service",
  "target_id": "service-uuid",
  "ip_address": "203.0.113.42",
  "user_agent": "Mozilla/5.0...",
  "success": true,
  "details": {
    "service_slug": "main-app",
    "service_name": "Main Application",
    "service_type": "web",
    "client_id": "client-uuid"
  },
  "created_at": "2025-01-15T10:30:00Z"
}

Audit Log Response with User

{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "org_id": "org-uuid",
  "actor": {
    "id": "user-uuid",
    "email": "admin@acme.com",
    "is_platform_owner": false
  },
  "action": "service.created",
  "target_type": "service",
  "target_id": "service-uuid",
  "ip_address": "203.0.113.42",
  "user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36",
  "success": true,
  "details": {
    "service_slug": "main-app",
    "service_name": "Main Application",
    "service_type": "web",
    "client_id": "client-uuid"
  },
  "created_at": "2025-01-15T10:30:00Z"
}

Pagination Info

{
  "page": 1,
  "limit": 50,
  "total": 1250,
  "total_pages": 25,
  "has_next": true,
  "has_prev": false
}

Audit Event Types

For a complete reference of all audit events including triggering actions and details payload schemas, see Audit Events Reference.

User Management Events

Event Description Target Type
user.invited User invited to organization user
user.joined User accepted invitation user
user.removed User removed from organization user
user.role_updated User role changed (owner/admin/member) user

Service Management Events

Event Description Target Type
service.created New service created service
service.updated Service configuration updated service
service.deleted Service deleted service
service.oauth_credentials.updated OAuth credentials configured service

Organization Management Events

Event Description Target Type
organization.updated Organization details updated organization
organization.smtp.configured SMTP settings configured organization
organization.smtp.removed SMTP settings removed organization

Plan Management Events

Event Description Target Type
plan.created Subscription plan created plan
plan.updated Plan details updated plan
plan.deleted Plan deleted plan

Subscription Management Events

Event Description Target Type
subscription.created User subscribed to plan subscription
subscription.updated Subscription modified subscription
subscription.canceled Subscription canceled subscription

Invitation Management Events

Event Description Target Type
invitation.accepted Invitation accepted invitation
invitation.declined Invitation declined invitation
invitation.expired Invitation expired invitation
invitation.revoked Invitation revoked invitation

Security Events

Event Description Target Type
security.mfa.enabled MFA enabled user
security.mfa.disabled MFA disabled user
security.password.changed Password changed user

API Key Management Events

Event Description Target Type
api_key.created API key created api_key
api_key.deleted API key deleted api_key

Custom Domains & Branding Events

Event Description Target Type
domain.set Custom domain set organization
domain.verified Custom domain verified organization
domain.deleted Custom domain removed organization
branding.updated Branding settings updated organization

Endpoints Summary

Method Path Description Permissions
GET /api/organizations/:org_slug/audit-log Get audit logs Owner/Admin
GET /api/organizations/:org_slug/audit-log/event-types Get available event types Owner/Admin

Audit Log Operations

GET /api/organizations/:org_slug/audit-log

Retrieve paginated audit logs for an organization with optional filtering.

Permissions: Owner or Admin

Headers:

Header Value
Authorization Bearer {jwt}

Path Parameters:

Parameter Type Description
org_slug string Organization slug

Query Parameters:

Parameter Type Required Description
page integer No Page number (default: 1, min: 1)
limit integer No Items per page (default: 50, max: 100)
action string No Filter by specific action (e.g., service.created)
target_type string No Filter by target type (e.g., service, user)
target_id string No Filter by specific target ID (requires target_type)

Example Request (All Logs):

curl -X GET "https://sso.example.com/api/organizations/acme-corp/audit-log?page=1&limit=50" \
  -H "Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9..."

Example Request (Filter by Action):

curl -X GET "https://sso.example.com/api/organizations/acme-corp/audit-log?action=service.created" \
  -H "Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9..."

Example Request (Filter by Target):

curl -X GET "https://sso.example.com/api/organizations/acme-corp/audit-log?target_type=service&target_id=service-uuid" \
  -H "Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9..."

Example Response (200 OK):

{
  "logs": [
    {
      "id": "log-uuid-1",
      "org_id": "org-uuid",
      "actor": {
        "id": "user-uuid",
        "email": "admin@acme.com",
        "is_platform_owner": false
      },
      "action": "service.created",
      "target_type": "service",
      "target_id": "service-uuid",
      "ip_address": "203.0.113.42",
      "user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36",
      "success": true,
      "details": {
        "service_slug": "main-app",
        "service_name": "Main Application",
        "service_type": "web",
        "client_id": "client-uuid"
      },
      "created_at": "2025-01-15T10:30:00Z"
    },
    {
      "id": "log-uuid-2",
      "org_id": "org-uuid",
      "actor": {
        "id": "user-uuid",
        "email": "admin@acme.com",
        "is_platform_owner": false
      },
      "action": "user.invited",
      "target_type": "user",
      "target_id": "invited-user-uuid",
      "ip_address": "203.0.113.42",
      "user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36",
      "success": true,
      "details": {
        "invited_email": "newuser@acme.com",
        "role": "member"
      },
      "created_at": "2025-01-15T11:00:00Z"
    },
    {
      "id": "log-uuid-3",
      "org_id": "org-uuid",
      "actor": {
        "id": "user-uuid",
        "email": "admin@acme.com",
        "is_platform_owner": false
      },
      "action": "api_key.created",
      "target_type": "api_key",
      "target_id": "api-key-uuid",
      "ip_address": "203.0.113.42",
      "user_agent": "curl/7.79.1",
      "success": true,
      "details": {
        "api_key_id": "api-key-uuid",
        "service_id": "service-uuid",
        "service_slug": "main-app",
        "name": "Production Backend",
        "permissions": ["read:users", "read:subscriptions"],
        "expires_at": "2025-04-15T10:30:00Z"
      },
      "created_at": "2025-01-15T14:20:00Z"
    }
  ],
  "pagination": {
    "page": 1,
    "limit": 50,
    "total": 150,
    "total_pages": 3,
    "has_next": true,
    "has_prev": false
  }
}

Error Responses:

  • 401 Unauthorized: Invalid or missing JWT
  • 403 Forbidden: User is not an owner or admin
  • 404 Not Found: Organization not found
  • 500 Internal Server Error: Database error

Notes:

  • Logs are returned in reverse chronological order (newest first)
  • Actor information is populated with user details
  • details field contains action-specific context (JSON)
  • success: false indicates failed actions (e.g., validation errors)
  • IP address and user agent may be null for background jobs
  • Maximum 100 items per page
  • Use action filter for specific event types
  • Use target_type + target_id to see all actions on a specific resource

Filtering Examples:

# All service-related events
GET /api/organizations/acme-corp/audit-log?target_type=service

# All actions by a specific user (as target)
GET /api/organizations/acme-corp/audit-log?target_type=user&target_id=user-uuid

# All failed actions
# (Note: filtering by success not currently supported - filter on client)

# Events from the last 7 days
# (Note: date filtering not currently supported - filter on client)

GET /api/organizations/:org_slug/audit-log/event-types

Get available audit event types for filtering.

Permissions: Owner or Admin

Headers:

Header Value
Authorization Bearer {jwt}

Path Parameters:

Parameter Type Description
org_slug string Organization slug

Example Request:

curl -X GET https://sso.example.com/api/organizations/acme-corp/audit-log/event-types \
  -H "Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9..."

Example Response (200 OK):

[
  {
    "value": "user.invited",
    "label": "User Invited",
    "category": "User Management"
  },
  {
    "value": "user.joined",
    "label": "User Joined",
    "category": "User Management"
  },
  {
    "value": "user.removed",
    "label": "User Removed",
    "category": "User Management"
  },
  {
    "value": "user.role_updated",
    "label": "User Role Updated",
    "category": "User Management"
  },
  {
    "value": "service.created",
    "label": "Service Created",
    "category": "Service Management"
  },
  {
    "value": "service.updated",
    "label": "Service Updated",
    "category": "Service Management"
  },
  {
    "value": "service.deleted",
    "label": "Service Deleted",
    "category": "Service Management"
  },
  {
    "value": "service.oauth_credentials.updated",
    "label": "Service OAuth Credentials Updated",
    "category": "Service Management"
  },
  {
    "value": "organization.updated",
    "label": "Organization Updated",
    "category": "Organization Management"
  },
  {
    "value": "organization.smtp.configured",
    "label": "Organization SMTP Configured",
    "category": "Organization Management"
  },
  {
    "value": "organization.smtp.removed",
    "label": "Organization SMTP Removed",
    "category": "Organization Management"
  },
  {
    "value": "plan.created",
    "label": "Plan Created",
    "category": "Plan Management"
  },
  {
    "value": "plan.updated",
    "label": "Plan Updated",
    "category": "Plan Management"
  },
  {
    "value": "plan.deleted",
    "label": "Plan Deleted",
    "category": "Plan Management"
  },
  {
    "value": "subscription.created",
    "label": "Subscription Created",
    "category": "Subscription Management"
  },
  {
    "value": "subscription.updated",
    "label": "Subscription Updated",
    "category": "Subscription Management"
  },
  {
    "value": "subscription.canceled",
    "label": "Subscription Canceled",
    "category": "Subscription Management"
  },
  {
    "value": "invitation.accepted",
    "label": "Invitation Accepted",
    "category": "Invitation Management"
  },
  {
    "value": "invitation.declined",
    "label": "Invitation Declined",
    "category": "Invitation Management"
  },
  {
    "value": "invitation.expired",
    "label": "Invitation Expired",
    "category": "Invitation Management"
  },
  {
    "value": "invitation.revoked",
    "label": "Invitation Revoked",
    "category": "Invitation Management"
  },
  {
    "value": "security.mfa.enabled",
    "label": "MFA Enabled",
    "category": "Security"
  },
  {
    "value": "security.mfa.disabled",
    "label": "MFA Disabled",
    "category": "Security"
  },
  {
    "value": "security.password.changed",
    "label": "Password Changed",
    "category": "Security"
  },
  {
    "value": "api_key.created",
    "label": "API Key Created",
    "category": "API Key Management"
  },
  {
    "value": "api_key.deleted",
    "label": "API Key Deleted",
    "category": "API Key Management"
  },
  {
    "value": "domain.set",
    "label": "Domain Set",
    "category": "Custom Domains & Branding"
  },
  {
    "value": "domain.verified",
    "label": "Domain Verified",
    "category": "Custom Domains & Branding"
  },
  {
    "value": "domain.deleted",
    "label": "Domain Deleted",
    "category": "Custom Domains & Branding"
  },
  {
    "value": "branding.updated",
    "label": "Branding Updated",
    "category": "Custom Domains & Branding"
  }
]

Error Responses:

  • 401 Unauthorized: Invalid or missing JWT
  • 403 Forbidden: User is not an owner or admin
  • 404 Not Found: Organization not found (path parameter only, no other 404s)
  • 500 Internal Server Error: Database error

Notes:

  • Returns all available event types with human-readable labels
  • Categorized for UI organization (e.g., dropdown groups)
  • Use value field for filtering in /audit-log endpoint
  • Event types are static and defined in the API code
  • New event types may be added in future versions

Common Use Cases

Security Investigation

Scenario: Investigate suspicious activity after detecting an anomaly.

# 1. Find all actions by a specific user
curl -X GET "https://sso.example.com/api/organizations/acme-corp/audit-log?page=1&limit=100" \
  -H "Authorization: Bearer ..." | jq '.logs[] | select(.actor.email == "suspect@acme.com")'

# 2. Check for service deletions
curl -X GET "https://sso.example.com/api/organizations/acme-corp/audit-log?action=service.deleted" \
  -H "Authorization: Bearer ..."

# 3. Review failed actions
curl -X GET "https://sso.example.com/api/organizations/acme-corp/audit-log?page=1&limit=100" \
  -H "Authorization: Bearer ..." | jq '.logs[] | select(.success == false)'

# 4. Check actions from unusual IP
curl -X GET "https://sso.example.com/api/organizations/acme-corp/audit-log?page=1&limit=100" \
  -H "Authorization: Bearer ..." | jq '.logs[] | select(.ip_address == "suspicious.ip.address")'

Compliance Audit

Scenario: Generate audit report for SOC 2 compliance.

# 1. Export all security events
curl -X GET "https://sso.example.com/api/organizations/acme-corp/audit-log?page=1&limit=100" \
  -H "Authorization: Bearer ..." | \
  jq '.logs[] | select(.category == "Security")' > security_events.json

# 2. Export all user management events
curl -X GET "https://sso.example.com/api/organizations/acme-corp/audit-log?target_type=user" \
  -H "Authorization: Bearer ..." > user_management.json

# 3. Generate CSV report
curl -X GET "https://sso.example.com/api/organizations/acme-corp/audit-log?page=1&limit=1000" \
  -H "Authorization: Bearer ..." | \
  jq -r '.logs[] | [.created_at, .actor.email, .action, .target_type, .target_id, .success] | @csv' \
  > audit_report.csv

Configuration Change Tracking

Scenario: Track changes to a specific service.

# Get all events for a specific service
curl -X GET "https://sso.example.com/api/organizations/acme-corp/audit-log?target_type=service&target_id=service-uuid" \
  -H "Authorization: Bearer ..."

# Example response shows:
# - When service was created
# - All configuration updates
# - OAuth credential changes
# - API key creations/deletions
# - Plan additions

User Activity Report

Scenario: Review all actions performed by a team member before offboarding.

# 1. Get all audit logs
curl -X GET "https://sso.example.com/api/organizations/acme-corp/audit-log?page=1&limit=1000" \
  -H "Authorization: Bearer ..."

# 2. Filter by actor email on client
jq '.logs[] | select(.actor.email == "leaving-employee@acme.com")' audit_logs.json

# 3. Group by action type
jq 'group_by(.action) | map({action: .[0].action, count: length})' filtered_logs.json

Security Considerations

Access Control:

  • Only owners and admins can view audit logs
  • Logs are scoped to organization (no cross-organization access)
  • Deleted users still appear in logs (email preserved)
  • Platform owners cannot access organization audit logs (privacy)

Data Retention:

  • Audit logs are retained indefinitely by default
  • Consider implementing retention policies for GDPR compliance
  • Export logs regularly for archival
  • Logs survive organization deletion (platform-level cleanup required)

Sensitive Information:

  • Passwords and secrets are never logged
  • OAuth tokens are never logged
  • API keys are logged by ID only (not full key)
  • Personal data (email) is logged for accountability
  • Consider GDPR right to erasure when deleting users

Performance:

  • Large organizations may have millions of log entries
  • Use pagination to avoid timeouts
  • Filter by action or target to reduce dataset size
  • Consider exporting to external log management system (e.g., Splunk, Datadog)

Tamper Protection:

  • Audit logs are append-only (cannot be modified)
  • Deletions are not supported (immutable audit trail)
  • Actor information captured at event time (not dynamic)
  • Timestamps are server-side (cannot be spoofed)

Integration Examples

Export to Splunk

#!/bin/bash
# Export audit logs to Splunk

ORG_SLUG="acme-corp"
AUTH_TOKEN="your-jwt-token"
SPLUNK_URL="https://splunk.example.com:8088/services/collector"
SPLUNK_TOKEN="your-splunk-hec-token"

# Fetch logs
logs=$(curl -s -X GET "https://sso.example.com/api/organizations/$ORG_SLUG/audit-log?limit=100" \
  -H "Authorization: Bearer $AUTH_TOKEN")

# Send to Splunk
echo "$logs" | jq -c '.logs[]' | while read log; do
  curl -X POST "$SPLUNK_URL" \
    -H "Authorization: Splunk $SPLUNK_TOKEN" \
    -d "{\"event\": $log, \"sourcetype\": \"sso_audit_log\"}"
done

Slack Notifications

// Node.js: Send critical audit events to Slack

const axios = require('axios');

const CRITICAL_EVENTS = [
  'service.deleted',
  'user.removed',
  'api_key.created',
  'api_key.deleted',
  'security.mfa.disabled'
];

async function pollAuditLogs() {
  const response = await axios.get(
    'https://sso.example.com/api/organizations/acme-corp/audit-log?limit=10',
    { headers: { Authorization: `Bearer ${process.env.SSO_JWT}` } }
  );

  for (const log of response.data.logs) {
    if (CRITICAL_EVENTS.includes(log.action)) {
      await sendSlackAlert(log);
    }
  }
}

async function sendSlackAlert(log) {
  await axios.post(process.env.SLACK_WEBHOOK_URL, {
    text: `=� Critical Action: ${log.action}`,
    attachments: [{
      color: 'danger',
      fields: [
        { title: 'Actor', value: log.actor.email, short: true },
        { title: 'Target', value: log.target_type, short: true },
        { title: 'Time', value: log.created_at, short: true },
        { title: 'IP', value: log.ip_address || 'N/A', short: true }
      ]
    }]
  });
}

// Poll every 5 minutes
setInterval(pollAuditLogs, 5 * 60 * 1000);

Python Report Generator

import requests
import csv
from datetime import datetime

SSO_API = 'https://sso.example.com'
ORG_SLUG = 'acme-corp'
AUTH_TOKEN = 'your-jwt-token'

def export_audit_logs_to_csv(output_file='audit_logs.csv'):
    """Export all audit logs to CSV for compliance reporting."""

    headers = {'Authorization': f'Bearer {AUTH_TOKEN}'}
    page = 1
    all_logs = []

    # Paginate through all logs
    while True:
        response = requests.get(
            f'{SSO_API}/api/organizations/{ORG_SLUG}/audit-log',
            params={'page': page, 'limit': 100},
            headers=headers
        )
        data = response.json()
        all_logs.extend(data['logs'])

        if not data['pagination']['has_next']:
            break
        page += 1

    # Write to CSV
    with open(output_file, 'w', newline='') as csvfile:
        fieldnames = ['timestamp', 'actor_email', 'action', 'target_type',
                      'target_id', 'success', 'ip_address']
        writer = csv.DictWriter(csvfile, fieldnames=fieldnames)

        writer.writeheader()
        for log in all_logs:
            writer.writerow({
                'timestamp': log['created_at'],
                'actor_email': log['actor']['email'],
                'action': log['action'],
                'target_type': log['target_type'],
                'target_id': log['target_id'],
                'success': log['success'],
                'ip_address': log.get('ip_address', 'N/A')
            })

    print(f'Exported {len(all_logs)} audit logs to {output_file}')

if __name__ == '__main__':
    export_audit_logs_to_csv()

Best Practices

Regular Review:

  • Review audit logs weekly for unusual activity
  • Set up automated alerts for critical events
  • Export logs monthly for archival
  • Investigate all failed actions

Filtering Strategies:

  • Start broad, then narrow down with filters
  • Use action filter for specific event types
  • Use target_type + target_id for resource history
  • Export to external tools for advanced analytics

Compliance:

  • Document audit log retention policy
  • Export logs regularly for long-term storage
  • Include audit logs in security audits
  • Train team on audit log interpretation

Security Monitoring:

  • Alert on critical events (service deletion, user removal)
  • Monitor for unusual IP addresses
  • Track failed actions for potential attacks
  • Review API key creation/deletion regularly

Troubleshooting:

  • Use audit logs to track configuration changes
  • Compare timestamps with issue reports
  • Check details field for context
  • Verify actor identity for change management