# Payment integration

The KASKO framework supports multiple payment providers through a pluggable payment handler system. This guide covers how to configure and use payment components in your webapp.

## Supported Payment Methods

| Method              | Description                         | Flow Type  |
| ------------------- | ----------------------------------- | ---------- |
| `free`              | No payment required (free products) | Immediate  |
| `distributor_web`   | Distributor-handled payments        | Immediate  |
| `stripe_intents`    | Stripe card payments with 3D Secure | Form-based |
| `stripe_sepa`       | SEPA Direct Debit via Stripe        | Form-based |
| `stripe_bancontact` | Bancontact via Stripe               | Redirect   |
| `paypal`            | PayPal via Braintree                | Popup      |
| `paypal_direct`     | Direct PayPal integration           | Redirect   |
| `postfinance`       | Swiss PostFinance                   | Redirect   |
| `slimpay`           | SlimPay SEPA processor              | Redirect   |
| `twikey`            | Direct bank transfer via Twikey     | Redirect   |

## Payment Components

### form-payment

The main payment form container that renders available payment methods as radio buttons. The user selects their preferred method, and the appropriate payment UI (card form, SEPA form, etc.) is displayed.

Available payment methods are determined by backend configuration, not by component config. The component only accepts `content_key` for labeling the payment method options.

```json
{
  "type": "form-payment",
  "config": {
    "content_key": {
      "payment_method_credit_card": "form.payment.credit_card",
      "payment_method_sepa": "form.payment.sepa",
      "payment_method_paypal": "form.payment.paypal",
      "payment_method_invoice": "form.payment.invoice",
      "payment_method_bancontact": "form.payment.bancontact",
      "payment_method_postfinance": "form.payment.postfinance",
      "payment_method_slimpay": "form.payment.slimpay",
      "payment_method_twikey": "form.payment.twikey"
    }
  }
}
```

Only include content keys for payment methods that are enabled for your product.

When a user selects a payment method, the value is stored in the `payment_method` input field (e.g., `creditcard/stripe_intents`, `sepa/stripe_sepa`, `paypal/paypal`). You can also pre-select a payment method using `default_values`:

```json
{
  "config": {
    "default_values": {
      "payment_method": "creditcard/stripe_intents"
    }
  }
}
```

### form-button-payment

The payment submission button. This triggers the payment flow when clicked.

```json
{
  "type": "form-button-payment",
  "config": {
    "content_key": "flow.payment.button"
  }
}
```

## Example Payment Screen

```json
{
  "path": "payment",
  "components": [
    {
      "type": "title",
      "config": {
        "content_key": "flow.payment.title"
      }
    },
    {
      "type": "form",
      "config": {
        "components": [
          {
            "type": "form-payment",
            "config": {
              "content_key": {
                "payment_method_credit_card": "form.payment.credit_card",
                "payment_method_paypal": "form.payment.paypal",
                "payment_method_invoice": "form.payment.invoice"
              }
            }
          }
        ],
        "footer_components": [
          {
            "type": "error-list"
          },
          {
            "type": "price-tag",
            "config": {
              "content_key": {
                "body": "flow.payment.price_body",
                "footer": "flow.payment.price_footer"
              }
            }
          },
          {
            "type": "button-back"
          },
          {
            "type": "form-button-payment",
            "config": {
              "content_key": "flow.payment.button"
            }
          }
        ]
      }
    }
  ],
  "next": "success"
}
```

## Payment Request Configuration

In the manifest, you must enable the `payment` request type:

```json
{
  "config": {
    "requests": [
      {
        "type": "quote",
        "version": "v2"
      },
      {
        "type": "policy",
        "version": "v2"
      },
      {
        "type": "payment"
      }
    ]
  }
}
```

## Payment Flow Types

### Form-based (Stripe Card, SEPA)

1. Payment form loads and mounts Stripe Elements
2. User enters card/IBAN details
3. User clicks payment button
4. Framework creates payment method with Stripe
5. If 3D Secure is required, user is redirected for authentication
6. Payment is completed and user proceeds to success screen

### Popup-based (PayPal)

1. User clicks PayPal button
2. PayPal popup window opens
3. User logs in and authorizes payment
4. Popup closes and returns payment token
5. Payment is completed

### Redirect-based (PostFinance, SlimPay, Twikey)

