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

# Opal Events

export const ParamList = ({items = [], is_child = false}) => {
  return items.map(item => {
    const field_props = {
      id: Math.random().toString(),
      body: item.name,
      name: item.name,
      type: item.type,
      required: item.required
    };
    const enums = item.enums || [];
    const items = item.items || [];
    const has_items = items?.length > 0;
    const has_enums = enums?.length > 0;
    const should_default_open = item.defaultOpen || false;
    const render_child_item = () => {
      const child_props = {
        title: has_enums ? "Possible enum values" : "properties"
      };
      if (should_default_open) child_props.defaultOpen = true;
      const has_inline_enums = has_enums && enums.every(enum_item => typeof enum_item === 'string') && enums.map((enum_item, idx) => {
        const is_last = idx === enums.length - 1;
        const is_2nd_to_last = idx === enums.length - 2;
        return <>
            <code>{enum_item}</code>
            {is_last && ''}
            {is_2nd_to_last && ' or '}
            {!is_last && !is_2nd_to_last && ', '}
          </>;
      });
      const enum_list = has_enums && !has_inline_enums && <Accordion {...child_props}>
          {enums.map((enum_item, index) => <div key={`enum-${index}`}>
              <code>{enum_item.name}</code>
              <br />
              <p>{enum_item.description}</p>
            </div>)}
        </Accordion>;
      const item_list = has_items && <Expandable {...child_props}>
          <ParamList items={items || []} is_child />
        </Expandable>;
      return <>
          <p>
            {item.description}
            {has_inline_enums && [has_inline_enums.length > 1 ? ' One of ' : ' Must be ', ...has_inline_enums]}
          </p>

          {enum_list}
          {item_list}
        </>;
    };
    return is_child ? <ResponseField {...field_props}>{render_child_item()}</ResponseField> : <ParamField {...field_props}>{render_child_item()}</ParamField>;
  });
};

Communication between Opal and your app is handled through a consistent, mode-aware event system. Events are emitted throughout the user session to indicate progress, completion, errors, and important milestones.

## Listening to Events

We strongly recommend using one of the Opal SDKs to receive typed events and lifecycle callbacks. The SDKs provide `onEvent`, `onOpen`, and `onExit` handlers and expose a small enum of well-known events under `OpalEventType` for convenience (e.g., `SESSION_STARTED`, `SESSION_COMPLETED`).

Each Opal mode (`identity_verification`, `connect`, `card_connect`, `account_verification`, `transactions`, `balance_transfer`) emits a set of mode‑specific events in addition to default session events. See below for structure, a complete list, and examples.

## Event Structure

All Opal events follow a consistent structure:

```json theme={null}
{
  "type": "opal.session.started",
  "mode": "opal",
  "object": "session",
  "action": "started",
  "timestamp": "2025-06-10T22:50:53.024Z",
  "data": null
}
```

### Event fields

| Field | Type | Description |
| - | - | - |
| `type` | string | Fully qualified event name: `<flow>.<object>.<action>` or `opal.session.<action>` for default session events. |
| `mode` | string | The active operational mode (e.g., `connect`, `identity_verification`, `account_verification`, `transactions`). |
| `object` | string | The related object (e.g., `session`, `flow`, `step`, `identity`, `card`, `accounts`). |
| `action` | string | The action that occurred (e.g., `started`, `completed`, `verified`, `errored`). |
| `timestamp` | string | ISO 8601 timestamp of when the event occurred. |
| `data` | object \| null | Additional context that varies by event type; may be `null` for lifecycle events. |

### Possible flows:

* `identity_verification`
* `connect`
* `account_verification`
* `transactions`
* `balance_transfer`

## Sample Events

### opal.session.started

```json theme={null}
{
  "type": "opal.session.started",
  "mode": "connect",
  "object": "session",
  "action": "started",
  "timestamp": "2025-06-10T22:50:53.024Z",
  "data": null
}
```

### opal.session.errored

