LatticeStripe.BillingPortal.Session (LatticeStripe v1.1.0)

Copy Markdown View Source

Operations on Stripe Billing Portal Session objects.

The Stripe Customer Portal is a hosted UI that lets customers manage their subscriptions and billing details — update payment methods, cancel or change subscriptions, download invoices, and update billing information. Your app creates a portal session and redirects the customer to the returned URL; Stripe handles the rest and redirects back to your return_url when the customer is done.

Creating a portal session

create/3 is the only operation exposed by the Stripe API — portal sessions cannot be retrieved, listed, updated, or deleted.

The "customer" param is required. All other params are optional:

  • "return_url" — URL to redirect the customer after they are done in the portal. Should be an absolute HTTPS URL you control.
  • "flow_data" — Deep-links the customer into a specific flow instead of the default portal homepage. See LatticeStripe.BillingPortal.Session.FlowData for the full schema and per-flow required sub-fields.
  • "configuration" — A bpc_* Billing Portal configuration ID. In v1.1, portal configuration is managed via the Stripe Dashboard; LatticeStripe.BillingPortal.Configuration is planned for v1.2+.
  • "locale" — Override the portal language (e.g. "en", "fr", "auto").
  • "on_behalf_of" — Connect account ID when creating a portal session for a connected account. See the stripe_account: opt for per-request Connect routing.

The "flow_data" param accepts four "type" values:

  • "subscription_cancel" — requires flow_data.subscription_cancel.subscription
  • "subscription_update" — requires flow_data.subscription_update.subscription
  • "subscription_update_confirm" — requires flow_data.subscription_update_confirm.subscription AND flow_data.subscription_update_confirm.items (non-empty list)
  • "payment_method_update" — no required sub-fields

A pre-flight guard validates these shapes pre-network and raises ArgumentError with an actionable message if required sub-fields are missing. See LatticeStripe.BillingPortal.Session.FlowData for the full nested struct schema.

Examples

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

# Basic portal session (customer lands on default portal homepage)
{:ok, session} = LatticeStripe.BillingPortal.Session.create(client, %{
  "customer" => "cus_123",
  "return_url" => "https://example.com/account"
})
redirect_to(conn, session.url)

# Deep-link into subscription cancellation flow
{:ok, session} = LatticeStripe.BillingPortal.Session.create(client, %{
  "customer" => "cus_123",
  "return_url" => "https://example.com/account",
  "flow_data" => %{
    "type" => "subscription_cancel",
    "subscription_cancel" => %{"subscription" => "sub_abc"}
  }
})

# Deep-link into payment method update flow
{:ok, session} = LatticeStripe.BillingPortal.Session.create(client, %{
  "customer" => "cus_123",
  "flow_data" => %{"type" => "payment_method_update"}
})

# Connect platform: create a portal session on behalf of a connected account
{:ok, session} = LatticeStripe.BillingPortal.Session.create(
  client,
  %{"customer" => "cus_123"},
  stripe_account: "acct_connect_123"
)

Security note — the :url field

session.url is a single-use, short-lived (~5 minutes) authenticated redirect that grants the customer full access to their portal session. It is a bearer credential for the portal scope — treat it like a password.

LatticeStripe masks :url (and :flow) from default Inspect output to prevent accidental leaks via Logger, APM agents, crash dumps, or telemetry handlers. Access the URL directly when redirecting: session.url.

To inspect all fields including :url and :flow during debugging:

IO.inspect(session, structs: false)
# or access directly:
session.url
session.flow

Portal configuration

Portal configuration (branding, allowed features, default behavior) is managed via the Stripe Dashboard in v1.1. LatticeStripe.BillingPortal.Configuration is planned for v1.2+. Pass a bpc_* configuration ID in params["configuration"] to select a specific portal configuration at session creation time.

Stripe API Reference

See the Stripe Billing Portal Session API for the full object reference and available parameters.

Summary

Functions

Create a Stripe Billing Portal Session.

Bang variant of create/3. Returns %Session{} on success, raises LatticeStripe.Error on API failure.

Decode a Stripe-shaped string-keyed map into a %Session{}.

Types

t()

@type t() :: %LatticeStripe.BillingPortal.Session{
  configuration: String.t() | nil,
  created: integer() | nil,
  customer: String.t() | nil,
  extra: map(),
  flow: LatticeStripe.BillingPortal.Session.FlowData.t() | nil,
  id: String.t() | nil,
  livemode: boolean() | nil,
  locale: String.t() | nil,
  object: String.t() | nil,
  on_behalf_of: String.t() | nil,
  return_url: String.t() | nil,
  url: String.t() | nil
}

Functions

create(client, params, opts \\ [])

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

Create a Stripe Billing Portal Session.

Returns {:ok, %Session{url: url}} on success. The url is a single-use, short-lived (~5 minutes) authenticated redirect — redirect the customer to it immediately. Do not cache or log it.

Required params

  • "customer" — The Stripe customer ID (cus_*) whose portal session to create.

Optional params

  • "return_url" — Absolute HTTPS URL to redirect the customer after the portal session.
  • "flow_data" — Deep-link into a specific flow. See module docs for flow type details. Omit to render the default portal homepage.
  • "configuration" — Billing Portal configuration ID (bpc_*). Defaults to the account default configured in the Stripe Dashboard.
  • "locale" — Portal language override ("en", "fr", "auto", etc.).
  • "on_behalf_of" — Connect account ID for platform-to-connected-account sessions.

Options

  • stripe_account: — Connect per-request account routing. Adds Stripe-Account header.

Examples

{:ok, session} = Session.create(client, %{
  "customer" => "cus_123",
  "return_url" => "https://example.com/account"
})

# With flow deep-link
{:ok, session} = Session.create(client, %{
  "customer" => "cus_123",
  "flow_data" => %{
    "type" => "subscription_cancel",
    "subscription_cancel" => %{"subscription" => "sub_abc"}
  }
})

# Connect platform routing
{:ok, session} = Session.create(client, %{"customer" => "cus_123"},
  stripe_account: "acct_connect_123"
)

Raises

  • ArgumentError — immediately (pre-network) when "customer" is missing
  • ArgumentError — immediately (pre-network) when "flow_data" is present but has an unknown "type" or is missing required sub-fields

create!(client, params, opts \\ [])

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

Bang variant of create/3. Returns %Session{} on success, raises LatticeStripe.Error on API failure.

from_map(map)

@spec from_map(map() | nil) :: t() | nil

Decode a Stripe-shaped string-keyed map into a %Session{}.

The "flow" sub-object is decoded into %FlowData{} via FlowData.from_map/1. Unknown top-level keys land in :extra.

Returns nil when given nil.