1. User clicks payment button
2. User is redirected to external payment provider
3. User completes payment on provider's site
4. User is redirected back to webapp
5. Framework verifies payment status

## Payment-Related Flags

These flags are available in [JsonLogic](https://docs.kasko.io/kasko-frontend-documentation/guides/jsonlogic) for conditional logic:

| Flag              | Type    | Description                             |
| ----------------- | ------- | --------------------------------------- |
| `is_3d_secure`    | boolean | 3D Secure authentication is in progress |
| `payment_back`    | boolean | User returned from payment redirect     |
| `payment_tbd`     | boolean | Payment is pending/to be determined     |
| `payment_fail`    | boolean | Payment has failed                      |
| `payment_success` | boolean | Payment completed successfully          |

Example usage:

```json
{
  "visibility_condition": {
    "type": "jsonlogic",
    "schema": {
      "===": [{"var": "flags.payment_success"}, true]
    }
  }
}
```

## Error Handling

Payment errors are displayed through the `error-list` component. Each payment method has specific error codes.

### Stripe Card Errors

| Error Code             | Content Key                                  | Description               |
| ---------------------- | -------------------------------------------- | ------------------------- |
| `incomplete_number`    | `form.cc_number.errors.incomplete_number`    | Card number is incomplete |
| `incomplete_expiry`    | `form.cc_expiry.errors.incomplete_expiry`    | Expiry date is incomplete |
| `incomplete_cvc`       | `form.cc_cvc.errors.incomplete_cvc`          | CVC is incomplete         |
| `invalid_number`       | `form.cc_number.errors.invalid_number`       | Card number is invalid    |
| `invalid_expiry_month` | `form.cc_expiry.errors.invalid_expiry_month` | Expiry month is invalid   |
| `invalid_cvc`          | `form.cc_cvc.errors.invalid_cvc`             | CVC is invalid            |
| `card_declined`        | `form.cc_number.errors.card_declined`        | Card was declined         |
| `expired_card`         | `form.cc_number.errors.expired_card`         | Card has expired          |
| `balance_insufficient` | `form.cc_number.errors.balance_insufficient` | Insufficient balance      |

### Stripe SEPA Errors

| Error Code                  | Content Key                                     | Description                 |
| --------------------------- | ----------------------------------------------- | --------------------------- |
| `incomplete_iban`           | `form.iban.errors.incomplete_iban`              | IBAN is incomplete          |
| `invalid_iban`              | `form.iban.errors.invalid_iban`                 | IBAN is invalid             |
| `invalid_iban_country_code` | `form.iban.errors.invalid_iban_country_code`    | Invalid country code        |
| `invalid_owner_name`        | `form.account_holder.errors.invalid_owner_name` | Invalid account holder name |

### PayPal Errors

| Error Code                 | Content Key                       | Description                     |
| -------------------------- | --------------------------------- | ------------------------------- |
| `PAYPAL_POPUP_CLOSED`      | `form.paypal.errors.popup_closed` | User closed the PayPal popup    |
| `PAYPAL_POPUP_OPEN_FAILED` | `form.paypal.errors.popup_failed` | Failed to open popup (blocked?) |
| `PAYPAL_FLOW_FAILED`       | `form.paypal.errors.flow_failed`  | PayPal authorization failed     |

## Content Keys for Payment

Standard content keys for payment screens:

```csv
"flow.payment.title","Payment"
"flow.payment.button","Pay Now"
"flow.payment.total","Total"
"form.cc_number.label","Card Number"
"form.cc_number.placeholder","1234 5678 9012 3456"
"form.cc_expiry.label","Expiry Date"
"form.cc_expiry.placeholder","MM/YY"
"form.cc_cvc.label","CVC"
"form.cc_cvc.placeholder","123"
"form.iban.label","IBAN"
"form.iban.placeholder","DE89 3704 0044 0532 0130 00"
"form.account_holder.label","Account Holder Name"
```

## Required Requests

For the success screen, you typically want to ensure payment has completed:

```json
{
  "path": "success",
  "required_requests": ["policy", "payment"],
  "flow_complete": true,
  "components": [...]
}
```

See the [required requests guide](https://docs.kasko.io/kasko-frontend-documentation/guides/required-requests) for more information.