```json theme={null}
{
  "type": "opal.session.errored",
  "mode": "connect",
  "object": "session",
  "action": "errored",
  "timestamp": "2025-06-10T22:50:53.024Z",
  "data": {
    "type": "INVALID_REQUEST",
    "sub_type": "INVALID_SMS_CODE",
    "message": "Invalid request please try again"
  }
}
```

### connect.flow\.completed

```json theme={null}
{
  "type": "connect.flow.completed",
  "mode": "connect",
  "object": "flow",
  "action": "completed",
  "timestamp": "2025-06-10T22:50:53.024Z",
  "data": {
    "accounts": ["acc_ge9hxMTPGdXmQ"],
    "entity_id": "ent_wrDBN43PR8LKC"
  }
}
```

## Event Categories

### Default session events (always available)

* `opal.session.started` - Opal UI opened and session began
* `opal.session.completed` - User completed the flow successfully
* `opal.session.errored` - A recoverable or terminal error occurred
* `opal.session.exited` - User exited or dismissed Opal

### Generic flow and step events

Emitted in addition to the default session events. These mirror the active mode‑specific events but are prefixed with `opal` and can be emitted for any mode.

#### Flow

* `opal.flow.started` - A sub‑flow of Opal started (e.g., identity verification, account selection, verification).
* `opal.flow.completed` - A sub‑flow of Opal completed. This does not always signify the end of the session; use `opal.session.completed` to detect when Opal is fully completed.

#### Step

* `opal.step.started` - A new step started (e.g., phone input, card selection, CVV input).
* `opal.step.completed` - A step completed and the next page is opening.

Notes:

* Additional mode-specific events may be introduced over time. Your handler should use the `OpalEventType` enum to handle the specific cases you need.

## All Event Types

The following table lists all currently supported event types with their `OpalEventType` mapping, and when they are typically emitted.

| Event (OpalEventType - type) | When you might see it |
| - | - |
| `SESSION_STARTED` - `opal.session.started` | Opal UI opened and session began. |
| `SESSION_COMPLETED` - `opal.session.completed` | User completed the overall Opal flow successfully. |
| `SESSION_ERRORED` - `opal.session.errored` | A recoverable or terminal error occurred. |
| `SESSION_EXITED` - `opal.session.exited` | User closed or dismissed Opal before completion. |
| `FLOW_STARTED` - `opal.flow.started` | A sub-flow (for any mode) started. |
| `FLOW_COMPLETED` - `opal.flow.completed` | A sub-flow (for any mode) completed. |
| `STEP_STARTED` - `opal.step.started` | A step (screen) started. |
| `STEP_COMPLETED` - `opal.step.completed` | A step (screen) completed. |
| `IDV_FLOW_STARTED` - `identity_verification.flow.started` | Identity Verification flow started. |
| `IDV_STEP_STARTED` - `identity_verification.step.started` | A step in Identity Verification started. |
| `IDV_STEP_COMPLETED` - `identity_verification.step.completed` | A step in Identity Verification completed. |
| `IDV_FLOW_COMPLETED` - `identity_verification.flow.completed` | Identity Verification flow completed. |
| `IDV_VERIFICATION_COMPLETED` - `identity_verification.identity.completed` | Identity successfully verified (KYC passed). |
| `CXN_FLOW_STARTED` - `connect.flow.started` | Connect flow started. |
| `CXN_STEP_STARTED` - `connect.step.started` | A step in Connect started. |
| `CXN_STEP_COMPLETED` - `connect.step.completed` | A step in Connect completed. |
| `CXN_FLOW_COMPLETED` - `connect.flow.completed` | Connect flow completed. |
| `CXN_ACCOUNTS_SELECTED` - `connect.accounts.selected` | User selected one or more accounts to connect. |
| `AVF_FLOW_STARTED` - `account_verification.flow.started` | Account Verification flow started. |
| `AVF_STEP_STARTED` - `account_verification.step.started` | A step in Account Verification started. |
| `AVF_STEP_COMPLETED` - `account_verification.step.completed` | A step in Account Verification completed. |
| `AVF_FLOW_COMPLETED` - `account_verification.flow.completed` | Account Verification flow completed. |
| `AVF_CARD_VERIFIED` - `account_verification.card.verified` | Card verified successfully. |
| `TXN_FLOW_STARTED` - `transactions.flow.started` | Transactions flow started. |
| `TXN_STEP_STARTED` - `transactions.step.started` | A step in Transactions started. |
| `TXN_STEP_COMPLETED` - `transactions.step.completed` | A step in Transactions completed. |
| `TXN_FLOW_COMPLETED` - `transactions.flow.completed` | Transactions flow completed. |
| `TXN_ACCOUNTS_LINKED` - `transactions.accounts.linked` | Accounts linked and subscribed for transactions. |

