> ## Documentation Index
> Fetch the complete documentation index at: https://docs.spitshake.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Audit Trails

> Query immutable, chain-hashed audit logs for document lifecycle events and security monitoring.

# Audit Trails

DocuTrust maintains an immutable audit trail for every significant action in the platform. Audit entries are protected by a PostgreSQL trigger that prevents modification or deletion, and each entry is chain-hashed with SHA-256 to form a tamper-evident log. All records are retained for 7 years.

## Audit Events

### List Audit Events

Retrieve audit events for your account, with optional filtering.

<CodeGroup>
  ```bash cURL theme={null}
  curl -X GET "https://your-app.com/api/audit_events?event_type=submission.completed&resource_type=submission&limit=25" \
    -H "X-Auth-Token: YOUR_API_TOKEN"
  ```

  ```javascript JavaScript theme={null}
  const params = new URLSearchParams({
    event_type: "submission.completed",
    resource_type: "submission",
    limit: "25"
  });
  const response = await fetch(`https://your-app.com/api/audit_events?${params}`, {
    headers: {
      "X-Auth-Token": "YOUR_API_TOKEN"
    }
  });
  const data = await response.json();
  ```
</CodeGroup>

**Query Parameters**

| Parameter       | Type    | Required | Description                                                                  |
| --------------- | ------- | -------- | ---------------------------------------------------------------------------- |
| `event_type`    | string  | No       | Filter by event type (e.g., `"submission.completed"`, `"document.viewed"`).  |
| `user`          | string  | No       | Filter by the email address of the user who performed the action.            |
| `resource_type` | string  | No       | Filter by resource type (e.g., `"submission"`, `"template"`, `"submitter"`). |
| `resource_id`   | integer | No       | Filter by the ID of a specific resource.                                     |
| `after`         | string  | No       | Cursor for pagination. Return events after this cursor value.                |
| `limit`         | integer | No       | Number of events to return per page. Default: `25`. Maximum: `100`.          |

**Response** `200 OK`

```json theme={null}
{
  "data": [
    {
      "id": 48291,
      "event_type": "submission.completed",
      "user_email": "signer@example.com",
      "resource_type": "submission",
      "resource_id": 1042,
      "metadata": {
        "template_id": 57,
        "template_name": "Employment Agreement",
        "submitter_id": 2089,
        "submitter_role": "Employee",
        "completion_method": "web",
        "ip_country": "US"
      },
      "ip_address": "203.0.113.42",
      "user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36",
      "created_at": "2026-04-08T14:23:17Z"
    },
    {
      "id": 48290,
      "event_type": "submission.created",
      "user_email": "admin@company.com",
      "resource_type": "submission",
      "resource_id": 1042,
      "metadata": {
        "template_id": 57,
        "template_name": "Employment Agreement",
        "submitters_count": 2,
        "source": "api"
      },
      "ip_address": "198.51.100.17",
      "user_agent": "curl/8.4.0",
      "created_at": "2026-04-08T09:15:03Z"
    }
  ],
  "pagination": {
    "next": "eyJpZCI6NDgyOTB9",
    "prev": null
  }
}
```

**AuditEvent Object**

| Field           | Type    | Description                                                                                         |
| --------------- | ------- | --------------------------------------------------------------------------------------------------- |
| `id`            | integer | Unique identifier for the audit event.                                                              |
| `event_type`    | string  | The type of event that occurred. See event types below.                                             |
| `user_email`    | string  | Email address of the user who triggered the event.                                                  |
| `resource_type` | string  | The type of resource affected (`"submission"`, `"template"`, `"submitter"`, `"account"`, `"user"`). |
| `resource_id`   | integer | The ID of the affected resource.                                                                    |
| `metadata`      | object  | Additional context about the event. Contents vary by event type.                                    |
| `ip_address`    | string  | The IP address from which the action was performed.                                                 |
| `user_agent`    | string  | The User-Agent header from the request that triggered the event.                                    |
| `created_at`    | string  | ISO 8601 timestamp of when the event occurred.                                                      |

### Common Audit Event Types

| Event Type             | Description                                           |
| ---------------------- | ----------------------------------------------------- |
| `template.created`     | A new template was created.                           |
| `template.updated`     | A template's schema, name, or settings were modified. |
| `template.archived`    | A template was archived.                              |
| `submission.created`   | A new submission was created from a template.         |
| `submission.sent`      | A submission was sent to submitters.                  |
| `submission.completed` | All submitters completed a submission.                |
| `submission.expired`   | A submission passed its expiration date.              |
| `submission.archived`  | A submission was archived.                            |
| `submitter.sent`       | An email was sent to a submitter.                     |
| `submitter.opened`     | A submitter opened the signing link.                  |
| `submitter.completed`  | A submitter completed their fields.                   |
| `submitter.declined`   | A submitter declined to sign.                         |
| `document.viewed`      | A document was viewed or downloaded.                  |
| `document.uploaded`    | A new document was uploaded to a template.            |
| `field.updated`        | A field value was submitted by a signer.              |
| `user.invited`         | A new user was invited to the account.                |
| `user.role_changed`    | A user's role was changed.                            |
| `settings.updated`     | Account settings were modified.                       |
| `webhook.delivered`    | A webhook was successfully delivered.                 |
| `webhook.failed`       | A webhook delivery failed.                            |

## Security Events

Security events are a specialized subset of audit events focused on authentication, access control, and threat detection. These are accessible only to account administrators.

### List Security Events

<CodeGroup>
  ```bash cURL theme={null}
  curl -X GET "https://your-app.com/api/security_events?event_type=user.login_failed&limit=50" \
    -H "X-Auth-Token: YOUR_API_TOKEN"
  ```

  ```javascript JavaScript theme={null}
  const params = new URLSearchParams({
    event_type: "user.login_failed",
    limit: "50"
  });
  const response = await fetch(`https://your-app.com/api/security_events?${params}`, {
    headers: {
      "X-Auth-Token": "YOUR_API_TOKEN"
    }
  });
  const data = await response.json();
  ```
</CodeGroup>

**Response** `200 OK`

```json theme={null}
{
  "data": [
    {
      "id": 7823,
      "event_type": "user.login_failed",
      "user_id": 142,
      "metadata": {
        "email": "admin@company.com",
        "reason": "invalid_password",
        "attempt_number": 3
      },
      "ip_address": "203.0.113.88",
      "user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36",
      "created_at": "2026-04-08T11:42:09Z"
    },
    {
      "id": 7822,
      "event_type": "user.login",
      "user_id": 85,
      "metadata": {
        "email": "operations@company.com",
        "mfa_verified": true,
        "session_id": "s_9f3a7c1e2d4b"
      },
      "ip_address": "198.51.100.22",
      "user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36",
      "created_at": "2026-04-08T11:38:51Z"
    }
  ],
  "pagination": {
    "next": "eyJpZCI6NzgyMn0",
    "prev": null
  }
}
```

**SecurityEvent Object**

| Field        | Type    | Description                                                      |
| ------------ | ------- | ---------------------------------------------------------------- |
| `id`         | integer | Unique identifier for the security event.                        |
| `event_type` | string  | The type of security event. See the full list below.             |
| `user_id`    | integer | The ID of the user associated with the event.                    |
| `metadata`   | object  | Additional context about the event. Contents vary by event type. |
| `ip_address` | string  | The IP address from which the action originated.                 |
| `user_agent` | string  | The User-Agent header from the originating request.              |
| `created_at` | string  | ISO 8601 timestamp of when the event occurred.                   |

### Security Event Types

| Event Type                      | Description                                               |
| ------------------------------- | --------------------------------------------------------- |
| `user.login`                    | Successful user login.                                    |
| `user.login_failed`             | Failed login attempt (wrong password or locked account).  |
| `user.locked`                   | Account locked after 5 consecutive failed login attempts. |
| `user.logout`                   | User logged out.                                          |
| `user.mfa_enabled`              | MFA was enabled for a user.                               |
| `user.mfa_disabled`             | MFA was disabled for a user.                              |
| `user.mfa_verified`             | Successful MFA code verification during login.            |
| `user.mfa_failed`               | Failed MFA code verification attempt.                     |
| `user.password_changed`         | User changed their password.                              |
| `user.created`                  | A new user account was created.                           |
| `user.role_changed`             | A user's role was changed (e.g., member to admin).        |
| `security.breach_detected`      | Automated breach detection flagged suspicious activity.   |
| `security.sessions_invalidated` | All sessions were invalidated for the account.            |
| `security.ip_blocked`           | A request was blocked by IP allowlist rules.              |
| `security.certificate_rotated`  | An encryption certificate or key was rotated.             |
| `api_token.created`             | A new API token was created.                              |
| `api_token.revoked`             | An API token was revoked.                                 |

### Security Events Summary

Get an aggregated summary of security events over a time period.

<CodeGroup>
  ```bash cURL theme={null}
  curl -X GET "https://your-app.com/api/security_events/summary?period=7d" \
    -H "X-Auth-Token: YOUR_API_TOKEN"
  ```

  ```javascript JavaScript theme={null}
  const response = await fetch("https://your-app.com/api/security_events/summary?period=7d", {
    headers: {
      "X-Auth-Token": "YOUR_API_TOKEN"
    }
  });
  const data = await response.json();
  ```
</CodeGroup>

**Query Parameters**

| Parameter | Type   | Required | Description                                                                               |
| --------- | ------ | -------- | ----------------------------------------------------------------------------------------- |
| `period`  | string | No       | Time period for the summary. Options: `"24h"`, `"7d"`, `"30d"`, `"90d"`. Default: `"7d"`. |

**Response** `200 OK`

```json theme={null}
{
  "period": "7d",
  "failed_logins": 12,
  "successful_logins": 347,
  "mfa_failures": 3,
  "ip_blocks": 8,
  "breach_detections": 0,
  "session_invalidations": 1,
  "account_lockouts": 2,
  "api_token_events": 5
}
```

**SecuritySummary Object**

| Field                   | Type    | Description                                                               |
| ----------------------- | ------- | ------------------------------------------------------------------------- |
| `period`                | string  | The time period covered by this summary.                                  |
| `failed_logins`         | integer | Total number of failed login attempts during the period.                  |
| `successful_logins`     | integer | Total number of successful logins during the period.                      |
| `mfa_failures`          | integer | Total number of failed MFA verification attempts.                         |
| `ip_blocks`             | integer | Total number of requests blocked by IP allowlist rules.                   |
| `breach_detections`     | integer | Number of times the breach detection service flagged suspicious activity. |
| `session_invalidations` | integer | Number of account-wide session invalidation events.                       |
| `account_lockouts`      | integer | Number of accounts locked due to failed login attempts.                   |
| `api_token_events`      | integer | Total number of API token creation and revocation events.                 |

## Chain Hashing

Every audit entry includes a SHA-256 hash that incorporates the hash of the previous entry, creating a tamper-evident chain. If any historical entry is modified, the chain breaks and the integrity violation is detectable.

```
Entry N:   hash = SHA256(entry_data + Entry[N-1].hash)
Entry N+1: hash = SHA256(entry_data + Entry[N].hash)
Entry N+2: hash = SHA256(entry_data + Entry[N+1].hash)
```

This mechanism ensures that:

* No entry can be modified after creation without detection
* No entry can be deleted without breaking the chain
* The entire audit history can be verified by recomputing hashes from the first entry

## Retention

Audit records are retained for **7 years** from the date of creation. This meets the retention requirements of:

* **HIPAA**: 6-year minimum for PHI access logs
* **SOC 2**: Retention period defined by organizational policy
* **GDPR**: Proportional retention justified by legal compliance obligations

After 7 years, records are securely purged.
