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

# Event Schema Reference: Input, Enriched & Chain Fields

> Complete reference for AuditRails event fields — what you send, what gets enriched, and how tamper-proof chain fields are computed.

Every event you log to AuditRails passes through a two-stage pipeline: your input fields are validated and stored, then AuditRails enriches the record with identity, geolocation, and tamper-proof chain data before persisting it. Understanding this schema helps you design consistent action names, use metadata effectively, and verify chain integrity in your own tooling.

## Input Fields

These are the fields you provide when you log an event. Only `action` is required — everything else is optional but strongly recommended for useful audit trails.

<ParamField body="action" type="string" required>
  The action that occurred, in `resource.verb` format. Maximum 255 characters. Must match an entry in the [compliance action catalog](#action-naming-convention) or be a registered custom action. This is the primary field used for filtering and compliance reporting.
</ParamField>

<ParamField body="actor_id" type="string">
  The internal identifier of the entity that performed the action. Maximum 255 characters. Use stable internal IDs (e.g. `user_123`, `svc_payments`) — never PII such as email addresses or full names.
</ParamField>

<ParamField body="resource" type="string">
  The object that was affected by the action, in `type/id` format (e.g. `document/doc-456`). Maximum 255 characters. Consistent formatting here makes resource-scoped queries significantly more powerful.
</ParamField>

<ParamField body="metadata" type="object">
  Arbitrary key-value pairs that provide additional context for the event. No server-side key or depth restrictions are enforced, but the overall request body must stay within **256 KB** for single-event requests or **2 MB** for batch requests. Metadata is stored as-is and returned on every read — it is never indexed or transformed by AuditRails.
</ParamField>

### Action Naming Convention

AuditRails uses a `resource.verb` convention for action names. The table below lists the built-in actions across common compliance categories. You can register additional custom actions from the dashboard.

| Category           | Actions                                                                          |
| ------------------ | -------------------------------------------------------------------------------- |
| **User lifecycle** | `user.login` · `user.logout` · `user.created` · `user.deleted`                   |
| **Documents**      | `document.created` · `document.updated` · `document.deleted` · `document.shared` |
| **API keys**       | `api_key.created` · `api_key.revoked`                                            |
| **Payments**       | `payment.processed` · `payment.refunded` · `payment.failed`                      |
| **Permissions**    | `permission.granted` · `permission.revoked`                                      |
| **System**         | `config.changed` · `deploy.completed`                                            |

<Tip>
  If you need an action that doesn't appear in the catalog, you can register a custom action from **Dashboard → Actions → New Custom Action**. Custom actions follow the same `resource.verb` naming rules and are available for compliance reports immediately after registration.
</Tip>

***

## Enriched Fields

AuditRails automatically appends enriched fields to every event before storage. You never need to supply these — and you cannot override them. They are split into two groups: fields that are **always present**, and fields that are **added when available**.

### Always Present

These fields appear on every stored event without exception.

<ResponseField name="log_id" type="string (ULID)">
  A globally unique, lexicographically sortable identifier for this event. ULIDs encode a millisecond-precision timestamp in their first 10 characters, making them ideal for cursor-based pagination.
</ResponseField>

<ResponseField name="tenant_id" type="string (UUID)">
  The UUID of the tenant that owns this event, derived from your API key at ingest time.
</ResponseField>

<ResponseField name="project_id" type="string (UUID)">
  The UUID of the project associated with the API key used to log the event.
</ResponseField>

<ResponseField name="schema_version" type="integer">
  The version of the AuditRails event schema used to store this record. Currently `1`. AuditRails will increment this value and provide a migration path for any breaking changes.
</ResponseField>

<ResponseField name="timestamp" type="string (ISO 8601 UTC)">
  The time AuditRails received and persisted the event, formatted as ISO 8601 in UTC (e.g. `2024-03-13T14:22:33.456Z`). If you need to record when the event *occurred* on the client side, include a `ts_client` field in `metadata` or as a top-level enrichment (see below).
</ResponseField>

### Added When Available

AuditRails appends these fields automatically when the data can be resolved. Their absence does not indicate an error.

| Field           | Type              | Description                                                                         |
| --------------- | ----------------- | ----------------------------------------------------------------------------------- |
| `actor_type`    | string            | Resolved type of the actor (e.g. `user`, `service_account`).                        |
| `resource_type` | string            | Resource portion of the `action` field (e.g. `document`).                           |
| `category`      | string            | Compliance category the action belongs to (e.g. `data_access`).                     |
| `severity`      | string            | Severity level assigned to this action in the catalog (`info`, `warn`, `critical`). |
| `session_id`    | string            | Session identifier, if passed by the SDK or ingest API.                             |
| `ts_client`     | string (ISO 8601) | Client-reported event time, if provided.                                            |
| `ip_address`    | string            | Originating IP address of the API request.                                          |
| `country`       | string            | Two-letter ISO 3166-1 country code resolved from the IP.                            |
| `city`          | string            | City name resolved from the IP.                                                     |

<Note>
  IP address and geolocation fields (`ip_address`, `country`, `city`) are **excluded from hash computation**. This means they can be updated by AuditRails (e.g. after a GeoIP database refresh) without invalidating your chain integrity. See [Chain Fields](#chain-fields) below.
</Note>

***

## Chain Fields

AuditRails implements a cryptographic hash chain across all events within a project. Each event is linked to the previous one, making any retroactive modification detectable. These fields are computed by AuditRails and cannot be supplied by you.

<ResponseField name="chain_seq" type="integer">
  A monotonically increasing sequence number within the project's chain. Gaps in `chain_seq` indicate a tampered or missing event.
</ResponseField>

<ResponseField name="hash" type="string">
  A SHA-256 hash of this event's canonical payload, encoded as 64 lowercase hex characters.
</ResponseField>

<ResponseField name="prev_hash" type="string">
  The `hash` of the immediately preceding event in the chain. For the very first event in a project, this is a string of 64 zero characters (`0000...0000`).
</ResponseField>

### Canonical Payload for Hash Computation

The hash is computed over a strict, deterministic subset of fields. Enrichment and chain fields themselves are excluded to allow non-breaking updates (such as GeoIP re-resolution) without invalidating the chain.

| Included in hash | Excluded from hash |
| ---------------- | ------------------ |
| `log_id`         | `chain_seq`        |
| `tenant_id`      | `hash`             |
| `action`         | `prev_hash`        |
| `actor_id`       | `ip_address`       |
| `resource`       | `country`          |
| `metadata`       | `city`             |
|                  | `actor_type`       |
|                  | `resource_type`    |
|                  | `category`         |
|                  | `severity`         |
|                  | `session_id`       |
|                  | `ts_client`        |

<Warning>
  Do not rely on the presence of any excluded field when computing your own chain verification. Always reconstruct the canonical payload from the six included fields only.
</Warning>

***

## Full Example

### Input (what you send)

```json theme={null}
{
  "action": "document.shared",
  "actor_id": "user_123",
  "resource": "document/doc-456",
  "metadata": {
    "shared_with": "team_engineering",
    "permission": "read",
    "expires_in": "7d"
  }
}
```

### Stored Event (what AuditRails persists)

```json theme={null}
{
  "log_id": "01HXA1B2C3D4E5F6G7H8J9K0",
  "tenant_id": "019cc9ce-7981-7316-bf99-1f7e43364f2f",
  "project_id": "019cc9ce-8a12-7456-bf99-2g8h54475g3g",
  "schema_version": 1,
  "action": "document.shared",
  "actor_id": "user_123",
  "resource": "document/doc-456",
  "metadata": {
    "shared_with": "team_engineering",
    "permission": "read",
    "expires_in": "7d"
  },
  "timestamp": "2024-03-13T14:22:33.456Z",
  "ip_address": "203.0.113.45",
  "country": "US",
  "city": "San Francisco",
  "chain_seq": 15421,
  "hash": "a1b2c3d4e5f6...64 hex chars",
  "prev_hash": "f6e5d4c3b2a1...64 hex chars"
}
```

<Info>
  The `log_id` returned in the ingest response is the same ULID stored in the event record. You can use it immediately to retrieve the event via `GET /v1/events/{log_id}`.
</Info>