### Balance Transfer events

The `OpalEventType` enum does not include constants for Balance Transfer events. Match these events on `event.type`.

| Event type | When you might see it |
| - | - |
| `balance_transfer.flow.started` | Balance Transfer amount allocation started. |
| `balance_transfer.step.started` | A step in Balance Transfer started. |
| `balance_transfer.step.completed` | A step in Balance Transfer completed. |
| `balance_transfer.amounts.confirmed` | User confirmed their allocations and closed the confirmation screen. |
| `balance_transfer.flow.completed` | Balance Transfer flow completed. |

See [Balance Transfer](/opal/balance_transfer/overview#events) for the payload of each event.

### Data Payloads

The following events always include a non-null `event.data` payload:

* `identity_verification.identity.completed`
* `connect.accounts.selected`
* `account_verification.card.verified`
* `transactions.accounts.linked`
* `balance_transfer.amounts.confirmed`

Use these payloads to retrieve context such as selected accounts, verification results, or linkage details.

## Enhanced Event Handling

### Using the JavaScript SDK

```javascript theme={null}
import { OpalEventType } from '@methodfi/opal-react';

const config = {
  onEvent: (event) => {
    console.log("Event received:", event.type);

    // Handle specific events using the OpalEventType enum
    switch (event.type) {
      case OpalEventType.SESSION_STARTED:
        // Session lifecycle
        break;
      case OpalEventType.SESSION_COMPLETED:
        // Entire Opal session completed successfully
        break;
      case OpalEventType.SESSION_ERRORED:
        // Handle recoverable or terminal error
        console.error("Opal error:", event.data);
        break;
      case OpalEventType.IDV_VERIFICATION_COMPLETED:
        // Identity verification completed; payload contains verification details
        handleIdentityVerified(event.data);
        break;
      case OpalEventType.CXN_ACCOUNTS_SELECTED:
        // User selected accounts in Connect
        handleAccountsSelected(event.data);
        break;
      case OpalEventType.AVF_CARD_VERIFIED:
        // Card verified in Account Verification
        handleCardVerified(event.data);
        break;
      case OpalEventType.TXN_ACCOUNTS_LINKED:
        // Accounts linked for Transactions
        handleAccountsLinked(event.data);
        break;
      default:
        // Optionally handle generic flow/step events
        break;
    }
  },

  // Specific event handlers
  onSuccess: (payload) => {
    // Called for successful completion events
    console.log("Success:", payload);
  },

  onError: (error) => {
    // Enhanced error handling with detailed information
    console.error("Error:", error.code, error.message);
    console.error("Details:", error.details);
  },
};

const opal = new MethodOpal(config);
```

## PostMessage Communication

For applications not using the Opal SDKs, you can listen to events via PostMessage:

### Setup PostMessage Listener

```javascript theme={null}
window.addEventListener("message", function (event) {
  // Verify origin for security
  if (event.origin !== "https://opal.production.methodfi.com") {
    return;
  }

  const opalEvent = event.data;
  console.log("Opal event:", opalEvent.type, opalEvent.data);

  // Handle events
  switch (opalEvent.type) {
    case OpalEventType.SESSION_STARTED:
      console.log("Opal started");
      break;
    case OpalEventType.SESSION_COMPLETED:
      console.log("Opal completed:", opalEvent.data);
      break;
  }
});
```

## Best Practices

### Event Handling

* Always verify event origins for security
* Use event filtering to reduce noise
* Implement proper error handling for all events
* Log events for debugging and analytics

### Security

* Validate all event data before processing
* Never trust client-side events for critical business logic


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.