# How Audit Logging Tracks API Operations in OpenWA: Complete Implementation Guide

> Discover how OpenWA audit logging tracks API operations with NestJS and TypeORM. Learn to capture API keys, sessions, HTTP metadata, and errors for robust security and monitoring.

- Repository: [Yudhi Armyndharis/OpenWA](https://github.com/rmyndharis/OpenWA)
- Tags: how-to-guide
- Published: 2026-05-21

---

**OpenWA implements a comprehensive audit logging subsystem using NestJS and TypeORM to capture every significant API interaction, storing detailed context including API keys, session IDs, HTTP metadata, and error states in a searchable database table.**

The **audit logging** system in OpenWA (WhatsApp API) provides administrators with complete visibility into API usage patterns, security events, and operational troubleshooting data. Built on a three-layer architecture, this subsystem automatically records who performed what action, when, and with what result across all WhatsApp session operations.

## Architecture Overview

The audit logging implementation follows a standard NestJS modular pattern with clear separation of concerns across three distinct layers:

1. **Controller Layer** – Exposes the `GET /audit` REST endpoint for log retrieval
2. **Service Layer** – Contains `AuditService` with methods for creating, querying, and cleaning up log entries
3. **Persistence Layer** – Defines the `AuditLog` entity schema mapped to the `audit_log` database table

All components are registered in [`src/modules/audit/audit.module.ts`](https://github.com/rmyndharis/OpenWA/blob/main/src/modules/audit/audit.module.ts), which wires together the TypeORM repository, service logic, and HTTP controller.

## Core Implementation Files

### AuditService: The Central Logging Engine

Located in [`src/modules/audit/audit.service.ts`](https://github.com/rmyndharis/OpenWA/blob/main/src/modules/audit/audit.service.ts), the `AuditService` class provides the primary interface for recording API operations. The core **`log`** method accepts an action type, severity level, and a rich context object, then persists an `AuditLog` entity via TypeORM.

```typescript
// Core method signature from audit.service.ts
async log(
  action: AuditAction,
  severity: AuditSeverity,
  context: AuditContext
): Promise<AuditLog>

```

The service exposes convenience wrappers that prepend severity levels:

- **`logInfo`** – Records informational events (successful operations)
- **`logWarn`** – Captures warning states requiring attention  
- **`logError`** – Stores failed operations with error details

For retrieval, the **`findAll`** method builds dynamic SQL `where` clauses from `AuditQueryOptions`, supporting date range filtering, pagination via `limit`/`offset`, and severity-based queries. The service also provides **`cleanup`**, which removes entries older than a configurable retention period to prevent database bloat.

### AuditController: REST API for Log Access

The `AuditController` in [`src/modules/audit/audit.controller.ts`](https://github.com/rmyndharis/OpenWA/blob/main/src/modules/audit/audit.controller.ts) exposes the `GET /audit` endpoint for administrators. It translates incoming query parameters into an `AuditQueryOptions` object and returns paginated results with total counts.

```typescript
// Example request handling in audit.controller.ts
@Get()
async findAll(@Query() query: AuditQueryOptions) {
  return this.auditService.findAll(query);
}

```

Query parameters support filtering by `action`, `severity`, `apiKeyId`, `sessionId`, and date ranges, enabling precise forensic analysis of specific API operations or credential usage.

### AuditLog Entity: Database Schema Definition

The `AuditLog` entity defined in [`src/modules/audit/entities/audit-log.entity.ts`](https://github.com/rmyndharis/OpenWA/blob/main/src/modules/audit/entities/audit-log.entity.ts) maps to the `audit_log` table with the following critical columns:

- **`action`** – Enum tracking specific operations (e.g., `SEND_MESSAGE`, `CREATE_GROUP`)
- **`severity`** – Classification as `INFO`, `WARN`, or `ERROR`
- **`apiKeyId`** / **`apiKeyName`** – Identifies the credential performing the request
- **`sessionId`** / **`sessionName`** – Links the log to specific WhatsApp sessions
- **`method`**, **`path`**, **`statusCode`** – Complete HTTP request context
- **`metadata`** – JSON column for flexible additional data (message IDs, group names)
- **`errorMessage`** – Populated exclusively for failed operations
- **`createdAt`** – Automatic timestamp generated by TypeORM

## Logging API Operations in Practice

When processing requests, OpenWA services inject `AuditService` and invoke logging methods with request context. The following pattern from the source demonstrates tracking a message send operation:

```typescript
@Injectable()
export class MessageService {
  constructor(
    private readonly audit: AuditService,
    // additional dependencies...
  ) {}

  async sendMessage(payload: SendMessageDto, ctx: RequestContext) {
    try {
      // Business logic to send WhatsApp message...
      
      await this.audit.logInfo(AuditAction.SEND_MESSAGE, {
        apiKey: ctx.apiKey,
        sessionId: ctx.session.id,
        ipAddress: ctx.ip,
        method: ctx.method,
        path: ctx.path,
        statusCode: 200,
        metadata: { messageId: result.id },
      });
    } catch (err) {
      await this.audit.logError(AuditAction.SEND_MESSAGE, {
        apiKey: ctx.apiKey,
        sessionId: ctx.session.id,
        ipAddress: ctx.ip,
        method: ctx.method,
        path: ctx.path,
        statusCode: 500,
        errorMessage: err.message,
      });
      throw err;
    }
  }
}

```

This implementation ensures both successful operations and failures are captured with identical context, enabling complete audit trails for compliance and debugging.

## Querying and Managing Audit Logs

Administrators retrieve logs via standardized HTTP requests:

```http
GET /audit?action=SEND_MESSAGE&severity=INFO&limit=20&offset=0

```

The response returns a paginated JSON structure:

```json
{
  "data": [
    {
      "id": "c1a2b3d4-e5f6-7890-abcd-1234567890ef",
      "action": "SEND_MESSAGE",
      "severity": "INFO",
      "apiKeyId": "key-123",
      "apiKeyName": "Production API Key",
      "sessionId": "session-abc",
      "ipAddress": "203.0.113.42",
      "method": "POST",
      "path": "/messages",
      "statusCode": 200,
      "metadata": { "messageId": "msg-987" },
      "createdAt": "2026-05-21T14:33:12.000Z"
    }
  ],
  "total": 42
}

```

For maintenance, the **`cleanup`** method in `AuditService` executes scheduled deletions based on configurable retention days, ensuring the `audit_log` table remains performant as volume scales.

## Summary

- **Three-layer architecture**: Controller (`GET /audit`), Service (`AuditService`), and Entity (`AuditLog`) work together in `src/modules/audit/`
- **Comprehensive context capture**: Every log stores API key, session, IP, HTTP method/path, status code, and optional metadata
- **Severity-based logging**: Use `logInfo`, `logWarn`, or `logError` to classify events automatically
- **Queryable storage**: Filter by action type, date ranges, or credentials via `AuditQueryOptions`
- **Automatic maintenance**: Built-in `cleanup` functionality prevents unlimited database growth

## Frequently Asked Questions

### What information does OpenWA store in each audit log entry?

Each entry in the `audit_log` table captures the **action** performed (enum), **severity** level (INFO/WARN/ERROR), the **API key** and **session** identifiers, source **IP address**, HTTP **method** and **path**, response **statusCode**, optional JSON **metadata**, and **errorMessage** for failures. The `createdAt` timestamp is automatically generated by TypeORM when the record persists.

### How do I query audit logs via the API?

Send a `GET` request to the `/audit` endpoint with query parameters matching `AuditQueryOptions`. Supported filters include `action`, `severity`, `apiKeyId`, `sessionId`, and date ranges. The controller returns a paginated response containing both the dataset array and total count, enabling frontend pagination implementations.

### Can I configure automatic cleanup of old audit logs?

Yes. The `AuditService` includes a **`cleanup`** method that removes entries older than a configurable number of days. This housekeeping function prevents the `audit_log` table from growing indefinitely and can be invoked via scheduled tasks or administrative triggers according to your retention policy requirements.

### Which API operations trigger audit logging in OpenWA?

Any service can trigger audit logging by injecting `AuditService` and calling `log`, `logInfo`, `logWarn`, or `logError`. Common tracked operations include `SEND_MESSAGE`, session creation, group management, and webhook processing. The system uses the `AuditAction` enum to standardize operation names across the codebase.