> For the complete documentation index, see [llms.txt](https://docs.akinon.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.akinon.com/technical-guides/commerce/payment-option-rules.md).

# Payment Option Rules

Payment option rules determine whether a payment option is available to a user during checkout. Each rule evaluates the current state of the pre-order (basket, user, shipping, etc.) and either passes or raises an exception.

Rules are configured in the `config.rule` field of a Payment Option using JSON. The `klass` field specifies the rule class and `params` contains the rule's parameters.

```json
{
  "rule": {
    "klass": "omnishop.payments.rules.RuleClassName",
    "params": {
      "error_level": "soft",
      "error_message": "This payment option is not available."
    }
  }
}
```

### Common Parameters

All rules accept the following optional parameters:

| Parameter       | Type                 | Default  | Description                                                                                                                                                 |
| --------------- | -------------------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `error_level`   | `string`             | `"hard"` | `"soft"` shows the payment option as unavailable with an error message. `"hard"` hides it completely.                                                       |
| `error_message` | `string` or `object` | `""`     | Error message shown when `error_level` is `"soft"`. Can be a plain string or a localized object keyed by language code (e.g. `{"tr": "...", "en": "..."}`). |
| `error_code`    | `string`             | `"00"`   | A code to identify the error.                                                                                                                               |

***

## Composite Rules

Composite rules allow combining multiple rules with logical operators.

### AndRule

The payment option is available only if **all** child rules pass.

```json
{
  "klass": "omnishop.payments.rules.AndRule",
  "params": {
    "error_level": "soft",
    "error_message": "This payment option is not available.",
    "children": [
      {
        "klass": "omnishop.payments.rules.RuleA",
        "params": {}
      },
      {
        "klass": "omnishop.payments.rules.RuleB",
        "params": {}
      }
    ]
  }
}
```

| Parameter     | Type     | Required | Description                                                          |
| ------------- | -------- | -------- | -------------------------------------------------------------------- |
| `children`    | `array`  | Yes      | List of child rule objects, each with `klass` and `params`.          |
| `error_level` | `string` | No       | If set, overrides child error levels and forces a unified exception. |

### OrRule

The payment option is available if **at least one** child rule passes.

```json
{
  "klass": "omnishop.payments.rules.OrRule",
  "params": {
    "error_level": "hard",
    "children": [
      {
        "klass": "omnishop.payments.rules.RuleA",
        "params": {}
      },
      {
        "klass": "omnishop.payments.rules.RuleB",
        "params": {}
      }
    ]
  }
}
```

| Parameter  | Type    | Required | Description                                                 |
| ---------- | ------- | -------- | ----------------------------------------------------------- |
| `children` | `array` | Yes      | List of child rule objects, each with `klass` and `params`. |

### NotRule

Inverts a child rule. The payment option is available if the child rule **fails**.

```json
{
  "klass": "omnishop.payments.rules.NotRule",
  "params": {
    "child": {
      "klass": "omnishop.payments.rules.RegisteredUserRule",
      "params": {}
    }
  }
}
```

| Parameter | Type     | Required | Description                                     |
| --------- | -------- | -------- | ----------------------------------------------- |
| `child`   | `object` | Yes      | A single rule object with `klass` and `params`. |

***

## Basket Rules

### BasketAmountRule

The payment option is available only if the discounted basket total is greater than or equal to `min_total_amount`.

```json
{
  "klass": "omnishop.payments.rules.BasketAmountRule",
  "params": {
    "min_total_amount": "500.00"
  }
}
```

| Parameter          | Type     | Required | Description                       |
| ------------------ | -------- | -------- | --------------------------------- |
| `min_total_amount` | `string` | Yes      | Minimum discounted basket amount. |

### TotalProductAmountRule

The payment option is available only if the undiscounted basket total is greater than or equal to `min_total_amount`.

```json
{
  "klass": "omnishop.payments.rules.TotalProductAmountRule",
  "params": {
    "min_total_amount": "500.00"
  }
}
```

| Parameter          | Type     | Required | Description                         |
| ------------------ | -------- | -------- | ----------------------------------- |
| `min_total_amount` | `string` | Yes      | Minimum undiscounted basket amount. |

### BasketProductSkuRule

The payment option is **not** available if the basket contains a product with the specified SKU.

```json
{
  "klass": "omnishop.payments.rules.BasketProductSkuRule",
  "params": {
    "sku": "PRODUCT-SKU-123"
  }
}
```

| Parameter | Type     | Required | Description                                              |
| --------- | -------- | -------- | -------------------------------------------------------- |
| `sku`     | `string` | Yes      | The SKU of the product that should not be in the basket. |

### BasketProductsHasAttributeRule

The payment option is available only if basket products have the specified attribute key.

```json
{
  "klass": "omnishop.payments.rules.BasketProductsHasAttributeRule",
  "params": {
    "attribute_key": "is_digital",
    "mode": "all"
  }
}
```

To require at least one product to have the attribute:

```json
{
  "klass": "omnishop.payments.rules.BasketProductsHasAttributeRule",
  "params": {
    "attribute_key": "is_digital",
    "mode": "any"
  }
}
```

| Parameter       | Type     | Required | Description                                                                                                                                     |
| --------------- | -------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------- |
| `attribute_key` | `string` | Yes      | The product attribute key to check.                                                                                                             |
| `mode`          | `string` | No       | <p><code>"all"</code> (default): all products must have the attribute.<br><code>"any"</code>: at least one product must have the attribute.</p> |

### BasketProductsAttributeRule

The payment option is available only if basket products have the specified attribute key with the specified value.

```json
{
  "klass": "omnishop.payments.rules.BasketProductsAttributeRule",
  "params": {
    "attribute_key": "product_type",
    "attribute_value": "digital",
    "mode": "all"
  }
}
```

| Parameter         | Type     | Required | Description                                                                                                                                                   |
| ----------------- | -------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `attribute_key`   | `string` | Yes      | The product attribute key to check.                                                                                                                           |
| `attribute_value` | `any`    | Yes      | The expected value for the attribute.                                                                                                                         |
| `mode`            | `string` | No       | <p><code>"all"</code> (default): all products must match the attribute value.<br><code>"any"</code>: at least one product must match the attribute value.</p> |

### BasketHasTradableItemRule

The payment option is available only if the basket contains at least one tradable item. No parameters required.

```json
{
  "klass": "omnishop.payments.rules.BasketHasTradableItemRule",
  "params": {}
}
```

***

## User Rules

### LoginRequiredRule

The payment option is available only if the user is logged in. No parameters required.

```json
{
  "klass": "omnishop.payments.rules.LoginRequiredRule",
  "params": {}
}
```

### RegisteredUserRule

The payment option is available only if the user is a registered (non-guest) user. No parameters required.

```json
{
  "klass": "omnishop.payments.rules.RegisteredUserRule",
  "params": {}
}
```

### UserRegisteredAndHasValidPhoneNumberRule

The payment option is available only if the user is registered and has a valid phone number. No parameters required.

```json
{
  "klass": "omnishop.payments.rules.UserRegisteredAndHasValidPhoneNumberRule",
  "params": {}
}
```

### SavedCreditCardRule

The payment option is available only if the user is logged in and has at least one saved credit card.

```json
{
  "klass": "omnishop.payments.rules.SavedCreditCardRule",
  "params": {
    "filter_by_pos": false
  }
}
```

| Parameter       | Type      | Required | Description                                                                                           |
| --------------- | --------- | -------- | ----------------------------------------------------------------------------------------------------- |
| `filter_by_pos` | `boolean` | No       | If `true`, checks only for saved cards associated with the payment option's POS. Defaults to `false`. |

### StoredCardRequiredRule

The payment option is available only if the user is logged in and has stored cards in the configured POS gateway. No parameters required.

```json
{
  "klass": "omnishop.payments.rules.StoredCardRequiredRule",
  "params": {}
}
```

***

## Shipping Rules

### PayOnDeliveryRule

The payment option is available only if the selected shipping option's slug is in the allowed list.

```json
{
  "klass": "omnishop.payments.rules.PayOnDeliveryRule",
  "params": {
    "available_shipping_options": ["standard-delivery", "express-delivery"]
  }
}
```

| Parameter                    | Type    | Required | Description                            |
| ---------------------------- | ------- | -------- | -------------------------------------- |
| `available_shipping_options` | `array` | Yes      | List of allowed shipping option slugs. |

### ShippingCityRule

The payment option is available based on the city of the shipping address.

```json
{
  "klass": "omnishop.payments.rules.ShippingCityRule",
  "params": {
    "cities": [1, 2, 3],
    "exclude": false
  }
}
```

| Parameter | Type      | Required | Description                                                                                                                                         |
| --------- | --------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------- |
| `cities`  | `array`   | Yes      | List of city IDs.                                                                                                                                   |
| `exclude` | `boolean` | No       | If `false` (default), the payment option is available only for listed cities. If `true`, it is available for all cities **except** the listed ones. |

### ShippingOptionRule

The payment option is available only if the selected shipping option matches the specified name or slug.

```json
{
  "klass": "omnishop.payments.rules.ShippingOptionRule",
  "params": {
    "slug": "standard-delivery"
  }
}
```

| Parameter | Type     | Required | Description                    |
| --------- | -------- | -------- | ------------------------------ |
| `name`    | `string` | No\*     | Shipping option name to match. |
| `slug`    | `string` | No\*     | Shipping option slug to match. |

\* At least one of `name` or `slug` must be provided.

### ShippingOptionPageRule

The payment option is available only if the active checkout shipping option selection page matches the specified page type. Useful when certain payment options should only appear on specific checkout flows.

```json
{
  "klass": "omnishop.payments.rules.ShippingOptionPageRule",
  "params": {
    "page": "DataSourceShippingOptionSelectionPage"
  }
}
```

| Parameter | Type     | Required | Description                                                                                                                                                                                                                                                                                                                                 |
| --------- | -------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `page`    | `string` | No       | <p>The checkout shipping page type to match. Defaults to <code>"ShippingOptionSelectionPage"</code>.<br>Available values: <code>"ShippingOptionSelectionPage"</code>, <code>"DataSourceShippingOptionSelectionPage"</code>, <code>"AttributeBasedShippingOptionSelectionPage"</code>, <code>"RemoteShippingOptionSelectionPage"</code>.</p> |

### RetailStoreStockRule

The payment option is available only if retail store stock is confirmed for the basket items based on the shipping address location.

```json
{
  "klass": "omnishop.payments.rules.RetailStoreStockRule",
  "params": {
    "use_city": true,
    "use_township": true,
    "use_county": false,
    "use_district": false,
    "extra_params": {}
  }
}
```

| Parameter      | Type      | Required | Description                                                               |
| -------------- | --------- | -------- | ------------------------------------------------------------------------- |
| `use_city`     | `boolean` | No       | Use the city from the shipping address as a tag. Defaults to `false`.     |
| `use_township` | `boolean` | No       | Use the township from the shipping address as a tag. Defaults to `false`. |
| `use_county`   | `boolean` | No       | Use the county from the shipping address as a tag. Defaults to `false`.   |
| `use_district` | `boolean` | No       | Use the district from the shipping address as a tag. Defaults to `false`. |
| `extra_params` | `object`  | No       | Additional parameters passed to the stock control service.                |

***

## Order Rules

### OnlyOnePayOnDeliveryRule

The payment option is available only if the user has no active pay-on-delivery orders. Prevents multiple concurrent cash-on-delivery orders. No parameters required.

```json
{
  "klass": "omnishop.payments.rules.OnlyOnePayOnDeliveryRule",
  "params": {}
}
```

### RecentOrderCountLimitRule

Limits usage based on the user's order count within the specified time period. The payment option is unavailable if the user has placed `max_order_count` or more orders in the last `period_hours` hours.

Orders with `cancelled`, `refunded`, or `merged` statuses are excluded from the count.

```json
{
  "klass": "omnishop.payments.rules.RecentOrderCountLimitRule",
  "params": {
    "max_order_count": 5,
    "period_hours": 24,
    "use_same_payment_option": false
  }
}
```

| Parameter                 | Type      | Required | Description                                                                                  |
| ------------------------- | --------- | -------- | -------------------------------------------------------------------------------------------- |
| `max_order_count`         | `integer` | Yes      | Maximum number of orders allowed within the period.                                          |
| `period_hours`            | `integer` | Yes      | The time window in hours to look back (e.g. `24` for daily, `168` for weekly).               |
| `use_same_payment_option` | `boolean` | No       | If `true`, only orders placed with the same payment option are counted. Defaults to `false`. |

### RecentOrderAmountLimitRule

Limits usage based on the user's total order amount within the specified time period. The payment option is unavailable if the user's total order amount reaches or exceeds `max_total_order_amount` in the last `period_hours` hours.

Orders with `cancelled`, `refunded`, or `merged` statuses are excluded from the total.

```json
{
  "klass": "omnishop.payments.rules.RecentOrderAmountLimitRule",
  "params": {
    "max_total_order_amount": "200000.00",
    "period_hours": 48,
    "use_same_payment_option": false
  }
}
```

| Parameter                 | Type      | Required | Description                                                                                                |
| ------------------------- | --------- | -------- | ---------------------------------------------------------------------------------------------------------- |
| `max_total_order_amount`  | `string`  | Yes      | Maximum total order amount allowed within the period.                                                      |
| `period_hours`            | `integer` | Yes      | The time window in hours to look back (e.g. `24` for daily, `168` for weekly).                             |
| `use_same_payment_option` | `boolean` | No       | If `true`, only orders placed with the same payment option are included in the total. Defaults to `false`. |

***

## Other Rules

### CurrencyRule

The payment option is available based on the order currency.

```json
{
  "klass": "omnishop.payments.rules.CurrencyRule",
  "params": {
    "currencies": ["try", "usd"],
    "exclude": false
  }
}
```

| Parameter    | Type      | Required | Description                                                                                                                                                 |
| ------------ | --------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `currencies` | `array`   | Yes      | List of currency codes.                                                                                                                                     |
| `exclude`    | `boolean` | No       | If `false` (default), the payment option is available only for listed currencies. If `true`, it is available for all currencies **except** the listed ones. |

### ClientTypeRule

The payment option is available only if the basket's client type is in the allowed list.

```json
{
  "klass": "omnishop.payments.rules.ClientTypeRule",
  "params": {
    "clients": ["b2b", "instore"]
  }
}
```

| Parameter | Type    | Required | Description                                                                  |
| --------- | ------- | -------- | ---------------------------------------------------------------------------- |
| `clients` | `array` | Yes      | List of allowed client type values (e.g. `"default"`, `"b2b"`, `"instore"`). |

### LoyaltyMoneyRule

The payment option is available only if loyalty money is enabled and covers the full order amount. No parameters required.

```json
{
  "klass": "omnishop.payments.rules.LoyaltyMoneyRule",
  "params": {}
}
```

### GiftCardRule

The payment option is available only if the basket has gift card reservations that cover the full order amount. No parameters required.

```json
{
  "klass": "omnishop.payments.rules.GiftCardRule",
  "params": {}
}
```

### PostCheckoutRule

The payment option is available only during post-checkout (after an order has been created). No parameters required.

```json
{
  "klass": "omnishop.payments.rules.PostCheckoutRule",
  "params": {}
}
```

### B2BPaymentRule

The payment option is available only if the request contains a valid B2B authorization header (`X-B2B`). The header value is verified against a hash of the basket items and the configured `B2B_EXTENSION_CONF` password. No parameters required.

```json
{
  "klass": "omnishop.payments.rules.B2BPaymentRule",
  "params": {}
}
```

### LiquerRule

A flexible rule that evaluates a custom query using the liquery DSL against the pre-order context.

```json
{
  "klass": "omnishop.payments.rules.LiquerRule",
  "params": {
    "query": {
      "basket__user_id": 123
    }
  }
}
```

| Parameter | Type     | Required | Description                                                                        |
| --------- | -------- | -------- | ---------------------------------------------------------------------------------- |
| `query`   | `object` | Yes      | A liquery DSL query object evaluated against `basket`, `pre_order`, and `request`. |


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.akinon.com/technical-guides/commerce/payment-option-rules.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
