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

Operations on Stripe PaymentMethod objects.

A PaymentMethod represents a customer's payment instrument. PaymentMethods
are used with PaymentIntents to collect payments or with SetupIntents to save
payment details for future use.

## Key behaviors

- **`list/3` requires a `"customer"` param** — Stripe only supports
  customer-scoped listing. Calling `list/3` without `%{"customer" => "cus_..."}` in
  params will raise `ArgumentError` before any network call is made. Example:
  `PaymentMethod.list(client, %{"customer" => "cus_123"})`.

- **`stream!/3` also requires `"customer"`** — Same constraint applies to
  the auto-pagination stream.

- **PaymentMethods cannot be deleted** — Use `detach/4` to remove a
  PaymentMethod from a customer. The PaymentMethod object will still exist in
  Stripe but `customer` will be set to `nil`.

- **Type-specific nested objects** — Fields like `card`, `us_bank_account`,
  `sepa_debit`, etc. are `nil` unless the PaymentMethod's `type` matches. For
  example, a card PaymentMethod will have a populated `card` map but `nil`
  `us_bank_account`.

## Usage

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

    # Create a PaymentMethod (card token from frontend)
    {:ok, pm} = LatticeStripe.PaymentMethod.create(client, %{
      "type" => "card",
      "card" => %{"token" => "tok_visa"}
    })

    # Attach it to a customer for reuse
    {:ok, pm} = LatticeStripe.PaymentMethod.attach(client, pm.id, %{
      "customer" => "cus_123"
    })

    # List a customer's PaymentMethods (customer param is required)
    {:ok, resp} = LatticeStripe.PaymentMethod.list(client, %{"customer" => "cus_123"})
    payment_methods = resp.data.data  # [%PaymentMethod{}, ...]

    # Stream all of a customer's PaymentMethods lazily (auto-pagination)
    client
    |> LatticeStripe.PaymentMethod.stream!(%{"customer" => "cus_123"})
    |> Enum.to_list()

    # Detach a PaymentMethod from a customer (does not delete the object)
    {:ok, pm} = LatticeStripe.PaymentMethod.detach(client, pm.id)

## Security and Inspect

The `Inspect` implementation hides all sensitive billing and card details.
Only `id`, `object`, and `type` are shown. When `type` is `"card"`, the
`card_brand` and `card_last4` are also shown (safe to log).

## Stripe API Reference

