# Event Context

The `context` object is part of the webhook payload that provides information about _who triggered the event_ and _what changed_ in the resource. It enables precise actor identification and granular change detection without additional API calls.

## Beta Status

This feature is currently in beta. The structure, behavior, and properties may evolve based on developer feedback until it reaches a stable release.

## What Context Provides

The `context` object includes two key components:

1. **`context.actor`** - Identifies who triggered the event with precise role information
2. **`context.previousState`** - Provides the previous values of fields that changed

Capabilities:

-   Identify which specific signer signed a document in a `Signed` event
-   Determine exactly what changed in an `Edited` event
-   Know who viewed a document in a `Viewed` event
-   Identify to which signer a reminder was sent in a `Reminder` event
-   Update only affected resources (e.g., specific signer's status)
-   Track field-level changes for auditing
-   Send targeted notifications to relevant parties

## Availability and Restrictions

### Supported Event Types

The context object is available for all **Document** and **Template** webhook events, except the following failure events (these currently do not include `context`):

-   `SendFailed`
-   `EditFailed`
-   `TemplateCreateFailed`
-   `TemplateSendFailed`

Context for **Sender Identity** and **Identity Verification** events is planned for future releases.

### Critical Date Restriction

> **Important**: The context object is only populated for documents and templates created **on or after January 08, 2026**.

-   Documents/templates created before this date will have `context` set to `null`
-   This limitation is permanent, even if older resources are updated after January 08, 2026
-   Your webhook handler must handle both scenarios: with context (new resources) and without context (older resources)

## Context Object Structure

The `context` object is a top-level property in the webhook payload:

```json
{
    "event": {
        "id": "event-uuid",
        "eventType": "Signed",
        "created": 1234567890,
        "environment": "Live"
    },
    "context": {
        "eventType": "Signed",
        "actor": {
            "userType": "Signer",
            "id": "signer-1"
        },
        "previousState": {
            "signerDetails": [
                {
                    "id": "signer-1",
                    "status": "NotCompleted"
                }
            ]
        }
    },
    "data": {
        // Current state
    }
}
```

### Properties

| Property        | Type           | Description                        |
| --------------- | -------------- | ---------------------------------- |
| `eventType`     | string enum    | The webhook event type             |
| `actor`         | object         | Identifies who triggered the event |
| `previousState` | object or null | Previous values of changed fields  |

## Using the Context Object

1. Route by event type using `event.eventType` or `context.eventType`
2. Identify the actor using `context.actor`
3. Detect changes using `context.previousState`
4. Compare states by examining `previousState` against current `data` values

`previousState` contains only changed fields with their previous values (diff-based approach).

## Event Type

The `eventType` property identifies the webhook event type.

-   **Type**: String enum
-   **Values**: `Sent`, `Signed`, `Completed`, etc.
-   **Behavior**: Mirrors `event.eventType`

## Actor

The `actor` object identifies who performed the action.

```json
{
    "actor": {
        "userType": "Signer",
        "id": "signer-1"
    }
}
```

### actor.userType

Indicates the type of actor. The exact values are:

-   `Sender` - Document/template sender
-   `Signer` - Document signer
-   `Cc` - CC recipient
-   `Creator` - Template creator
-   `Admin` - Account or team administrator
-   `SenderIdentity` - The sender identity user (for document/template created on behalf of a sender identity)

### actor.id

The meaning of `id` depends on `userType`:

| userType         | Represents                                 | Usage                               |
| ---------------- | ------------------------------------------ | ----------------------------------- |
| `Sender`         | BoldSign user ID                           | Sender identifier for audit logging |
| `Admin`          | BoldSign user ID                           | Admin who performed the action      |
| `Creator`        | BoldSign user ID                           | Creator when different from sender  |
| `Signer`         | Document: Signer ID (`signerDetails[].id`) | Match with document signers         |
| `Cc`             | CC ID (`ccDetails[].id`)                   | Match with document CC recipients   |
| `SenderIdentity` | Sender identity ID                         | Correlate with `behalfOf.id`        |

**Important notes**:

-   Treat `actor.id` as an opaque string identifier
-   Always use `actor.id` with `actor.userType`
-   `context.actor` can be `null` for system-triggered events (for example, `Completed`, automatic reminders, and other scheduled/automated actions)
-   For `Signer`/`Cc` types, the ID is the entity ID, not the email address
-   For view events, rely on `context.actor` rather than inferring from document state
-   For reminder events, `context.actor` identifies who triggered the reminder (e.g., `Sender`/`Admin`). To identify which signers were reminded, use `context.previousState.signerDetails[]` and compare it with `data.signerDetails[]`.

### Admin Actions

When an admin performs an action:

-   `actor.userType` is set to `Admin`
-   `actor.id` contains the admin's BoldSign user ID

Common admin actions include revoking documents, editing document settings, and viewing the document.

## Previous State

The `previousState` object provides previous values of properties modified by the event.

-   **Type**: Object (dynamic) or null
-   **Behavior**: Contains only changed fields
-   **Values**: Represent the state before the event

### What to Expect

-   **Scalar changes** (e.g., document status): `previousState` includes only changed keys
-   **Nested object changes**: `previousState` includes only changed subfields
-   **Collection changes** (e.g., `signerDetails`): Array of diff objects with an identifier plus changed fields (document signer diffs use `signerDetails[].id`, template role diffs use `signerDetails[].roleIndex`)
-   **Add-only changes**: May have no `previousState` entries (no previous value)
-   **Date/time fields**: Serialized as Unix timestamps (seconds)

### When previousState is null or empty

-   `previousState` is `null` when diff processing is not performed
-   `previousState` can be an empty object (`{}`) when no previous values are emitted (e.g., add-only changes, or when the differ detects no changes)

## Examples

### Document: Signed Event

```json
{
    "event": {
        "eventType": "Signed"
    },
    "context": {
        "eventType": "Signed",
        "actor": { "userType": "Signer", "id": "signer-1" },
        "previousState": {
            "signerDetails": [{ "id": "signer-1", "status": "NotCompleted" }]
        }
    },
    "data": {
        "object": "document",
        "documentId": "doc-id",
        "signerDetails": [{ "id": "signer-1", "status": "Completed" }]
    }
}
```

Interpretation:

-   `context.actor` identifies which signer acted (`signer-1`)
-   `previousState.signerDetails[0]` shows the previous status (`NotCompleted`)
-   Current status is in `data.signerDetails[]` (`Completed`)

Usage: Find the signer in `data.signerDetails` where `id == context.actor.id` and this is the signer who signed the document.

### Document: Viewed Event

```json
{
    "context": {
        "eventType": "Viewed",
        "actor": { "userType": "Cc", "id": "cc-123" },
        "previousState": null
    },
    "data": {
        "object": "document",
        "ccDetails": [{ "id": "cc-123", "emailAddress": "cc@example.com" }]
    }
}
```

Usage: Match `context.actor.id` with `data.ccDetails[].id` to identify which CC recipient viewed the document.

### Document: Reminder Event

```json
{
    "context": {
        "eventType": "Reminder",
        "actor": { "userType": "Sender", "id": "user-123" },
        "previousState": {
            "signerDetails": [
                { "id": "signer-1", "lastReminderSentOn": null },
                { "id": "signer-2", "lastReminderSentOn": null }
            ]
        }
    },
    "data": {
        "object": "document",
        "signerDetails": [
            { "id": "signer-1", "status": "NotCompleted", "lastReminderSentOn": 1735689600 },
            { "id": "signer-2", "status": "NotCompleted", "lastReminderSentOn": 1735689600 },
            { "id": "signer-3", "status": "NotCompleted", "lastReminderSentOn": null }
        ]
    }
}
```

Interpretation:

-   `context.actor` identifies who triggered the reminder action (typically `Sender` or `Admin`)
-   Multiple signers may be reminded in a single event
-   `context.previousState.signerDetails[]` contains the signers affected by this reminder action, with their previous `lastReminderSentOn` values
-   Use the IDs in `previousState.signerDetails[]` to find the corresponding signers in `data.signerDetails[]` and process only those signers

Usage: For each entry in `context.previousState.signerDetails`, match the signer in `data.signerDetails` where `id == previousSigner.id` to identify and process only the signers who were reminded.

### Template: Edited Event

```json
{
    "context": {
        "eventType": "TemplateEdited",
        "actor": { "userType": "Creator", "id": "actor-id" },
        "previousState": {
            "templateName": "Old Name"
        }
    },
    "data": {
        "object": "template",
        "templateName": "New Name"
    }
}
```

### Sender Identity: On Behalf Of

When `context.actor.userType` is `SenderIdentity`, the `actor.id` is the **sender identity ID**.
You can correlate this with `behalfOf.id` in the document/template payload (when present).

```json
{
    "context": {
        "eventType": "Sent",
        "actor": { "userType": "SenderIdentity", "id": "sender-identity-id" }
    },
    "data": {
        "object": "document",
        "onBehalfOf": "sender.identity@example.com",
        "behalfOf": { "id": "sender-identity-id", "email": "sender.identity@example.com" }
    }
}
```

## Frequently Asked Questions

### Is context guaranteed to be present?

No. The `context` object is only populated for documents and templates created on or after January 08, 2026, and it is currently not included for these failure events: `SendFailed`, `TemplateCreateFailed`, `TemplateSendFailed`, `EditFailed`. Always check for context availability.

### Why is previousState sometimes null?

`previousState` is `null` when diff processing is not performed. Your handler should handle `null`, `{}` (empty object), and objects with previous values.

### Why don't added items appear in previousState?

Newly added items have no previous values. Use `previousState` to detect updates/removals; compare with stored state to detect additions.

### Are timestamps ISO strings?

No. Date/time values are typically Unix timestamps (seconds). Convert them appropriately.

### How do I map actor.id correctly?

Use `actor.userType` first:

-   `Signer`/`Cc` - Document: match with `data.signerDetails[].id` / `data.ccDetails[].id`
-   `SenderIdentity` - Match with `data.behalfOf.id`
-   `Sender`/`Admin`/`Creator` - BoldSign user IDs

### Who is the actor for view events?

The actor can be any participant type. Always use `context.actor` rather than inferring.

### How do I identify to which signer a reminder was sent?

For `Reminder` events, `context.actor` identifies who triggered the reminder (typically `Sender`/`Admin`), not the recipients.

To identify which signers were reminded, use `context.previousState.signerDetails[]` and match by `id` to `data.signerDetails[]`. Each entry in `previousState.signerDetails[]` corresponds to a signer whose reminder-related fields changed (for example, `lastReminderSentOn`).
