# `LatticeStripe.ExternalAccount`
[🔗](https://github.com/szTheory/lattice_stripe/blob/v1.1.0/lib/lattice_stripe/external_account.ex#L1)

Polymorphic dispatcher for external accounts on a Stripe Connect connected account.

External accounts are either bank accounts (`%LatticeStripe.BankAccount{}`)
or debit cards (`%LatticeStripe.Card{}`). All CRUD operations for the
`/v1/accounts/:account/external_accounts` endpoint live on this module;
responses are dispatched to the appropriate struct via `cast/1` based on
the `object` discriminator.

Unknown future object types fall back to
`%LatticeStripe.ExternalAccount.Unknown{}` so user code never crashes on a
new Stripe shape:

    case ea do
      %LatticeStripe.BankAccount{} -> ...
      %LatticeStripe.Card{} -> ...
      %LatticeStripe.ExternalAccount.Unknown{} -> ...
    end

## Usage

    client = LatticeStripe.Client.new!(api_key: "sk_live_...", finch: MyApp.Finch)

    # Attach a tokenized bank account to a connected account
    {:ok, ba} =
      LatticeStripe.ExternalAccount.create(client, "acct_1...", %{
        "external_account" => "btok_..."
      })

    # Retrieve a single external account
    {:ok, ea} = LatticeStripe.ExternalAccount.retrieve(client, "acct_1...", "ba_1...")

    # List all external accounts (mixed bank_account + card)
    {:ok, resp} = LatticeStripe.ExternalAccount.list(client, "acct_1...")
    Enum.each(resp.data.data, &handle_external_account/1)

    # Stream all external accounts lazily with auto-pagination
    client
    |> LatticeStripe.ExternalAccount.stream!("acct_1...")
    |> Enum.each(&handle_external_account/1)

    # Delete an external account
    {:ok, %{extra: %{"deleted" => true}}} =
      LatticeStripe.ExternalAccount.delete(client, "acct_1...", "ba_1...")

## Stripe API Reference

- https://docs.stripe.com/api/external_account_bank_accounts
- https://docs.stripe.com/api/external_account_cards

# `ea`

```elixir
@type ea() ::
  LatticeStripe.BankAccount.t()
  | LatticeStripe.Card.t()
  | LatticeStripe.ExternalAccount.Unknown.t()
```

The sum-type returned by every operation in this module. Pattern-match on
the concrete struct:

    case ea do
      %LatticeStripe.BankAccount{} -> ...
      %LatticeStripe.Card{} -> ...
      %LatticeStripe.ExternalAccount.Unknown{} -> ...
    end

# `cast`

```elixir
@spec cast(map() | nil) :: ea() | nil
```

Dispatches a decoded Stripe external-account map to the correct struct.

Returns a `%BankAccount{}`, `%Card{}`, or `%ExternalAccount.Unknown{}`
depending on the `"object"` field in the payload. Returns `nil` if given
`nil`. Never raises on novel object types — the `Unknown` fallback
preserves the full raw payload in `:extra`.

# `create`

```elixir
@spec create(LatticeStripe.Client.t(), String.t(), map(), keyword()) ::
  {:ok, ea()} | {:error, LatticeStripe.Error.t()}
```

Creates a new external account on a Connect connected account.

Sends `POST /v1/accounts/:account/external_accounts` with the given params
and returns `{:ok, sum_type}` — a `%BankAccount{}` or `%Card{}` depending
on the token type used.

## Parameters

- `client` - `%LatticeStripe.Client{}`
- `account_id` - Connected account ID (e.g., `"acct_1..."`). Required, non-empty.
- `params` - Creation params, typically `%{"external_account" => "btok_..." | "tok_..."}`
- `opts` - Per-request overrides

## Returns

- `{:ok, %LatticeStripe.BankAccount{} | %LatticeStripe.Card{}}` on success
- `{:error, %LatticeStripe.Error{}}` on failure

# `create!`

```elixir
@spec create!(LatticeStripe.Client.t(), String.t(), map(), keyword()) :: ea()
```

Like `create/4` but raises `LatticeStripe.Error` on failure.

# `delete`

```elixir
@spec delete(LatticeStripe.Client.t(), String.t(), String.t(), keyword()) ::
  {:ok, ea()} | {:error, LatticeStripe.Error.t()}
```

Deletes an external account on a connected account.

Sends `DELETE /v1/accounts/:account/external_accounts/:id`. Stripe returns
the object type with `"deleted" => true`, which flows into the struct's
`:extra` map so callers can verify the deletion outcome.

# `delete!`

```elixir
@spec delete!(LatticeStripe.Client.t(), String.t(), String.t(), keyword()) :: ea()
```

Like `delete/4` but raises `LatticeStripe.Error` on failure.

# `list`

```elixir
@spec list(LatticeStripe.Client.t(), String.t(), map(), keyword()) ::
  {:ok, LatticeStripe.Response.t()} | {:error, LatticeStripe.Error.t()}
```

Lists external accounts on a connected account.

Sends `GET /v1/accounts/:account/external_accounts`. Pass
`%{"object" => "bank_account"}` or `%{"object" => "card"}` to filter by type.

# `list!`

```elixir
@spec list!(LatticeStripe.Client.t(), String.t(), map(), keyword()) ::
  LatticeStripe.Response.t()
```

Like `list/4` but raises `LatticeStripe.Error` on failure.

# `retrieve`

```elixir
@spec retrieve(LatticeStripe.Client.t(), String.t(), String.t(), keyword()) ::
  {:ok, ea()} | {:error, LatticeStripe.Error.t()}
```

Retrieves a single external account on a connected account.

Sends `GET /v1/accounts/:account/external_accounts/:id`.

# `retrieve!`

```elixir
@spec retrieve!(LatticeStripe.Client.t(), String.t(), String.t(), keyword()) :: ea()
```

Like `retrieve/4` but raises `LatticeStripe.Error` on failure.

# `stream!`

```elixir
@spec stream!(LatticeStripe.Client.t(), String.t(), map(), keyword()) ::
  Enumerable.t()
```

Returns a lazy stream of external accounts on a connected account.

Emits individual sum-type structs (`%BankAccount{}`, `%Card{}`, or
`%Unknown{}`), fetching additional pages as needed. Raises
`LatticeStripe.Error` if any page fetch fails.

# `update`

```elixir
@spec update(LatticeStripe.Client.t(), String.t(), String.t(), map(), keyword()) ::
  {:ok, ea()} | {:error, LatticeStripe.Error.t()}
```

Updates an external account on a connected account.

Sends `POST /v1/accounts/:account/external_accounts/:id`. Stripe's update
surface is field-limited (metadata, account_holder_name, default_for_currency,
etc. — varies by external account type).

# `update!`

```elixir
@spec update!(LatticeStripe.Client.t(), String.t(), String.t(), map(), keyword()) ::
  ea()
```

Like `update/5` but raises `LatticeStripe.Error` on failure.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
