Audit Logs
Comprehensive activity logging for security, compliance, and debugging.
What's Logged
Every significant action is recorded:
| Category | Examples |
|---|---|
| Authentication | Login, logout, MFA events, failed attempts |
| Authorization | Permission changes, role updates |
| Agents | Create, update, delete, execute |
| Conversations | Start, message, end, delete |
| Users | Invite, update, remove |
| Teams | Create, update, membership changes |
| Integrations | Connect, disconnect, tool execution |
| API Keys | Create, rotate, revoke |
| Settings | Configuration changes |
Viewing Audit Logs
Via Dashboard
- Go to Security → Audit Logs
- Filter by user, action, date range
- Export to CSV/JSON
Via API
const logs = await client.audit.list({
// Filters
userId: 'user-123',
action: 'agent.create',
severity: 'warning',
resourceType: 'agent',
resourceId: 'agent-456',
// Date range
startDate: '2024-01-01',
endDate: '2024-01-31',
// Search
search: 'delete',
// Pagination
limit: 100,
offset: 0
});
for (const log of logs.data) {
console.log({
id: log.id,
action: log.action,
severity: log.severity,
userId: log.userId,
resourceType: log.resourceType,
resourceId: log.resourceId,
description: log.description,
metadata: log.metadata,
ipAddress: log.ipAddress,
userAgent: log.userAgent,
timestamp: log.timestamp
});
}
Log Entry Structure
interface AuditLogEntry {
id: string;
tenantId: string;
// Who
userId: string;
userName?: string;
ipAddress: string;
userAgent: string;
// What
action: string;
severity: 'info' | 'warning' | 'critical';
resourceType: string;
resourceId: string;
description: string;
// Details
metadata: Record<string, any>;
// When
timestamp: string;
}
Action Types
Authentication Actions
| Action | Description |
|---|---|
auth.login | User logged in |
auth.logout | User logged out |
auth.login_failed | Failed login attempt |
auth.mfa_enabled | MFA was enabled |
auth.mfa_verified | MFA code verified |
auth.password_changed | Password was changed |
auth.password_reset | Password reset requested |
auth.session_revoked | Session was terminated |
Agent Actions
| Action | Description |
|---|---|
agent.create | Agent created |
agent.update | Agent configuration changed |
agent.delete | Agent deleted |
agent.chat | Chat message sent to agent |
agent.tool_executed | Agent executed a tool |
User Actions
| Action | Description |
|---|---|
user.invite | User invited |
user.joined | User accepted invite |
user.update | User profile updated |
user.role_changed | User role changed |
user.delete | User deleted |
Team Actions
| Action | Description |
|---|---|
team.create | Team created |
team.update | Team settings changed |
team.delete | Team deleted |
team.member_added | Member added to team |
team.member_removed | Member removed from team |
Integration Actions
| Action | Description |
|---|---|
integration.connected | Integration connected |
integration.disconnected | Integration revoked |
integration.tool_executed | Integration tool called |
integration.refresh | OAuth token refreshed |
API Key Actions
| Action | Description |
|---|---|
api_key.created | API key created |
api_key.rotated | API key rotated |
api_key.revoked | API key revoked |
Severity Levels
| Level | Description | Examples |
|---|---|---|
info | Normal operations | Login, create agent |
warning | Potentially concerning | Failed login, permission denied |
critical | Security-relevant | User deleted, bulk operation |
Filter by Severity
// Get only security-relevant events
const criticalLogs = await client.audit.list({
severity: 'critical'
});
// Get warnings and above
const warningsAndCritical = await client.audit.list({
severity: ['warning', 'critical']
});
Search and Filter
By User
const userLogs = await client.audit.list({
userId: 'user-123'
});
By Action
// Single action
const createLogs = await client.audit.list({
action: 'agent.create'
});
// Multiple actions
const modifyLogs = await client.audit.list({
action: ['agent.update', 'agent.delete']
});
// Pattern matching
const allAgentLogs = await client.audit.list({
action: 'agent.*'
});
By Resource
const agentLogs = await client.audit.list({
resourceType: 'agent',
resourceId: 'agent-123'
});
By Time Range
const recentLogs = await client.audit.list({
startDate: '2024-01-15T00:00:00Z',
endDate: '2024-01-15T23:59:59Z'
});
Full-Text Search
const searchResults = await client.audit.list({
search: 'production agent delete'
});
Statistics
Get aggregated audit data:
const stats = await client.audit.getStats({
startDate: '2024-01-01',
endDate: '2024-01-31'
});
console.log({
totalEvents: stats.total,
bySeverity: stats.bySeverity,
byAction: stats.byAction,
topUsers: stats.topUsers,
failedLogins: stats.failedLogins
});
Security Alerts
Configure alerts for suspicious activity. Alerts trigger when a specific action pattern occurs more than a threshold number of times within a time window.
Create Alert
await client.audit.createAlert({
name: 'Multiple Failed Logins',
description: 'Alert when multiple login failures occur', // optional
condition: {
action: 'auth.login_failed', // action pattern to match
threshold: 5, // number of occurrences
window: '5m' // time window: 5m, 1h, 24h, etc.
},
notify: ['security@company.com'], // email recipients (required)
notifyWebhook: 'https://slack.com/...', // optional webhook URL
severity: 'high' // low, medium, high, critical
});
Schedule-Based Alerts (SOX Compliance)
For SOX compliance, you can configure alerts that only trigger during or outside specific hours. This is essential for monitoring after-hours access.
// Alert when admin actions occur OUTSIDE business hours (after-hours monitoring)
await client.audit.createAlert({
name: 'After-Hours Admin Activity',
description: 'Alert when admin actions occur outside business hours',
condition: {
action: 'admin.*',
threshold: 1,
window: '5m'
},
timeWindow: {
mode: 'exclude', // 'exclude' = alert OUTSIDE these hours, 'include' = alert DURING these hours
start: '09:00', // Business hours start (HH:MM)
end: '18:00', // Business hours end (HH:MM)
daysOfWeek: [1, 2, 3, 4, 5], // Mon-Fri (0=Sun, 6=Sat)
useUserTimezone: true, // SOX: evaluate in acting user's local timezone
timezone: 'America/New_York' // Fallback if useUserTimezone is false
},
notify: ['security@company.com', 'compliance@company.com'],
severity: 'critical'
});
// Alert for weekend access
await client.audit.createAlert({
name: 'Weekend System Access',
condition: {
action: 'auth.login',
threshold: 1,
window: '1h'
},
timeWindow: {
mode: 'include', // Alert only DURING these times (weekends)
start: '00:00',
end: '23:59',
daysOfWeek: [0, 6], // Sat-Sun only
useUserTimezone: true
},
notify: ['security@company.com'],
severity: 'high'
});
Time Window Options
| Field | Description |
|---|---|
mode | 'always' (24/7), 'include' (only during hours), 'exclude' (only outside hours) |
start | Start time in HH:MM format (e.g., '09:00') |
end | End time in HH:MM format (e.g., '18:00') |
daysOfWeek | Array of day numbers: 0=Sun, 1=Mon, ..., 6=Sat |
useUserTimezone | true = evaluate in acting user's timezone (SOX recommended) |
timezone | IANA timezone fallback (e.g., 'America/New_York', 'Europe/Paris') |
For SOX compliance, set useUserTimezone: true. This ensures that "after-hours" is evaluated based on each user's local timezone:
- NY user logging in at 8pm NY time → After hours → Alert triggers
- Tokyo user logging in at 8pm Tokyo time → After hours → Alert triggers
This is more accurate than using a fixed timezone for global organizations.
List Alerts
const response = await client.audit.listAlerts();
for (const alert of response.data) {
console.log({
id: alert.id,
name: alert.name,
description: alert.description,
condition: alert.condition, // { action, threshold, window }
timeWindow: alert.timeWindow, // { mode, start, end, timezone, daysOfWeek, useUserTimezone }
notify: alert.notify, // email array
notifyWebhook: alert.notifyWebhook,
severity: alert.severity,
enabled: alert.enabled,
triggeredCount: alert.triggeredCount,
lastTriggeredAt: alert.lastTriggeredAt,
createdAt: alert.createdAt,
updatedAt: alert.updatedAt
});
}
Update Alert
await client.audit.updateAlert('alert-123', {
enabled: false, // disable the alert
condition: {
threshold: 10 // increase threshold
},
timeWindow: {
mode: 'exclude',
start: '08:00',
end: '19:00' // extend business hours
}
});
Delete Alert
await client.audit.deleteAlert('alert-123');
SOX Compliance Features
MeetLoyd provides comprehensive SOX compliance features for audit logging:
1. Tamper-Proof Hash Chain
Every audit log entry includes a cryptographic hash that chains to the previous entry, creating an immutable, verifiable audit trail.
// Each log entry contains:
{
id: "log_abc123",
hash: "a1b2c3d4...", // SHA-256 hash of this entry
previousHash: "x9y8z7...", // Hash of previous entry (blockchain-like)
sequenceNumber: 42, // Monotonic sequence for verification
// ... other fields
}
Verify Hash Chain Integrity
const result = await client.audit.verifyIntegrity();
console.log({
valid: result.valid, // true if no tampering detected
totalLogs: result.totalLogs, // number of logs verified
firstLog: result.firstLog, // timestamp of first log
lastLog: result.lastLog, // timestamp of last log
errors: result.errors, // any integrity errors found
message: result.message // human-readable summary
});
2. Immutable Logs
Configure logs to become immutable after a specified time period:
await client.retention.update({
auditLogsImmutable: true, // Enable immutability
auditLogsImmutableAfterHours: 24, // Logs become immutable after 24 hours
auditLogsHashChainEnabled: true, // Enable hash chain verification
});
3. Segregation of Duties (SoD) Alerts
Detect when the same user performs conflicting actions that should require separate individuals:
// Create SoD alert to detect self-approval
await client.audit.createSodAlert({
name: 'Self-Approval Prevention',
description: 'Alert when same user requests and approves',
conditionType: 'segregation',
segregation: {
firstAction: 'approval.request',
secondAction: 'approval.approve',
window: '24h' // Check for both actions within 24 hours
},
notify: ['compliance@company.com'],
severity: 'critical'
});
Get SoD Presets
MeetLoyd provides common SoD conflict presets:
const presets = await client.audit.getSodPresets();
// Available presets:
// - approval_self_approve: Same user requests and approves
// - agent_create_delete: Same user creates and deletes an agent
// - user_invite_remove: Same user invites and removes a team member
// - api_key_lifecycle: Same user creates and revokes an API key
// - settings_audit: Same user modifies settings and exports audit logs
4. User Timezone Tracking
Each audit log entry captures the actor's timezone for accurate time-based compliance analysis:
// Log entry includes:
{
actorId: "user_123",
actorEmail: "john@company.com",
actorTimezone: "America/New_York", // User's timezone at action time
createdAt: "2024-01-15T14:30:00Z",
// ...
}
SIEM Integration
Export logs to your security information and event management system:
Webhook Export
await client.audit.configureSiemExport({
type: 'webhook',
url: 'https://siem.company.com/ingest',
headers: {
'Authorization': 'Bearer ${secrets.SIEM_TOKEN}'
},
format: 'json', // json, cef, leef
filters: {
severity: ['warning', 'critical'],
actions: ['auth.*', '*.delete']
},
realtime: true
});
S3 Export
await client.audit.configureSiemExport({
type: 's3',
bucket: 'company-audit-logs',
prefix: 'meetloyd/',
region: 'us-east-1',
credentials: {
accessKeyId: process.env.AWS_ACCESS_KEY,
secretAccessKey: process.env.AWS_SECRET_KEY
},
format: 'json',
schedule: 'hourly'
});
Supported SIEM Platforms
| Platform | Format | Method |
|---|---|---|
| Splunk | JSON/CEF | Webhook/S3 |
| Datadog | JSON | Webhook |
| Elastic | JSON | Webhook |
| Azure Sentinel | CEF | Webhook |
| IBM QRadar | LEEF | Webhook |
Log Formats
JSON (Default)
{
"id": "log-123",
"timestamp": "2024-01-15T10:30:00.000Z",
"severity": "warning",
"action": "auth.login_failed",
"userId": "user-456",
"userName": "john@company.com",
"ipAddress": "203.0.113.50",
"userAgent": "Mozilla/5.0...",
"resourceType": "auth",
"description": "Failed login attempt",
"metadata": {
"reason": "invalid_password",
"attemptCount": 3
}
}
CEF (Common Event Format)
CEF:0|MeetLoyd|Platform|1.0|auth.login_failed|Failed login attempt|5|src=203.0.113.50 suser=john@company.com cs1=invalid_password
LEEF (Log Event Extended Format)
LEEF:2.0|MeetLoyd|Platform|1.0|auth.login_failed|src=203.0.113.50 usrName=john@company.com reason=invalid_password
Retention
Log retention varies by plan:
| Plan | Retention |
|---|---|
| Starter | 7 days |
| Pro | 30 days |
| Business | 90 days |
| Enterprise | Custom (up to 7 years) |
Configure Retention
// Enterprise only
await client.audit.setRetention({
defaultRetention: '365d',
criticalRetention: '7y', // Keep critical logs longer
archiveAfter: '90d',
archiveDestination: 's3://audit-archive/'
});
Export Logs
CSV Export
const csv = await client.audit.export({
format: 'csv',
startDate: '2024-01-01',
endDate: '2024-01-31',
columns: ['timestamp', 'action', 'userId', 'description']
});
JSON Export
const json = await client.audit.export({
format: 'json',
startDate: '2024-01-01',
endDate: '2024-01-31'
});
Best Practices
1. Regular Reviews
Schedule regular audit log reviews:
// Weekly security review
const weeklyReview = await client.audit.list({
severity: ['warning', 'critical'],
startDate: weekAgo(),
endDate: now()
});
2. Set Up Alerts
Don't just log—alert on suspicious patterns:
// Alert on bulk data access
await client.audit.createAlert({
name: 'Bulk Data Access',
condition: {
action: 'data.export',
threshold: 5,
window: '1h'
},
notify: ['security@company.com'],
severity: 'high'
});
// SOX: Alert on after-hours admin activity
await client.audit.createAlert({
name: 'After-Hours Admin Activity',
condition: {
action: 'admin.*',
threshold: 1,
window: '5m'
},
timeWindow: {
mode: 'exclude',
start: '09:00',
end: '18:00',
daysOfWeek: [1, 2, 3, 4, 5],
useUserTimezone: true // Evaluate in each user's local time
},
notify: ['security@company.com'],
severity: 'critical'
});
3. Integrate with SIEM
For enterprise, send logs to your security team:
await client.audit.configureSiemExport({
type: 'webhook',
url: 'https://siem.company.com/ingest',
realtime: true
});
4. Archive for Compliance
Keep logs for compliance requirements:
await client.audit.setRetention({
criticalRetention: '7y' // SOX, HIPAA requirements
});
Next: Explore the Store for pre-built agent templates.