# Audit Trail

> Track every action on a document with a tamper-proof audit trail

Source: https://docs.korala.ai/guides/audit-trail

---

Each Korala document carries a complete audit trail that records each action from creation through completion. The trail is immutable; no one can modify or delete an event.

## Event Types

| Event | Description |
|-------|-------------|
| `document_created` | Document was uploaded and created |
| `document_sent` | Document was sent for signing |
| `document_viewed` | A signer opened the document |
| `field_filled` | A signer filled in a field value |
| `field_locked` | The sender fixed a field value for a signer through a signing packet; the signer reviews it but cannot change it |
| `signature_applied` | A signature image was applied to a field |
| `document_signed` | A signer completed all their fields |
| `document_completed` | All signers finished and Korala applied the cryptographic seal |
| `document_failed` | Document completion failed after retries |
| `document_voided` | Document was cancelled before completion |
| `document_declined` | A signer declined to sign |
| `reminder_sent` | A signing reminder was sent to a signer |
| `access_revoked` | A signer's access was revoked |

## Retrieving the Audit Trail

    ```typescript
    import { KoralaClient } from '@korala/api-client';

    const korala = new KoralaClient({
      apiKeyId: 'your-api-key-id',
      apiSecret: 'your-api-secret',
    });

    const events = await korala.documents.getAuditTrail(documentId);

    for (const event of events) {
      console.log(`${event.createdAt}: ${event.eventType}`);
      if (event.ipAddress) {
        console.log(`  IP: ${event.ipAddress}`);
      }
      if (event.signerId) {
        console.log(`  Signer: ${event.signerId}`);
      }
    }
    ```
    ```bash
    api_request "GET" "/api/v1/documents/${DOCUMENT_ID}/audit-trail"
    ```

## Event Details

Each audit event includes:

| Field | Type | Description |
|-------|------|-------------|
| `id` | string | Unique event identifier |
| `documentId` | string | The document this event belongs to |
| `signerId` | string \| null | The signer who triggered the event (if applicable) |
| `eventType` | string | One of the event types listed above |
| `ipAddress` | string \| null | IP address of the actor |
| `claimedIpAddress` | string \| null | Partner-asserted end-user IP (from `X-Client-IP` header) |
| `userAgent` | string \| null | Browser or client user agent |
| `metadata` | object \| null | Additional context (e.g., field ID for `field_filled`) |
| `createdAt` | string | ISO 8601 timestamp |

## Response Format

```json
[
  {
    "id": "evt_abc123",
    "documentId": "doc_xyz789",
    "signerId": null,
    "eventType": "document_created",
    "ipAddress": "203.0.113.1",
    "claimedIpAddress": null,
    "userAgent": "KoralaClient/1.0",
    "metadata": null,
    "createdAt": "2024-01-14T09:00:00Z"
  },
  {
    "id": "evt_def456",
    "documentId": "doc_xyz789",
    "signerId": "sgn_abc123",
    "eventType": "document_signed",
    "ipAddress": "198.51.100.42",
    "claimedIpAddress": "192.0.2.10",
    "userAgent": "Mozilla/5.0...",
    "metadata": { "bulkSign": false },
    "createdAt": "2024-01-15T10:30:00Z"
  }
]
```

## Certificate of Completion

When a document completes, Korala generates a **Certificate of Completion** PDF that summarizes the entire audit trail. This certificate includes:

- Document name and ID
- All signers with their signing timestamps
- IP addresses and user agents for each action
- Cryptographic signature verification details

The certificate is available as `certificateFileUrl` on the completed document:

    ```typescript
    const document = await korala.documents.get(documentId);

    if (document.status === 'completed' && document.certificateFileUrl) {
      // Download the Certificate of Completion
      const certificate = await fetch(document.certificateFileUrl);
      fs.writeFileSync('certificate.pdf', await certificate.buffer());
    }
    ```

## Signing packet evidence

A signing packet adds shared authorization evidence without replacing the
document audit trail. Each signed document keeps its certificate and records
the packet ID, packet item ID, packet action ID, and manifest hash in its audit
metadata. You can verify one document without retrieving the other packet
items.

The packet Certificate of Completion records the cross-document context:

- Frozen document manifest and source hashes
- Recipient consent and confirmation text
- Authentication method, IP address, user agent, and timestamps
- Result for each selected item

Retrieve packet events and the certificate URL through the authenticated management
API:

```typescript
const audit = await korala.signingPackets.audit(packetId);

for (const event of audit.events) {
  console.log(`${event.createdAt}: ${event.eventType}`);
}

if (audit.certificateUrl) {
  const certificate = await fetch(audit.certificateUrl);
  // Store or inspect the packet Certificate of Completion.
}
```

`certificateUrl` remains `null` until the packet worker finishes the action and
generates the certificate.

## IP Address Tracking

Korala captures two IP address fields per event:

- **`ipAddress`**: The IP address Korala's servers observe (the direct connection)
- **`claimedIpAddress`**: The end-user's IP address your application asserts via the `X-Client-IP` request header

If you call the API on behalf of end users (e.g., through a backend proxy), pass the `X-Client-IP` header so the audit trail reflects the end user's IP rather than your server's.

## Using Audit Trails for Compliance

Audit trails are essential for legal compliance in electronic signatures. They provide evidence of:

- **Intent to sign**: The signer viewed the document and filled fields
- **Identity**: IP address, user agent, and timing establish who signed
- **Integrity**: The cryptographic seal and RFC 3161 timestamp prove no one has modified the document since signing
- **Non-repudiation**: The complete event history makes it difficult for a signer to deny their participation
