# `Accrue.Billing.SubscriptionActions`
[🔗](https://github.com/szTheory/accrue/blob/accrue-v1.1.1/lib/accrue/billing/subscription_actions.ex#L1)

Write surface for subscription lifecycle operations.

Every function here is exposed on `Accrue.Billing` — you rarely call
this module directly. Use `Accrue.Billing.subscribe/3`,
`Accrue.Billing.cancel/2`, etc. instead.

## When you reach for this module

If you need to go deeper than `Accrue.Billing` exposes — for example,
to call a function in a context where `defdelegate` wrapping is in the
way — these are the underlying implementations.

## Lifecycle groups

**Create**
- `subscribe/3` — subscribe a billable to a price; returns an intent result
  (SCA-safe: may return `{:ok, :requires_action, payment_intent}`)
- `comp_subscription/3` — create a 100%-off comped subscription

**Manage plan**
- `swap_plan/3` — replace the current price with a new one (proration required)
- `update_quantity/3` — change the quantity on a single-item subscription
- `preview_upcoming_invoice/2` — fetch the next invoice before it's finalized

**Pause and resume**
- `pause/2` — pause collection (void, mark_uncollectible, or keep_as_draft)
- `unpause/2` — resume a paused subscription
- `resume/2` — cancel a pending cancellation (undo `cancel_at_period_end`)

**Cancel**
- `cancel/2` — cancel immediately
- `cancel_at_period_end/2` — schedule cancellation at the end of the billing period

**Read**
- `get_subscription/2` — fetch a local subscription row by id

## Return types

Operations that involve a PaymentIntent (subscribe, swap_plan, cancel
with `invoice_now: true`) return `intent_result(Subscription.t())`:

    {:ok, %Subscription{}}
    | {:ok, :requires_action, payment_intent_map}
    | {:error, term()}

All other operations return `{:ok, %Subscription{}} | {:error, term()}`.

## Atomicity

Every write atomically persists the local row change **and** appends an
event to `accrue_events` inside the same `Repo.transact/1` call.

# `cancel`

```elixir
@spec cancel(
  Accrue.Billing.Subscription.t(),
  keyword()
) ::
  {:ok, Accrue.Billing.Subscription.t()}
  | {:ok, :requires_action, map()}
  | {:error, term()}
```

# `cancel!`

```elixir
@spec cancel!(
  Accrue.Billing.Subscription.t(),
  keyword()
) :: Accrue.Billing.Subscription.t()
```

# `cancel_at_period_end`

```elixir
@spec cancel_at_period_end(
  Accrue.Billing.Subscription.t(),
  keyword()
) :: {:ok, Accrue.Billing.Subscription.t()} | {:error, term()}
```

# `cancel_at_period_end!`

```elixir
@spec cancel_at_period_end!(
  Accrue.Billing.Subscription.t(),
  keyword()
) :: Accrue.Billing.Subscription.t()
```

# `comp_subscription`

```elixir
@spec comp_subscription(term(), term(), keyword()) ::
  {:ok, Accrue.Billing.Subscription.t()} | {:error, term()}
```

Creates a free-tier ("comped") subscription with a 100%-off coupon
applied. Skips the payment_method guard since there is nothing to
charge.

The coupon referenced by `coupon_id` must exist in the processor's
dashboard. Defaults to `"accrue_comp_100_forever"`; host apps create
this once via `Accrue.Billing.create_coupon/2` (landed in 04-05) or
the Stripe Dashboard.

# `comp_subscription!`

```elixir
@spec comp_subscription!(term(), term(), keyword()) :: Accrue.Billing.Subscription.t()
```

Raising variant of `comp_subscription/3`.

# `get_subscription`

```elixir
@spec get_subscription(
  String.t(),
  keyword()
) :: {:ok, Accrue.Billing.Subscription.t()} | {:error, :not_found}
```

# `get_subscription!`

```elixir
@spec get_subscription!(
  String.t(),
  keyword()
) :: Accrue.Billing.Subscription.t()
```

# `pause`

```elixir
@spec pause(
  Accrue.Billing.Subscription.t(),
  keyword()
) :: {:ok, Accrue.Billing.Subscription.t()} | {:error, term()}
```

# `pause!`

```elixir
@spec pause!(
  Accrue.Billing.Subscription.t(),
  keyword()
) :: Accrue.Billing.Subscription.t()
```

# `preview_upcoming_invoice`

```elixir
@spec preview_upcoming_invoice(
  Accrue.Billing.Subscription.t() | Accrue.Billing.Customer.t(),
  keyword()
) :: {:ok, Accrue.Billing.UpcomingInvoice.t()} | {:error, term()}
```

# `preview_upcoming_invoice!`

```elixir
@spec preview_upcoming_invoice!(
  Accrue.Billing.Subscription.t() | Accrue.Billing.Customer.t(),
  keyword()
) :: Accrue.Billing.UpcomingInvoice.t()
```

# `resume`

```elixir
@spec resume(
  Accrue.Billing.Subscription.t(),
  keyword()
) :: {:ok, Accrue.Billing.Subscription.t()} | {:error, term()}
```

# `resume!`

```elixir
@spec resume!(
  Accrue.Billing.Subscription.t(),
  keyword()
) :: Accrue.Billing.Subscription.t()
```

# `subscribe`

```elixir
@spec subscribe(term(), term(), keyword()) ::
  {:ok, Accrue.Billing.Subscription.t()}
  | {:ok, :requires_action, map()}
  | {:error, term()}
```

Creates a subscription for the given billable (or `%Customer{}`) against
the configured processor. Returns `intent_result(Subscription.t())`.

# `subscribe!`

```elixir
@spec subscribe!(term(), term(), keyword()) :: Accrue.Billing.Subscription.t()
```

Raising variant of `subscribe/3`.

# `swap_plan`

```elixir
@spec swap_plan(Accrue.Billing.Subscription.t(), String.t(), keyword()) ::
  {:ok, Accrue.Billing.Subscription.t()}
  | {:ok, :requires_action, map()}
  | {:error, term()}
```

# `swap_plan!`

```elixir
@spec swap_plan!(Accrue.Billing.Subscription.t(), String.t(), keyword()) ::
  Accrue.Billing.Subscription.t()
```

# `unpause`

```elixir
@spec unpause(
  Accrue.Billing.Subscription.t(),
  keyword()
) :: {:ok, Accrue.Billing.Subscription.t()} | {:error, term()}
```

# `unpause!`

```elixir
@spec unpause!(
  Accrue.Billing.Subscription.t(),
  keyword()
) :: Accrue.Billing.Subscription.t()
```

# `update_quantity`

```elixir
@spec update_quantity(Accrue.Billing.Subscription.t(), pos_integer(), keyword()) ::
  {:ok, Accrue.Billing.Subscription.t()} | {:error, term()}
```

# `update_quantity!`

```elixir
@spec update_quantity!(Accrue.Billing.Subscription.t(), pos_integer(), keyword()) ::
  Accrue.Billing.Subscription.t()
```

---

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