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

# Events and Lifecycle

> Event system, status transitions, and instance lifecycle management.

The `Deposit` class emits events during the deposit flow. Use `on()` and `off()` to subscribe and unsubscribe.

## Events

### complete

Fired when the payment completes successfully. The handler receives a `DepositResult`.

```typescript theme={null}
deposit.on('complete', (result: DepositResult) => {
  console.log('Transfer ID:', result.transfer.id);
  console.log('Status:', result.transfer.status);
});
```

### error

Fired when the deposit flow fails. The handler receives a `DepositError`.

```typescript theme={null}
deposit.on('error', (error: DepositError) => {
  console.error('Transfer failed:', error.code, error.message);
});
```

### close

Fired when the transfer iframe is dismissed (user tapped backdrop, pressed Escape, or the flow was closed programmatically).

```typescript theme={null}
deposit.on('close', () => {
  console.log('Transfer closed');
});
```

### status-change

Fired on every status transition. The handler receives the new `DepositStatus`.

```typescript theme={null}
deposit.on('status-change', (status: DepositStatus) => {
  console.log('Status:', status);
});
```

## Status transitions

```mermaid theme={null}
stateDiagram-v2
    idle --> signerLoading: requestDeposit()
    signerLoading --> iframeActive: Signer responded
    signerLoading --> errorState: Signer failed
    iframeActive --> completed: Payment complete
    iframeActive --> errorState: Flow timeout / dismissed
    completed --> signerLoading: requestDeposit()
    errorState --> signerLoading: requestDeposit()
    state "signer-loading" as signerLoading
    state "iframe-active" as iframeActive
    state "error" as errorState
```

| Status           | Meaning                                                                   |
| ---------------- | ------------------------------------------------------------------------- |
| `idle`           | No active flow. Initial state and state after `close()` or `destroy()`.   |
| `signer-loading` | The SDK is calling the merchant signer endpoint.                          |
| `iframe-active`  | The hosted flow iframe is open. Waiting for the user to complete payment. |
| `completed`      | Transfer succeeded. `result` is available.                                |
| `error`          | Something failed. `error` is available.                                   |

## Subscribing and unsubscribing

```typescript theme={null}
const onComplete = (result: DepositResult) => {
  updateUI(result);
};

// Subscribe
deposit.on('complete', onComplete);

// Unsubscribe
deposit.off('complete', onComplete);
```

Both `on()` and `off()` return `this` for chaining:

```typescript theme={null}
deposit
  .on('complete', handleComplete)
  .on('error', handleError)
  .on('close', handleClose);
```

## Lifecycle management

### close()

Closes the transfer iframe and resets status to `idle`. Fires the `close` event. Does not destroy the instance. You can call `requestDeposit()` again.

```typescript theme={null}
deposit.close();
```

### destroy()

Closes the iframe, removes all event listeners, and marks the instance as destroyed. Subsequent calls to `requestDeposit()` will reject with `INVALID_REQUEST`.

Call this when the component unmounts or the page unloads.

```typescript theme={null}
// Vanilla JS, on page unload
window.addEventListener('beforeunload', () => deposit.destroy());

// React, handled automatically by useBlinkDeposit
```

<Warning>
  Always call `destroy()` when the transfer is no longer needed to prevent memory leaks from lingering event listeners.
</Warning>

## React lifecycle

The `useBlinkDeposit` hook manages the `Deposit` instance lifecycle automatically:

* Creates the instance on first render.
* Subscribes to `status-change`, `complete`, and `error` events.
* Cleans up all subscriptions and calls `destroy()` on unmount.

You do not need to call `destroy()` manually when using the React hook.
