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

Operations on Stripe Refund objects.

A Refund represents a return of a charge to a customer's payment method.
You can create a refund for a PaymentIntent or Charge.

## Key behaviors

- The `payment_intent` parameter is required when creating a refund — an `ArgumentError`
  is raised immediately (pre-network) if it is missing.
- Refunds cannot be deleted. Use `cancel/4` to cancel a pending refund.
- Updates are limited to the `metadata` field only (Stripe API constraint).

## Usage

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

    # Create a full refund for a PaymentIntent
    {:ok, refund} = LatticeStripe.Refund.create(client, %{
      "payment_intent" => "pi_...",
      "reason" => "requested_by_customer"
    })

    # Create a partial refund
    {:ok, refund} = LatticeStripe.Refund.create(client, %{
      "payment_intent" => "pi_...",
      "amount" => 500
    })

    # Retrieve a refund
    {:ok, refund} = LatticeStripe.Refund.retrieve(client, "re_...")

    # Update a refund's metadata
    {:ok, refund} = LatticeStripe.Refund.update(client, "re_...", %{
      "metadata" => %{"order_id" => "ord_123"}
    })

    # Cancel a pending refund
    {:ok, refund} = LatticeStripe.Refund.cancel(client, "re_...")

    # List refunds with optional filters
    {:ok, resp} = LatticeStripe.Refund.list(client, %{"payment_intent" => "pi_..."})
    refunds = resp.data.data  # [%Refund{}, ...]

    # Stream all refunds lazily (auto-pagination)
    client
    |> LatticeStripe.Refund.stream!()
    |> Stream.take(100)
    |> Enum.each(&process_refund/1)

## Security and Inspect

The `Inspect` implementation shows only `id`, `object`, `amount`, `currency`, and `status`.
Payment intent IDs, charge IDs, and other operational details are hidden.

## Stripe API Reference

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

# `t`

```elixir
@type t() :: %LatticeStripe.Refund{
  amount: integer() | nil,
  balance_transaction: String.t() | nil,
  charge: String.t() | nil,
  created: integer() | nil,
  currency: String.t() | nil,
  destination_details: map() | nil,
  extra: map(),
  failure_balance_transaction: String.t() | nil,
  failure_reason: String.t() | nil,
  id: String.t() | nil,
  instructions_email: String.t() | nil,
  metadata: map() | nil,
  next_action: map() | nil,
  object: String.t(),
  payment_intent: String.t() | nil,
  reason: String.t() | nil,
  receipt_number: String.t() | nil,
  source_transfer_reversal: String.t() | nil,
  status: String.t() | nil,
  transfer_reversal: String.t() | nil
}
```

A Stripe Refund object.

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

# `cancel`

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

Cancels a pending Refund.

Sends `POST /v1/refunds/:id/cancel` and returns `{:ok, %Refund{status: "canceled"}}`.
Only refunds with `status: "pending"` can be canceled.

## Parameters

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

## Returns

- `{:ok, %Refund{status: "canceled"}}` on success
- `{:error, %LatticeStripe.Error{}}` on failure

## Example

    {:ok, refund} = LatticeStripe.Refund.cancel(client, "re_...")

# `cancel!`

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

Like `cancel/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 Refund for a PaymentIntent.

Sends `POST /v1/refunds` with the given params and returns `{:ok, %Refund{}}`.
The `payment_intent` param is required — an `ArgumentError` is raised immediately
(before any network call) if it is missing.

## Parameters

- `client` - A `%LatticeStripe.Client{}` struct
- `params` - Map of Refund attributes. **Required:** `"payment_intent"`.
  Optional: `"amount"` (omit for full refund), `"reason"`, `"metadata"`.
- `opts` - Per-request overrides (e.g., `[idempotency_key: "..."]`)

## Returns

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

## Example

    {:ok, refund} = LatticeStripe.Refund.create(client, %{
      "payment_intent" => "pi_3N...",
      "reason" => "requested_by_customer"
    })

# `create!`

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

Like `create/3` but raises `LatticeStripe.Error` on failure.
Also raises `ArgumentError` when `payment_intent` param is missing.

# `from_map`

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

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

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

## Example

    refund = LatticeStripe.Refund.from_map(%{
      "id" => "re_...",
      "amount" => 2000,
      "currency" => "usd",
      "status" => "succeeded"
    })

# `list`

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

Lists Refunds with optional filters.

Sends `GET /v1/refunds` and returns `{:ok, %Response{data: %List{}}}` with
typed `%Refund{}` items. All params are optional.

## Parameters

- `client` - A `%LatticeStripe.Client{}` struct
- `params` - Filter params (e.g., `%{"payment_intent" => "pi_...", "limit" => "20"}`)
- `opts` - Per-request overrides

## Returns

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

## Example

    {:ok, resp} = LatticeStripe.Refund.list(client, %{"payment_intent" => "pi_..."})
    Enum.each(resp.data.data, &IO.inspect/1)

# `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 Refund by ID.

Sends `GET /v1/refunds/:id` and returns `{:ok, %Refund{}}`.

## Parameters

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

## Returns

- `{:ok, %Refund{}}` 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 Refunds matching the given params (auto-pagination).

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

## Parameters

- `client` - A `%LatticeStripe.Client{}` struct
- `params` - Filter params (e.g., `%{"payment_intent" => "pi_...", "limit" => "100"}`)
- `opts` - Per-request overrides

## Returns

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

## Example

    client
    |> LatticeStripe.Refund.stream!()
    |> Stream.take(500)
    |> Enum.to_list()

# `update`

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

Updates a Refund by ID.

Sends `POST /v1/refunds/:id` with the given params and returns `{:ok, %Refund{}}`.
Note: the Stripe API only supports updating the `metadata` field on a Refund.

## Parameters

- `client` - A `%LatticeStripe.Client{}` struct
- `id` - The Refund ID string
- `params` - Map of fields to update (only `"metadata"` is accepted by Stripe)
- `opts` - Per-request overrides

## Returns

- `{:ok, %Refund{}}` 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*