See the [Stripe PaymentMethod API](https://docs.stripe.com/api/payment_methods) for the full
object reference and available parameters.

# `t`

```elixir
@type t() :: %LatticeStripe.PaymentMethod{
  acss_debit: map() | nil,
  affirm: map() | nil,
  afterpay_clearpay: map() | nil,
  alipay: map() | nil,
  allow_redisplay: String.t() | nil,
  alma: map() | nil,
  au_becs_debit: map() | nil,
  bacs_debit: map() | nil,
  bancontact: map() | nil,
  billie: map() | nil,
  billing_details: map() | nil,
  boleto: map() | nil,
  card: map() | nil,
  card_present: map() | nil,
  cashapp: map() | nil,
  created: integer() | nil,
  customer: String.t() | nil,
  customer_balance: map() | nil,
  eps: map() | nil,
  extra: map(),
  fpx: map() | nil,
  giropay: map() | nil,
  grabpay: map() | nil,
  id: String.t() | nil,
  ideal: map() | nil,
  interac_present: map() | nil,
  kakao_pay: map() | nil,
  klarna: map() | nil,
  konbini: map() | nil,
  link: map() | nil,
  livemode: boolean() | nil,
  metadata: map() | nil,
  mobilepay: map() | nil,
  multibanco: map() | nil,
  naver_pay: map() | nil,
  nz_bank_account: map() | nil,
  object: String.t(),
  oxxo: map() | nil,
  p24: map() | nil,
  paynow: map() | nil,
  paypal: map() | nil,
  promptpay: map() | nil,
  radar_options: map() | nil,
  revolut_pay: map() | nil,
  samsung_pay: map() | nil,
  sepa_debit: map() | nil,
  sofort: map() | nil,
  swish: map() | nil,
  twint: map() | nil,
  type: String.t() | nil,
  us_bank_account: map() | nil,
  wechat_pay: map() | nil,
  zip: map() | nil
}
```

A Stripe PaymentMethod object.

See the [Stripe PaymentMethod API](https://docs.stripe.com/api/payment_methods/object) for field definitions.

# `attach`

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

Attaches a PaymentMethod to a customer.

Sends `POST /v1/payment_methods/:id/attach` with params containing the
customer ID and returns `{:ok, %PaymentMethod{customer: "cus_..."}}`.

## Parameters

- `client` - A `%LatticeStripe.Client{}` struct
- `id` - The PaymentMethod ID string
- `params` - MUST include `%{"customer" => "cus_..."}` to specify which customer
- `opts` - Per-request overrides

## Returns

- `{:ok, %PaymentMethod{customer: "cus_..."}}` on success
- `{:error, %LatticeStripe.Error{}}` on failure

## Example

    {:ok, pm} = LatticeStripe.PaymentMethod.attach(client, "pm_123", %{
      "customer" => "cus_123"
    })

# `attach!`

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

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

# `create`

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

Creates a new PaymentMethod.

Sends `POST /v1/payment_methods` with the given params and returns
`{:ok, %PaymentMethod{}}`. This does not attach the PaymentMethod to a
customer — use `attach/4` after creating.

## Parameters

- `client` - A `%LatticeStripe.Client{}` struct
- `params` - Map of PaymentMethod attributes (e.g., `%{"type" => "card", "card" => %{"token" => "tok_visa"}}`)
- `opts` - Per-request overrides (e.g., `[idempotency_key: "..."]`)

## Returns

- `{:ok, %PaymentMethod{}}` on success
- `{:error, %LatticeStripe.Error{}}` on failure

## Example

    {:ok, pm} = LatticeStripe.PaymentMethod.create(client, %{
      "type" => "card",
      "card" => %{"token" => "tok_visa"}
    })

# `create!`

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

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

# `detach`

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

Detaches a PaymentMethod from a customer.

Sends `POST /v1/payment_methods/:id/detach` and returns
`{:ok, %PaymentMethod{customer: nil}}`. The PaymentMethod object continues
to exist in Stripe but is no longer associated with any customer.

Note: PaymentMethods cannot be deleted — use `detach/4` to disassociate
a PaymentMethod from a customer.

## Parameters

- `client` - A `%LatticeStripe.Client{}` struct
- `id` - The PaymentMethod ID string
- `params` - Optional params (typically `%{}`)
- `opts` - Per-request overrides

## Returns

- `{:ok, %PaymentMethod{customer: nil}}` on success
- `{:error, %LatticeStripe.Error{}}` on failure

## Example

    {:ok, pm} = LatticeStripe.PaymentMethod.detach(client, "pm_123")
    nil = pm.customer

# `detach!`

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

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

# `from_map`

```elixir
@spec from_map(map()) :: t()
```

Converts a decoded Stripe API map to a `%PaymentMethod{}` struct.

Maps all known Stripe PaymentMethod fields. Any unrecognized fields are
collected into the `extra` map so no data is silently lost.

Type-specific nested objects (e.g., `card`, `us_bank_account`) are set to
`nil` unless the map contains them.

## Example

    pm = LatticeStripe.PaymentMethod.from_map(%{
      "id" => "pm_123",
      "type" => "card",
      "card" => %{"brand" => "visa", "last4" => "4242"}
    })

# `list`

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

Lists PaymentMethods for a customer.

Sends `GET /v1/payment_methods` and returns
`{:ok, %Response{data: %List{}}}` with typed `%PaymentMethod{}` items.

**Requires `"customer"` in params.** Stripe only supports customer-scoped
listing. This function raises `ArgumentError` before making any network call
if `"customer"` is missing from params.

## Parameters

- `client` - A `%LatticeStripe.Client{}` struct
- `params` - Filter params — MUST include `%{"customer" => "cus_..."}`.
  Optional: `"type"`, `"limit"`, `"starting_after"`, `"ending_before"`.
- `opts` - Per-request overrides

## Returns

- `{:ok, %Response{data: %List{data: [%PaymentMethod{}, ...]}}}` on success
- `{:error, %LatticeStripe.Error{}}` on failure

## Example

    {:ok, resp} = LatticeStripe.PaymentMethod.list(client, %{
      "customer" => "cus_123",
      "type" => "card"
    })
    payment_methods = resp.data.data

# `list!`

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

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

# `retrieve`

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

Retrieves a PaymentMethod by ID.

Sends `GET /v1/payment_methods/:id` and returns `{:ok, %PaymentMethod{}}`.

## Parameters

- `client` - A `%LatticeStripe.Client{}` struct
- `id` - The PaymentMethod ID string (e.g., `"pm_123"`)
- `opts` - Per-request overrides

## Returns

- `{:ok, %PaymentMethod{}}` on success
- `{:error, %LatticeStripe.Error{}}` on failure

# `retrieve!`

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

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

# `stream!`

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

Returns a lazy stream of all PaymentMethods for a customer (auto-pagination).

Emits individual `%PaymentMethod{}` structs, fetching additional pages as needed.
Raises `LatticeStripe.Error` if any page fetch fails.

**Requires `"customer"` in params.** Raises `ArgumentError` before any network
call if `"customer"` is missing.

## Parameters

- `client` - A `%LatticeStripe.Client{}` struct
- `params` - MUST include `%{"customer" => "cus_..."}`. Optional: `"type"`, `"limit"`.
- `opts` - Per-request overrides

## Returns

An `Enumerable.t()` of `%PaymentMethod{}` structs.

## Example

    client
    |> LatticeStripe.PaymentMethod.stream!(%{"customer" => "cus_123"})
    |> Stream.take(100)
    |> Enum.to_list()

# `update`

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

Updates a PaymentMethod by ID.

Sends `POST /v1/payment_methods/:id` with the given params and returns
`{:ok, %PaymentMethod{}}`.

## Parameters

- `client` - A `%LatticeStripe.Client{}` struct
- `id` - The PaymentMethod ID string
- `params` - Map of fields to update (e.g., `%{"billing_details" => %{"name" => "John"}}`)
- `opts` - Per-request overrides

## Returns

- `{:ok, %PaymentMethod{}}` on success
- `{:error, %LatticeStripe.Error{}}` on failure

# `update!`

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

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

---

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