# `PhoenixKitBilling.Providers.Provider`
[🔗](https://github.com/BeamLabEU/phoenix_kit_billing/blob/0.5.1/lib/phoenix_kit_billing/providers/provider.ex#L1)

Behaviour for payment providers.

Defines a unified interface for all payment systems (Stripe, PayPal, Razorpay).
Each provider implements this behaviour to handle payments, refunds, and webhooks.

## Provider Architecture

PhoenixKit uses Internal Subscription Control - subscriptions are managed
in our database, not by providers. Providers only handle:
- One-time payments (checkout sessions)
- Saving payment methods for recurring billing
- Charging saved payment methods
- Processing refunds

## Hosted Checkout Flow

    1. User clicks "Pay with Stripe" on invoice
    2. Backend calls create_checkout_session/2
    3. User redirected to provider's checkout page
    4. Provider processes payment
    5. Provider sends webhook
    6. WebhookProcessor updates invoice status

## Implementation Example

    defmodule PhoenixKitBilling.Providers.Stripe do
      @behaviour PhoenixKitBilling.Providers.Provider

      @impl true
      def provider_name, do: :stripe

      @impl true
      def available? do
        config = get_config()
        config && config.enabled && config.api_key
      end

      @impl true
      def create_checkout_session(invoice, opts) do
        # Implementation
      end
      # ... other callbacks
    end

# `charge_result`

```elixir
@type charge_result() :: PhoenixKitBilling.Providers.Types.ChargeResult.t()
```

# `checkout_session`

```elixir
@type checkout_session() :: PhoenixKitBilling.Providers.Types.CheckoutSession.t()
```

# `payment_method`

```elixir
@type payment_method() :: PhoenixKitBilling.Providers.Types.PaymentMethodInfo.t()
```

# `refund_result`

```elixir
@type refund_result() :: PhoenixKitBilling.Providers.Types.RefundResult.t()
```

# `setup_session`

```elixir
@type setup_session() :: PhoenixKitBilling.Providers.Types.SetupSession.t()
```

# `webhook_event`

```elixir
@type webhook_event() :: PhoenixKitBilling.Providers.Types.WebhookEventData.t()
```

# `available?`

```elixir
@callback available?() :: boolean()
```

Checks if the provider is configured and available for use.

Returns `true` if:
- Provider is enabled in settings
- API credentials are configured
- Provider passed verification (if applicable)

## Examples

    iex> Stripe.available?()
    true

# `charge_payment_method`

```elixir
@callback charge_payment_method(
  payment_method :: map(),
  amount :: Decimal.t(),
  opts :: keyword()
) :: {:ok, charge_result()} | {:error, term()}
```

Charges a saved payment method.

Used for subscription renewals. The payment method was previously
saved during checkout or setup session.

## Parameters

- `payment_method` - The saved payment method record
- `amount` - Amount to charge (Decimal)
- `opts` - Options:
  - `:currency` - Currency code (default: from payment method)
  - `:description` - Description for the charge
  - `:invoice_uuid` - Associated invoice UUID
  - `:metadata` - Additional metadata

## Returns

- `{:ok, charge_result}` - Charge successful
- `{:error, :card_declined}` - Card was declined
- `{:error, :payment_method_expired}` - Payment method expired
- `{:error, reason}` - Other error

# `create_checkout_session`

```elixir
@callback create_checkout_session(invoice :: map(), opts :: keyword()) ::
  {:ok, checkout_session()} | {:error, term()}
```

Creates a checkout session for one-time payment.

This is used for paying invoices. The user is redirected to the
provider's hosted checkout page where they enter payment details.

## Parameters

- `invoice` - The invoice to pay (must include amount, currency, line_items)
- `opts` - Options:
  - `:success_url` - URL to redirect after successful payment
  - `:cancel_url` - URL to redirect if user cancels
  - `:save_payment_method` - Whether to save card for future use (default: false)

## Returns

- `{:ok, checkout_session}` - Session created, redirect user to `session.url`
- `{:error, reason}` - Failed to create session

# `create_refund`

```elixir
@callback create_refund(
  provider_transaction_id :: String.t(),
  amount :: Decimal.t() | nil,
  opts :: keyword()
) :: {:ok, refund_result()} | {:error, term()}
```

Creates a refund for a transaction.

## Parameters

- `provider_transaction_id` - The provider's transaction/charge ID
- `amount` - Amount to refund (Decimal, nil for full refund)
- `opts` - Options:
  - `:reason` - Reason for refund
  - `:metadata` - Additional metadata

## Returns

- `{:ok, refund_result}` - Refund created
- `{:error, :already_refunded}` - Transaction already refunded
- `{:error, reason}` - Refund failed

# `create_setup_session`

```elixir
@callback create_setup_session(user :: map(), opts :: keyword()) ::
  {:ok, setup_session()} | {:error, term()}
```

Creates a setup session to save a payment method without charging.

Used when a user wants to add a payment method for future subscriptions
without making an immediate payment.

## Parameters

- `user` - The user to save payment method for
- `opts` - Options:
  - `:success_url` - URL to redirect after success
  - `:cancel_url` - URL to redirect if user cancels

## Returns

- `{:ok, setup_session}` - Session created
- `{:error, reason}` - Failed to create session

# `detach_payment_method`
*optional* 

```elixir
@callback detach_payment_method(provider_payment_method_id :: String.t()) ::
  :ok | {:error, term()}
```

Detaches/removes a saved payment method from the provider.

## Parameters

- `provider_payment_method_id` - The provider's payment method ID

## Returns

- `:ok` - Payment method removed
- `{:error, :not_found}` - Payment method not found
- `{:error, reason}` - Failed to remove

# `get_payment_method_details`

```elixir
@callback get_payment_method_details(provider_payment_method_id :: String.t()) ::
  {:ok, payment_method()} | {:error, term()}
```

Gets details of a saved payment method.

## Parameters

- `provider_payment_method_id` - The provider's payment method ID

## Returns

- `{:ok, payment_method}` - Payment method details
- `{:error, :not_found}` - Payment method not found
- `{:error, reason}` - Failed to get details

# `handle_webhook_event`

```elixir
@callback handle_webhook_event(payload :: map()) ::
  {:ok, webhook_event()} | {:error, term()}
```

Handles and normalizes a webhook event payload.

Converts provider-specific event format to a normalized format
that can be processed by WebhookProcessor.

## Parameters

- `payload` - Decoded JSON payload from webhook

## Returns

- `{:ok, webhook_event}` - Event parsed successfully
- `{:error, :unknown_event}` - Event type not recognized
- `{:error, reason}` - Failed to parse event

# `provider_name`

```elixir
@callback provider_name() :: atom()
```

Returns the provider name as an atom.

## Examples

    iex> Stripe.provider_name()
    :stripe

    iex> PayPal.provider_name()
    :paypal

# `verify_webhook_signature`

```elixir
@callback verify_webhook_signature(
  payload :: binary(),
  signature :: String.t(),
  secret :: String.t()
) :: :ok | {:error, :invalid_signature}
```

Verifies webhook signature to ensure request is from the provider.

## Parameters

- `payload` - Raw request body as binary
- `signature` - Signature from request headers
- `secret` - Webhook secret for this provider

## Returns

- `:ok` - Signature is valid
- `{:error, :invalid_signature}` - Signature verification failed

---

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