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

# Deposit / Redeem Lifecycle

> Event sequence, confirmation depth, and how to reconcile your UI with on-chain state.

The Headless API mode lets your UI call BarkerEngine directly with the user's wallet. After the user signs a deposit or redeem transaction, your frontend sees the tx hash immediately — but the position is not "real" until the on-chain log is confirmed and we've notified you.

This page documents the event sequence so you can show "pending" / "confirmed" states correctly without hammering `/position`.

## Why lifecycle webhooks (vs polling `/position`)

The `/position` endpoint reads `balanceOf` + `convertToAssets` directly from the chain — accurate but expensive to poll, and it doesn't tell you **which** transaction caused the change. Lifecycle webhooks give you:

* A push signal the moment a deposit or redeem hits confirmation depth (no polling)
* The originating `tx_hash` so you can join with your own pending-tx table
* The exact `shares` / `amount` so you can update your DB without a follow-up RPC call

Use lifecycle webhooks for state transitions, use `/position` for total balance display.

## Sync vault sequence

Most BarkerEngine products wrap a synchronous ERC-4626 vault — `deposit()` returns shares atomically, `redeem()` returns assets atomically.

### Deposit

```mermaid theme={null}
sequenceDiagram
    participant User
    participant PartnerUI
    participant Engine as BarkerEngine
    participant Barker as Barker Backend
    participant Endpoint as Your Webhook

    User->>PartnerUI: Click "Deposit $1000"
    PartnerUI->>Engine: approve(USDC, 1000)
    PartnerUI->>Engine: deposit(1000, user)
    Engine-->>PartnerUI: tx hash
    Note over PartnerUI: Show "Pending" with tx hash
    Engine->>Engine: Mint shares, emit Deposit log
    Note over Barker: Watcher sees log,<br/>waits for confirmation depth
    Barker->>Endpoint: POST deposit.confirmed
    Endpoint-->>Barker: 200 OK
    Note over PartnerUI: Update UI to "Confirmed"<br/>(via your own state push)
```

Events fired:

1. **`deposit.confirmed`** — fires once, after the `Deposit(sender, owner, assets, shares)` log reaches confirmation depth.

### Redeem

```mermaid theme={null}
sequenceDiagram
    participant User
    participant PartnerUI
    participant Engine as BarkerEngine
    participant Barker as Barker Backend
    participant Endpoint as Your Webhook

    User->>PartnerUI: Click "Withdraw all"
    PartnerUI->>Engine: redeem(shares, user, user)
    Engine-->>PartnerUI: tx hash
    Engine->>Engine: Burn shares, transfer asset, emit Withdraw log
    Note over Barker: Watcher sees log,<br/>waits for confirmation depth
    Barker->>Endpoint: POST redeem.confirmed
```

Events fired:

1. **`redeem.confirmed`** — fires once, after the `Withdraw(sender, receiver, owner, assets, shares)` log reaches confirmation depth.

## Async vault sequence

Some underlying vaults (e.g. liquid-staking with unbond periods, certain Morpho strategies) cannot redeem atomically — the user submits a request, settlement happens later. BarkerEngine wraps this with two events.

```mermaid theme={null}
sequenceDiagram
    participant User
    participant PartnerUI
    participant Engine as BarkerEngine
    participant Barker as Barker Backend
    participant Endpoint as Your Webhook

    User->>PartnerUI: Click "Withdraw"
    PartnerUI->>Engine: requestRedeem(shares, user)
    Engine->>Engine: Lock shares, emit RedeemRequested(request_id)
    Note over Barker,Endpoint: Watcher waits for depth, fires
    Barker->>Endpoint: POST redeem.requested<br/>{request_id, estimated_settlement_at}
    Note over PartnerUI: Show "Pending settlement<br/>~6h" using estimated_settlement_at
    Note over Engine: ...time passes (hours / days)...
    Engine->>Engine: Underlying settles, emit Withdraw log
    Barker->>Endpoint: POST redeem.confirmed<br/>{tx_hash of settlement, shares, amount}
```

Events fired:

1. **`redeem.requested`** — fires after `RedeemRequested(request_id, owner, shares)` log. Includes `estimated_settlement_at` (computed from the underlying vault's unbond period).
2. **`redeem.confirmed`** — fires when the settlement `Withdraw` log appears. The `tx_hash` here is the **settlement** tx, not the request tx.

You can correlate the two via the `user_address` + `shares` (or query `/position` to confirm).

A product is sync vs async based on the underlying vault — check the `redeem_mode` field on the [product detail endpoint](/api-reference/products/single-product-detail-with-latest-metrics) (`sync` | `async`). Sync products never emit `redeem.requested`.

## Confirmation depth

Engine logs are not delivered until they're deep enough that a chain reorg is unlikely to drop them.

| Chain            | `chain_id`                | Depth     | Approx. delay |
| ---------------- | ------------------------- | --------- | ------------- |
| Ethereum mainnet | `1`                       | 12 blocks | \~3 min       |
| Base             | `8453`                    | 32 blocks | \~1 min       |
| Arbitrum One     | `42161`                   | 32 blocks | \~10 sec      |
| Optimism         | `10`                      | 32 blocks | \~1 min       |
| Polygon PoS      | `137`                     | 64 blocks | \~2 min       |
| Sandbox testnets | `11155111`, `84532`, etc. | 1 block   | \~12 sec      |

These are the defaults. The exact value used for delivery is included in the engine health endpoint (`GET /api/partner/products/{slug}/health`) under `confirmation_depth_blocks` so you can compute the same "still pending" cutoff in your UI.

## Reconciling with `/position`

After you handle `deposit.confirmed` you generally don't need to call `/position` — the event payload already has the new `shares` and `amount`. But for a sanity check or when you reconnect after downtime:

* `/position` returns the current chain state, not a snapshot at the event time
* For a user who just deposited and immediately withdrew, the events arrive in order but `/position` reflects the net (zero)
* The webhook's `block_number` lets you order events; do not rely on delivery order alone (retries can shuffle)

## Edge cases

**Chain reorg below confirmation depth.** The reorg happens before we deliver — no event fires for the orphaned tx. The user's wallet shows the tx as dropped; your UI should treat tx-without-event as a failure once you exceed `confirmation_depth_blocks * 2 * block_time` since submission.

**Multiple deposits in the same tx (multicall).** Each `Deposit` log produces one `deposit.confirmed`. The `log_index` differentiates them within the tx.

**Same user, multiple products in one tx.** Same as above — one event per log. The `slug` field tells you which product.

**Engine paused mid-deposit.** The deposit either reverts (no event) or completes (normal `deposit.confirmed`) — pause prevents new deposits but doesn't void in-flight ones. After pause, the next event you'll see for that product is `vault_pause`.

**Redeem requested then user changes mind.** Most async vaults don't support cancellation. If they do, you'll see neither `redeem.confirmed` nor a cancel event in v1; the request quietly disappears from the underlying vault. Until cancellation events ship, reconcile via `/position`.

## What's next

* [Failure modes](/failure-modes) — RPC outages, tx replacement, webhook delivery failure, idempotency
* [Webhooks](/webhooks) — signature verification, retry policy, dedupe keys
* [Headless integration](/integration-api) — wallet-side deposit/redeem code samples
