Stripe payment provider implementation.
This module implements the PhoenixKit.Modules.Billing.Providers.Provider behaviour
for Stripe payments. It supports:
- Hosted Checkout for one-time payments
- Setup sessions for saving payment methods
- Charging saved payment methods (for subscription renewals)
- Webhook signature verification
- Refunds
Configuration
Configure Stripe in your provider settings:
# Via Admin UI: /admin/settings/billing/providers
# Or via Settings API:
PhoenixKit.Modules.Billing.update_provider_config(:stripe, %{
enabled: true,
mode: "test",
api_key: "sk_test_...",
webhook_secret: "whsec_..."
})Webhook Events
Configure your Stripe webhook to send these events:
checkout.session.completed- Payment completedcheckout.session.expired- Session expiredpayment_intent.succeeded- Payment succeeded (for saved cards)payment_intent.payment_failed- Payment failedcharge.refunded- Refund processedsetup_intent.succeeded- Card saved successfully
Dependencies
Requires the stripe hex package:
{:stripe, "~> 1.1"}
Summary
Functions
Charges a saved payment method.
Creates a Stripe Checkout Session for one-time payment.
Creates a refund for a Stripe charge.
Creates a Stripe Setup Session to save a payment method.
Detaches a payment method from its customer.
Gets details of a saved payment method from Stripe.
Handles and normalizes Stripe webhook events.
Verifies Stripe webhook signature.
Functions
Charges a saved payment method.
Used for subscription renewals where the payment method was previously saved.
Options
:currency- Currency code (default: EUR):description- Description for the charge:invoice_id- Associated invoice ID:metadata- Additional metadata
Examples
iex> charge_payment_method(payment_method, Decimal.new("99.00"), currency: "EUR")
{:ok, %{id: "pi_...", provider_transaction_id: "ch_...", status: "succeeded"}}
Creates a Stripe Checkout Session for one-time payment.
Options
:success_url- URL to redirect after successful payment (required):cancel_url- URL to redirect if user cancels (required):save_payment_method- Whether to save card for future use (default: false):customer_email- Pre-fill customer email:metadata- Additional metadata to attach
Examples
iex> create_checkout_session(invoice, success_url: "https://...", cancel_url: "https://...")
{:ok, %{id: "cs_test_...", url: "https://checkout.stripe.com/..."}}
Creates a refund for a Stripe charge.
Options
:reason- Reason for refund ("duplicate", "fraudulent", "requested_by_customer"):metadata- Additional metadata
Examples
iex> create_refund("ch_xxx", Decimal.new("50.00"), reason: "requested_by_customer")
{:ok, %{id: "re_...", provider_refund_id: "re_...", amount: #Decimal<50.00>}}
Creates a Stripe Setup Session to save a payment method.
Options
:success_url- URL to redirect after success (required):cancel_url- URL to redirect if user cancels (required):customer_email- Customer email
Examples
iex> create_setup_session(user, success_url: "https://...", cancel_url: "https://...")
{:ok, %{id: "seti_...", url: "https://checkout.stripe.com/..."}}
Detaches a payment method from its customer.
Examples
iex> detach_payment_method("pm_xxx")
:ok
Gets details of a saved payment method from Stripe.
Examples
iex> get_payment_method_details("pm_xxx")
{:ok, %{id: "pm_xxx", type: "card", brand: "visa", last4: "4242", ...}}
Handles and normalizes Stripe webhook events.
Supported Events
checkout.session.completed- Checkout payment completedcheckout.session.expired- Checkout session expiredpayment_intent.succeeded- Payment intent succeededpayment_intent.payment_failed- Payment failedcharge.refunded- Charge refundedsetup_intent.succeeded- Setup intent completed (card saved)
Examples
iex> handle_webhook_event(%{"type" => "checkout.session.completed", ...})
{:ok, %{type: "checkout.completed", event_id: "evt_...", data: %{...}}}
Verifies Stripe webhook signature.
Uses Stripe's signature verification to ensure the webhook came from Stripe.
Examples
iex> verify_webhook_signature(raw_body, signature_header, webhook_secret)
:ok
iex> verify_webhook_signature(raw_body, "invalid", webhook_secret)
{:error, :invalid_signature}