---
title: "Update earning rule"
method: PUT
path: "/v2/loyalties/earning-rules/{earningRuleId}"
tags: ["Earning Rules"]
---

# Update earning rule

`PUT /v2/loyalties/earning-rules/{earningRuleId}`

## Request

- Base URL: `https://api.voucherify.io`
- URL: `https://api.voucherify.io/v2/loyalties/earning-rules/{earningRuleId}`
- Auth: one of:
  - API key in header `X-App-Id` and API key in header `X-App-Token`
  - HTTP bearer

<Info>

<Badge color="gray">Documentation in progress</Badge>

This documentation is in progress. The parameters, fields, request and response bodies, and other data may be subject to change. If you need more information or you want to share feedback, contact [Voucherify support](https://www.voucherify.io/contact-support) or your Technical Account Manager.

</Info>

Updates an earning rule. All properties are optional; `status` cannot be changed
through this endpoint (use the activate/deactivate/draft endpoints). For rules that
are not in `DRAFT` status, only the following properties may effectively change:
name, earnings, error, validity_hours, start_date, end_date, trigger_limits, earning_limits, metadata.
Earnings items may carry an `id` (`lernei_...`) to update an existing earning item;
items without an `id` are created.

## Request body

- V2LoyaltiesEarningRulesUpdateRequestBody: Request body for updating an earning rule. All properties are optional; `status` is not updatable here.
  - `error` LoyaltyV2ActivityEarningRuleError: Custom error message configuration.
    - `message` string, required: Error message shown when validation fails.
  - `start_date` string, date-time, nullable: Date-time from which the rule is active. Can be `null`. When both `start_date` and `end_date` are set, `start_date` must be earlier than `end_date`.
  - `end_date` string, date-time, nullable: Date-time until which the rule is active. Can be `null`.
  - `metadata` LoyaltyV2ActivityMetadata: Arbitrary key-value metadata; any JSON object is accepted.
  - `name` string: Earning rule name.
  - `trigger` EarningRuleTrigger: Event that triggers the earning rule. Depending on `event`, either `custom_event` or `segment` is required and the other trigger contexts must be `null`/absent.
    - `event` 'customer.order.paid' | 'customer.custom_event' | 'customer.segment.entered', required: Triggering event type.
    - `custom_event` LoyaltyV2ActivityEarningRuleTriggerCustomEvent: Custom event trigger configuration.
      - `schema_id` string, required: Custom event schema ID (`ms_...`).
    - `segment` LoyaltyV2ActivityEarningRuleTriggerSegment: Segment trigger configuration.
      - `id` string, required: Segment ID (`seg_...`).
  - `earnings` EarningRuleEarningUpdate[]: Earning definitions. Items with an `id` update existing earning items; items without an `id` are created. Omitted existing items are removed.
    - `rules` EarningRuleRulesGroup: Group of rule definitions combined by a logical formula. Besides `logic`, only positive-integer keys are allowed (property names must match `^[1-9]\d*$`), each referencing a rule definition. The `logic` value is a logical expression referencing the numbered rules, e.g. `"1 and 2"` or `"1 and (2 or 3)"`. At least one numbered rule is required (`minProperties: 2` including `logic`).
      - `logic` string, required: Logical expression combining the numbered rule definitions, e.g. `"1 and 2"`.
    - `effects` EarningRuleEffect[], required: Lists the effects applied when the rules match. Required. Contains 1 to 10 effects.
      - `type` 'POINTS' | 'POINTS_PROPORTIONAL' | 'BENEFIT', required: Effect type.
      - `points` EarningRuleEffectPoints: Fixed points effect - awards a fixed number of points to a card definition.
        - `value` integer, required: Fixed number of points to award.
        - `card_definition_id` string, required: Card definition ID (`lcdef_...`) the points are awarded to.
        - `points_expiration` EarningRuleEffectPointsExpiration: Points expiration override. Depending on `type`, exactly one of `rolling_expiration`, `calendar_expiration` or `sliding_expiration` is required; for `NO_EXPIRATION` all three must be null/absent.
          - `type` 'NO_EXPIRATION' | 'ROLLING_EXPIRATION' | 'CALENDAR_EXPIRATION' | 'SLIDING_EXPIRATION', required: Points expiration type.
          - `rolling_expiration` EarningRuleEffectPointsExpirationRollingExpiration: Rolling expiration - points expire a fixed period after earning.
            - `period` LoyaltyV2ActivityEarningRuleEffectPointsExpirationRollingExpirationPeriod, required: Rolling expiration period. The maximum `value` depends on `unit`: `DAY` - 90, `MONTH` - 12, `YEAR` - 5.
              - …
            - `rounding` LoyaltyV2ActivityEarningRuleEffectPointsExpirationRollingExpirationRounding: `value` is the month (1-12). Required when `type` is `END_OF_PARTICULAR_MONTH`. Absent for other rounding types.
              - …
          - `calendar_expiration` EarningRuleEffectPointsExpirationCalendarExpiration: Calendar expiration - points expire on fixed calendar dates (1 to 20 dates).
            - `expiration_dates` LoyaltyV2ActivityEarningRuleEffectPointsExpirationCalendarExpirationDate[], required: Fixed expiration dates (day + month).
              - …
          - `sliding_expiration` EarningRuleEffectPointsExpirationSlidingExpiration: Sliding expiration. Points expire after a period of member inactivity.
            - `earning_activity` boolean, required: Whether earning activity resets the expiration window.
            - `period` LoyaltyV2ActivityEarningRuleEffectPointsExpirationSlidingExpirationPeriod, required: Sliding expiration inactivity period. The maximum `value` depends on `unit`: `DAY` - 90, `MONTH` - 12, `YEAR` - 1.
              - …
      - `points_proportional` EarningRuleEffectPointsProportional: Proportional points effect - awards points using an "every X gives Y points" formula. Depending on `calculation_type`, one specific configuration object is required and the others must be null/absent: - `PRE_DISCOUNT_ORDER_AMOUNT`: requires `order.amount` - `POST_DISCOUNT_ORDER_AMOUNT`: requires `order.total_amount` - `ORDER_METADATA_VALUE`: requires `order.metadata` - `CUSTOMER_METADATA_VALUE`: requires `customer.metadata` - `CUSTOM_EVENT_METADATA_VALUE`: requires `custom_event.metadata` - `PRE_DISCOUNT_ORDER_ITEMS_AMOUNT`: requires `order_items.amount` - `POST_DISCOUNT_ORDER_ITEMS_AMOUNT`: requires `order_items.subtotal_amount` - `ORDER_ITEMS_QUANTITY`: requires `order_items.quantity` The trigger further restricts allowed calculation types: `customer.order.paid` allows all order/order-items types plus `CUSTOMER_METADATA_VALUE`; `customer.custom_event` allows `CUSTOMER_METADATA_VALUE` and `CUSTOM_EVENT_METADATA_VALUE`; `customer.segment.entered` allows only `CUSTOMER_METADATA_VALUE`.
        - `calculation_type` 'PRE_DISCOUNT_ORDER_AMOUNT' | 'POST_DISCOUNT_ORDER_AMOUNT' | 'PRE_DISCOUNT_ORDER_ITEMS_AMOUNT' | 'POST_DISCOUNT_ORDER_ITEMS_AMOUNT' | 'ORDER_ITEMS_QUANTITY' | 'ORDER_METADATA_VALUE' | 'CUSTOMER_METADATA_VALUE' | 'CUSTOM_EVENT_METADATA_VALUE', required: How the proportional points are calculated.
        - `card_definition_id` string, required: Card definition ID (`lcdef_...`) the points are awarded to.
        - `points_expiration` EarningRuleEffectPointsExpiration: Points expiration override. Depending on `type`, exactly one of `rolling_expiration`, `calendar_expiration` or `sliding_expiration` is required; for `NO_EXPIRATION` all three must be null/absent.
          - `type` 'NO_EXPIRATION' | 'ROLLING_EXPIRATION' | 'CALENDAR_EXPIRATION' | 'SLIDING_EXPIRATION', required: Points expiration type.
          - `rolling_expiration` EarningRuleEffectPointsExpirationRollingExpiration: Rolling expiration - points expire a fixed period after earning.
            - `period` LoyaltyV2ActivityEarningRuleEffectPointsExpirationRollingExpirationPeriod, required: Rolling expiration period. The maximum `value` depends on `unit`: `DAY` - 90, `MONTH` - 12, `YEAR` - 5.
              - …
            - `rounding` LoyaltyV2ActivityEarningRuleEffectPointsExpirationRollingExpirationRounding: `value` is the month (1-12). Required when `type` is `END_OF_PARTICULAR_MONTH`. Absent for other rounding types.
              - …
          - `calendar_expiration` EarningRuleEffectPointsExpirationCalendarExpiration: Calendar expiration - points expire on fixed calendar dates (1 to 20 dates).
            - `expiration_dates` LoyaltyV2ActivityEarningRuleEffectPointsExpirationCalendarExpirationDate[], required: Fixed expiration dates (day + month).
              - …
          - `sliding_expiration` EarningRuleEffectPointsExpirationSlidingExpiration: Sliding expiration. Points expire after a period of member inactivity.
            - `earning_activity` boolean, required: Whether earning activity resets the expiration window.
            - `period` LoyaltyV2ActivityEarningRuleEffectPointsExpirationSlidingExpirationPeriod, required: Sliding expiration inactivity period. The maximum `value` depends on `unit`: `DAY` - 90, `MONTH` - 12, `YEAR` - 1.
              - …
        - `order` EarningRulePointsProportionalOrder: Order-based proportional calculation configuration. `amount` is used by `PRE_DISCOUNT_ORDER_AMOUNT`, `total_amount` by `POST_DISCOUNT_ORDER_AMOUNT` and `metadata` by `ORDER_METADATA_VALUE`.
          - `amount` LoyaltyV2ActivityEarningRulePointsProportionalEvery: "Every X gives Y points" formula based on an amount.
            - `every` integer, required: The divisor – every this amount (e.g. in cents) awards `value` points.
            - `value` number, required: Points awarded per `every` unit.
          - `total_amount` LoyaltyV2ActivityEarningRulePointsProportionalEvery: "Every X gives Y points" formula based on an amount.
            - `every` integer, required: The divisor – every this amount (e.g. in cents) awards `value` points.
            - `value` number, required: Points awarded per `every` unit.
          - `metadata` LoyaltyV2ActivityEarningRulePointsProportionalMetadata: "Every X gives Y points" formula based on a numeric metadata property.
            - `every` integer, required: The divisor – every this metadata value awards `value` points.
            - `value` number, required: Points awarded per `every` unit.
            - `property` string, required: Metadata property name holding the numeric value.
        - `customer` EarningRulePointsProportionalCustomer
          - `metadata` LoyaltyV2ActivityEarningRulePointsProportionalMetadata, required: "Every X gives Y points" formula based on a numeric metadata property.
            - `every` integer, required: The divisor – every this metadata value awards `value` points.
            - `value` number, required: Points awarded per `every` unit.
            - `property` string, required: Metadata property name holding the numeric value.
        - `custom_event` EarningRulePointsProportionalCustomEvent
          - `metadata` LoyaltyV2ActivityEarningRulePointsProportionalMetadata, required: "Every X gives Y points" formula based on a numeric metadata property.
            - `every` integer, required: The divisor – every this metadata value awards `value` points.
            - `value` number, required: Points awarded per `every` unit.
            - `property` string, required: Metadata property name holding the numeric value.
        - `order_items` EarningRulePointsProportionalOrderItems: Order items based proportional calculation configuration. `amount` is used by `PRE_DISCOUNT_ORDER_ITEMS_AMOUNT`, `subtotal_amount` by `POST_DISCOUNT_ORDER_ITEMS_AMOUNT` and `quantity` by `ORDER_ITEMS_QUANTITY`.
          - `amount` EarningRulePointsProportionalOrderItemsCalculation: Order items based calculation - "every X gives Y points" applied to items matching the `applicable_to` criteria.
            - `every` integer, required: The divisor - every this amount/quantity awards `value` points.
            - `value` number, required: Points awarded per `every` unit.
            - `applicable_to` EarningRulePointsProportionalApplicableTo[], required: Product/SKU/collection criteria selecting matching order items.
              - …
          - `subtotal_amount` EarningRulePointsProportionalOrderItemsCalculation: Order items based calculation - "every X gives Y points" applied to items matching the `applicable_to` criteria.
            - `every` integer, required: The divisor - every this amount/quantity awards `value` points.
            - `value` number, required: Points awarded per `every` unit.
            - `applicable_to` EarningRulePointsProportionalApplicableTo[], required: Product/SKU/collection criteria selecting matching order items.
              - …
          - `quantity` EarningRulePointsProportionalOrderItemsCalculation: Order items based calculation - "every X gives Y points" applied to items matching the `applicable_to` criteria.
            - `every` integer, required: The divisor - every this amount/quantity awards `value` points.
            - `value` number, required: Points awarded per `every` unit.
            - `applicable_to` EarningRulePointsProportionalApplicableTo[], required: Product/SKU/collection criteria selecting matching order items.
              - …
      - `benefit` LoyaltyV2ActivityEarningRuleEffectBenefit: Benefit effect - grants a predefined benefit.
        - `id` string, required: Benefit ID (`lben_...`).
    - `name` string, nullable: Optional earning item name. Can be `null`.
    - `tier_rules` EarningRuleTierRules: Tier requirements for an earning. With `NO_REQUIREMENTS`, `any_of` must be null/absent. With `ANY_OF`, `any_of` is required (at least one entry) and the member must be in any of the listed tiers to earn.
      - `type` 'NO_REQUIREMENTS' | 'ANY_OF', required: Tier requirement type.
      - `any_of` LoyaltyV2ActivityEarningRuleTierRulesAnyOfEntry[], nullable: Tier structure/tier combinations, any of which satisfies the requirement. Can be `null`.
        - `tier_structure_id` string, required: Tier structure ID (`lts_...`).
        - `tier_ids` string[], required: Qualifying tier IDs (`lt_...`).
    - `id` string: Existing earning item ID (`lernei_...`). Omit to create a new item.
  - `validity_hours` EarningRuleValidityHours: Hours during which the earning rule is active. With `ANY_TIME`, `daily` must be null/absent. With `DAILY`, `daily` is required (at least one entry).
    - `type` 'DAILY' | 'ANY_TIME', required: Validity hours type.
    - `daily` LoyaltyV2ActivityEarningRuleValidityDailyHours[], nullable: Daily validity windows. Can be `null`.
      - `days_of_week` integer[], required: Days of week (0 = Sunday ... 6 = Saturday). Items must be unique.
      - `start_time` string, required: Window start time in `HH:mm` format.
      - `end_time` string, required: Window end time in `HH:mm` format.
  - `trigger_limits` EarningRuleTriggerLimits: Cooldown and frequency limits applied to the earning rule trigger.
    - `cooldown` EarningRuleTriggerLimitsCooldown: Cooldown between consecutive triggers per member. With `NO_COOLDOWN`, `fixed_cooldown` must be null/absent. With `FIXED_COOLDOWN`, `fixed_cooldown` is required.
      - `type` 'NO_COOLDOWN' | 'FIXED_COOLDOWN', required: Cooldown type.
      - `fixed_cooldown` EarningRuleTriggerLimitsCooldownFixedCooldown: Fixed cooldown period configuration.
        - `period` LoyaltyV2ActivityEarningRuleTriggerLimitsCooldownFixedCooldownPeriod, required: Cooldown period. The maximum `value` depends on `unit`: `HOUR` - 24, `DAY` - 90, `WEEK` - 52, `MONTH` - 12, `YEAR` - 1.
          - `value` integer, required: Period length. Maximum depends on `unit`: 24 for HOUR, 90 for DAY, 52 for WEEK, 12 for MONTH, 1 for YEAR.
          - `unit` 'HOUR' | 'DAY' | 'WEEK' | 'MONTH' | 'YEAR', required: Period unit.
    - `frequency` EarningRuleTriggerLimitsFrequency: Frequency limit for triggers per member. With `NO_LIMIT`, `limits` must be null or an empty array. With `LIMITED`, `limits` is required and must contain exactly one limit.
      - `type` 'NO_LIMIT' | 'LIMITED', required: Frequency limit type.
      - `limits` EarningRuleTriggerLimitsFrequencyLimit[], nullable: Frequency limits (at most one). Can be `null`.
        - `type` 'TIME_BASED', required: Frequency limit variant.
        - `period` EarningRuleTriggerLimitsFrequencyLimitTimeBasedPeriod, required: Time-based frequency limit period. Currently only `CURRENT_PERIOD` is supported; when selected, `current_period` is required.
          - `type` 'CURRENT_PERIOD', required: Period type.
          - `current_period` LoyaltyV2ActivityEarningRuleTriggerLimitsFrequencyLimitTimeBasedCurrentPeriod: Current calendar period unit for the frequency limit.
            - `unit` 'DAY' | 'WEEK' | 'MONTH' | 'QUARTER' | 'YEAR', required: Calendar period unit.
        - `triggers` LoyaltyV2ActivityEarningRuleTriggerLimitsFrequencyLimitTimeBasedTriggers, required: Maximum number of triggers allowed within the period.
          - `max` integer, required: Maximum number of triggers per period.

## Response `200`

Updated earning rule

- V2LoyaltiesEarningRulesUpdateResponseBody: Earning rule as returned by the API.
  - `id` string, required: Earning rule ID (`lern_...`).
  - `name` string, required: Earning rule name.
  - `status` 'DRAFT' | 'ACTIVE' | 'INACTIVE', required: Current status. `DELETED` also exists internally but deleted rules are excluded from API reads.
  - `earnings` EarningRuleEarning[], required: Earning definitions of the rule. Contains at least one earning.
    - `id` string, required: Earning item ID (`lernei_...`).
    - `name` string, nullable: Earning item name. Can be `null`.
    - `rules` EarningRuleRulesGroup: Group of rule definitions combined by a logical formula. Besides `logic`, only positive-integer keys are allowed (property names must match `^[1-9]\d*$`), each referencing a rule definition. The `logic` value is a logical expression referencing the numbered rules, e.g. `"1 and 2"` or `"1 and (2 or 3)"`. At least one numbered rule is required (`minProperties: 2` including `logic`).
      - `logic` string, required: Logical expression combining the numbered rule definitions, e.g. `"1 and 2"`.
    - `tier_rules` EarningRuleTierRules, required: Tier requirements for an earning. With `NO_REQUIREMENTS`, `any_of` must be null/absent. With `ANY_OF`, `any_of` is required (at least one entry) and the member must be in any of the listed tiers to earn.
      - `type` 'NO_REQUIREMENTS' | 'ANY_OF', required: Tier requirement type.
      - `any_of` LoyaltyV2ActivityEarningRuleTierRulesAnyOfEntry[], nullable: Tier structure/tier combinations, any of which satisfies the requirement. Can be `null`.
        - `tier_structure_id` string, required: Tier structure ID (`lts_...`).
        - `tier_ids` string[], required: Qualifying tier IDs (`lt_...`).
    - `effects` EarningRuleEffect[], required: Effects applied when the rules match. Contains 1 to 10 effects.
      - `type` 'POINTS' | 'POINTS_PROPORTIONAL' | 'BENEFIT', required: Effect type.
      - `points` EarningRuleEffectPoints: Fixed points effect - awards a fixed number of points to a card definition.
        - `value` integer, required: Fixed number of points to award.
        - `card_definition_id` string, required: Card definition ID (`lcdef_...`) the points are awarded to.
        - `points_expiration` EarningRuleEffectPointsExpiration: Points expiration override. Depending on `type`, exactly one of `rolling_expiration`, `calendar_expiration` or `sliding_expiration` is required; for `NO_EXPIRATION` all three must be null/absent.
          - `type` 'NO_EXPIRATION' | 'ROLLING_EXPIRATION' | 'CALENDAR_EXPIRATION' | 'SLIDING_EXPIRATION', required: Points expiration type.
          - `rolling_expiration` EarningRuleEffectPointsExpirationRollingExpiration: Rolling expiration - points expire a fixed period after earning.
            - `period` LoyaltyV2ActivityEarningRuleEffectPointsExpirationRollingExpirationPeriod, required: Rolling expiration period. The maximum `value` depends on `unit`: `DAY` - 90, `MONTH` - 12, `YEAR` - 5.
              - …
            - `rounding` LoyaltyV2ActivityEarningRuleEffectPointsExpirationRollingExpirationRounding: `value` is the month (1-12). Required when `type` is `END_OF_PARTICULAR_MONTH`. Absent for other rounding types.
              - …
          - `calendar_expiration` EarningRuleEffectPointsExpirationCalendarExpiration: Calendar expiration - points expire on fixed calendar dates (1 to 20 dates).
            - `expiration_dates` LoyaltyV2ActivityEarningRuleEffectPointsExpirationCalendarExpirationDate[], required: Fixed expiration dates (day + month).
              - …
          - `sliding_expiration` EarningRuleEffectPointsExpirationSlidingExpiration: Sliding expiration. Points expire after a period of member inactivity.
            - `earning_activity` boolean, required: Whether earning activity resets the expiration window.
            - `period` LoyaltyV2ActivityEarningRuleEffectPointsExpirationSlidingExpirationPeriod, required: Sliding expiration inactivity period. The maximum `value` depends on `unit`: `DAY` - 90, `MONTH` - 12, `YEAR` - 1.
              - …
      - `points_proportional` EarningRuleEffectPointsProportional: Proportional points effect - awards points using an "every X gives Y points" formula. Depending on `calculation_type`, one specific configuration object is required and the others must be null/absent: - `PRE_DISCOUNT_ORDER_AMOUNT`: requires `order.amount` - `POST_DISCOUNT_ORDER_AMOUNT`: requires `order.total_amount` - `ORDER_METADATA_VALUE`: requires `order.metadata` - `CUSTOMER_METADATA_VALUE`: requires `customer.metadata` - `CUSTOM_EVENT_METADATA_VALUE`: requires `custom_event.metadata` - `PRE_DISCOUNT_ORDER_ITEMS_AMOUNT`: requires `order_items.amount` - `POST_DISCOUNT_ORDER_ITEMS_AMOUNT`: requires `order_items.subtotal_amount` - `ORDER_ITEMS_QUANTITY`: requires `order_items.quantity` The trigger further restricts allowed calculation types: `customer.order.paid` allows all order/order-items types plus `CUSTOMER_METADATA_VALUE`; `customer.custom_event` allows `CUSTOMER_METADATA_VALUE` and `CUSTOM_EVENT_METADATA_VALUE`; `customer.segment.entered` allows only `CUSTOMER_METADATA_VALUE`.
        - `calculation_type` 'PRE_DISCOUNT_ORDER_AMOUNT' | 'POST_DISCOUNT_ORDER_AMOUNT' | 'PRE_DISCOUNT_ORDER_ITEMS_AMOUNT' | 'POST_DISCOUNT_ORDER_ITEMS_AMOUNT' | 'ORDER_ITEMS_QUANTITY' | 'ORDER_METADATA_VALUE' | 'CUSTOMER_METADATA_VALUE' | 'CUSTOM_EVENT_METADATA_VALUE', required: How the proportional points are calculated.
        - `card_definition_id` string, required: Card definition ID (`lcdef_...`) the points are awarded to.
        - `points_expiration` EarningRuleEffectPointsExpiration: Points expiration override. Depending on `type`, exactly one of `rolling_expiration`, `calendar_expiration` or `sliding_expiration` is required; for `NO_EXPIRATION` all three must be null/absent.
          - `type` 'NO_EXPIRATION' | 'ROLLING_EXPIRATION' | 'CALENDAR_EXPIRATION' | 'SLIDING_EXPIRATION', required: Points expiration type.
          - `rolling_expiration` EarningRuleEffectPointsExpirationRollingExpiration: Rolling expiration - points expire a fixed period after earning.
            - `period` LoyaltyV2ActivityEarningRuleEffectPointsExpirationRollingExpirationPeriod, required: Rolling expiration period. The maximum `value` depends on `unit`: `DAY` - 90, `MONTH` - 12, `YEAR` - 5.
              - …
            - `rounding` LoyaltyV2ActivityEarningRuleEffectPointsExpirationRollingExpirationRounding: `value` is the month (1-12). Required when `type` is `END_OF_PARTICULAR_MONTH`. Absent for other rounding types.
              - …
          - `calendar_expiration` EarningRuleEffectPointsExpirationCalendarExpiration: Calendar expiration - points expire on fixed calendar dates (1 to 20 dates).
            - `expiration_dates` LoyaltyV2ActivityEarningRuleEffectPointsExpirationCalendarExpirationDate[], required: Fixed expiration dates (day + month).
              - …
          - `sliding_expiration` EarningRuleEffectPointsExpirationSlidingExpiration: Sliding expiration. Points expire after a period of member inactivity.
            - `earning_activity` boolean, required: Whether earning activity resets the expiration window.
            - `period` LoyaltyV2ActivityEarningRuleEffectPointsExpirationSlidingExpirationPeriod, required: Sliding expiration inactivity period. The maximum `value` depends on `unit`: `DAY` - 90, `MONTH` - 12, `YEAR` - 1.
              - …
        - `order` EarningRulePointsProportionalOrder: Order-based proportional calculation configuration. `amount` is used by `PRE_DISCOUNT_ORDER_AMOUNT`, `total_amount` by `POST_DISCOUNT_ORDER_AMOUNT` and `metadata` by `ORDER_METADATA_VALUE`.
          - `amount` LoyaltyV2ActivityEarningRulePointsProportionalEvery: "Every X gives Y points" formula based on an amount.
            - `every` integer, required: The divisor – every this amount (e.g. in cents) awards `value` points.
            - `value` number, required: Points awarded per `every` unit.
          - `total_amount` LoyaltyV2ActivityEarningRulePointsProportionalEvery: "Every X gives Y points" formula based on an amount.
            - `every` integer, required: The divisor – every this amount (e.g. in cents) awards `value` points.
            - `value` number, required: Points awarded per `every` unit.
          - `metadata` LoyaltyV2ActivityEarningRulePointsProportionalMetadata: "Every X gives Y points" formula based on a numeric metadata property.
            - `every` integer, required: The divisor – every this metadata value awards `value` points.
            - `value` number, required: Points awarded per `every` unit.
            - `property` string, required: Metadata property name holding the numeric value.
        - `customer` EarningRulePointsProportionalCustomer
          - `metadata` LoyaltyV2ActivityEarningRulePointsProportionalMetadata, required: "Every X gives Y points" formula based on a numeric metadata property.
            - `every` integer, required: The divisor – every this metadata value awards `value` points.
            - `value` number, required: Points awarded per `every` unit.
            - `property` string, required: Metadata property name holding the numeric value.
        - `custom_event` EarningRulePointsProportionalCustomEvent
          - `metadata` LoyaltyV2ActivityEarningRulePointsProportionalMetadata, required: "Every X gives Y points" formula based on a numeric metadata property.
            - `every` integer, required: The divisor – every this metadata value awards `value` points.
            - `value` number, required: Points awarded per `every` unit.
            - `property` string, required: Metadata property name holding the numeric value.
        - `order_items` EarningRulePointsProportionalOrderItems: Order items based proportional calculation configuration. `amount` is used by `PRE_DISCOUNT_ORDER_ITEMS_AMOUNT`, `subtotal_amount` by `POST_DISCOUNT_ORDER_ITEMS_AMOUNT` and `quantity` by `ORDER_ITEMS_QUANTITY`.
          - `amount` EarningRulePointsProportionalOrderItemsCalculation: Order items based calculation - "every X gives Y points" applied to items matching the `applicable_to` criteria.
            - `every` integer, required: The divisor - every this amount/quantity awards `value` points.
            - `value` number, required: Points awarded per `every` unit.
            - `applicable_to` EarningRulePointsProportionalApplicableTo[], required: Product/SKU/collection criteria selecting matching order items.
              - …
          - `subtotal_amount` EarningRulePointsProportionalOrderItemsCalculation: Order items based calculation - "every X gives Y points" applied to items matching the `applicable_to` criteria.
            - `every` integer, required: The divisor - every this amount/quantity awards `value` points.
            - `value` number, required: Points awarded per `every` unit.
            - `applicable_to` EarningRulePointsProportionalApplicableTo[], required: Product/SKU/collection criteria selecting matching order items.
              - …
          - `quantity` EarningRulePointsProportionalOrderItemsCalculation: Order items based calculation - "every X gives Y points" applied to items matching the `applicable_to` criteria.
            - `every` integer, required: The divisor - every this amount/quantity awards `value` points.
            - `value` number, required: Points awarded per `every` unit.
            - `applicable_to` EarningRulePointsProportionalApplicableTo[], required: Product/SKU/collection criteria selecting matching order items.
              - …
      - `benefit` LoyaltyV2ActivityEarningRuleEffectBenefit: Benefit effect - grants a predefined benefit.
        - `id` string, required: Benefit ID (`lben_...`).
  - `trigger` EarningRuleTrigger, required: Event that triggers the earning rule. Depending on `event`, either `custom_event` or `segment` is required and the other trigger contexts must be `null`/absent.
    - `event` 'customer.order.paid' | 'customer.custom_event' | 'customer.segment.entered', required: Triggering event type.
    - `custom_event` LoyaltyV2ActivityEarningRuleTriggerCustomEvent: Custom event trigger configuration.
      - `schema_id` string, required: Custom event schema ID (`ms_...`).
    - `segment` LoyaltyV2ActivityEarningRuleTriggerSegment: Segment trigger configuration.
      - `id` string, required: Segment ID (`seg_...`).
  - `error` LoyaltyV2ActivityEarningRuleError: Custom error message configuration.
    - `message` string, required: Error message shown when validation fails.
  - `validity_hours` EarningRuleValidityHours, required: Hours during which the earning rule is active. With `ANY_TIME`, `daily` must be null/absent. With `DAILY`, `daily` is required (at least one entry).
    - `type` 'DAILY' | 'ANY_TIME', required: Validity hours type.
    - `daily` LoyaltyV2ActivityEarningRuleValidityDailyHours[], nullable: Daily validity windows. Can be `null`.
      - `days_of_week` integer[], required: Days of week (0 = Sunday ... 6 = Saturday). Items must be unique.
      - `start_time` string, required: Window start time in `HH:mm` format.
      - `end_time` string, required: Window end time in `HH:mm` format.
  - `start_date` string, date-time, nullable, required: Date-time from which the rule is active. Can be `null`.
  - `end_date` string, date-time, nullable, required: Date-time until which the rule is active. Can be `null`.
  - `trigger_limits` object, required: Cooldown and frequency limits applied to the earning rule trigger.
    - `cooldown` object, required: Cooldown between consecutive triggers per member. With `NO_COOLDOWN`, `fixed_cooldown` must be null/absent. With `FIXED_COOLDOWN`, `fixed_cooldown` is required.
      - `type` 'NO_COOLDOWN' | 'FIXED_COOLDOWN', required: Cooldown type.
      - `fixed_cooldown` EarningRuleTriggerLimitsCooldownFixedCooldown: Fixed cooldown period configuration.
        - `period` LoyaltyV2ActivityEarningRuleTriggerLimitsCooldownFixedCooldownPeriod, required: Cooldown period. The maximum `value` depends on `unit`: `HOUR` - 24, `DAY` - 90, `WEEK` - 52, `MONTH` - 12, `YEAR` - 1.
          - `value` integer, required: Period length. Maximum depends on `unit`: 24 for HOUR, 90 for DAY, 52 for WEEK, 12 for MONTH, 1 for YEAR.
          - `unit` 'HOUR' | 'DAY' | 'WEEK' | 'MONTH' | 'YEAR', required: Period unit.
    - `frequency` object, required: Frequency limit for triggers per member. With `NO_LIMIT`, `limits` must be null or an empty array. With `LIMITED`, `limits` is required and must contain exactly one limit.
      - `type` 'NO_LIMIT' | 'LIMITED', required: Frequency limit type.
      - `limits` EarningRuleTriggerLimitsFrequencyLimit[], nullable: Frequency limits (at most one). Can be `null`.
        - `type` 'TIME_BASED', required: Frequency limit variant.
        - `period` EarningRuleTriggerLimitsFrequencyLimitTimeBasedPeriod, required: Time-based frequency limit period. Currently only `CURRENT_PERIOD` is supported; when selected, `current_period` is required.
          - `type` 'CURRENT_PERIOD', required: Period type.
          - `current_period` LoyaltyV2ActivityEarningRuleTriggerLimitsFrequencyLimitTimeBasedCurrentPeriod: Current calendar period unit for the frequency limit.
            - `unit` 'DAY' | 'WEEK' | 'MONTH' | 'QUARTER' | 'YEAR', required: Calendar period unit.
        - `triggers` LoyaltyV2ActivityEarningRuleTriggerLimitsFrequencyLimitTimeBasedTriggers, required: Maximum number of triggers allowed within the period.
          - `max` integer, required: Maximum number of triggers per period.
  - `earning_limits` LoyaltyV2ActivityEarningRuleEarningLimits, required: Limits on points earned through this rule. Always present. Defaults to `{ "global": { "type": "NO_LIMIT", "limits": [] } }`. Unlike card definition earning limits, this object has no `transactions` key.
    - `global` LoyaltyV2ActivityEarningRuleEarningLimitsGlobal, required: Global (per member, across this rule) earning limits. With `NO_LIMIT`, `limits` is an empty array. With `LIMITED`, `limits` contains exactly one `TIME_BASED` limit.
      - `type` 'NO_LIMIT' | 'LIMITED', required: Whether global earning limits apply.
      - `limits` LoyaltyV2ActivityEarningRuleEarningLimitsGlobalLimit[]: Earning limits (at most one). Empty array when `type` is `NO_LIMIT`.
        - `type` 'TIME_BASED', required: Earning limit variant.
        - `period` LoyaltyV2ActivityEarningRuleEarningLimitsGlobalTimeBasedPeriod, required: Time-based earning limit period. Currently only `CURRENT_PERIOD` is supported; when selected, `current_period` is required.
          - `type` 'CURRENT_PERIOD', required: Period type.
          - `current_period` LoyaltyV2ActivityEarningRuleEarningLimitsGlobalTimeBasedCurrentPeriod: Current calendar period unit for the earning limit.
            - `unit` 'DAY' | 'WEEK' | 'MONTH' | 'QUARTER' | 'YEAR', required: Calendar period unit.
        - `points` LoyaltyV2ActivityEarningRuleEarningLimitsGlobalTimeBasedPoints, required: Maximum points that can be earned in the period.
          - `max` integer, required: Maximum points in the period.
  - `metadata` LoyaltyV2ActivityMetadata, required: Arbitrary key-value metadata; any JSON object is accepted.
  - `created_at` string, date-time, required: Creation timestamp (ISO 8601).
  - `updated_at` string, date-time, nullable, required: Last update timestamp (ISO 8601). `null` when never updated.
  - `object` 'earning_rule', required: Object type marker. Always `earning_rule`.

## Other responses

- `400`: Validation error - request body or query parameters failed validation, or the operation is not allowed in the current resource state.
- `404`: Resource not found.
- `409`: Conflict - e.g. duplicate resource or invalid state transition.
- `500`: Internal server error.

## Changes

- **2026-10-14** (v2) `d29b33490051`: 10 breaking, 9 warning, 8 info
  - added `#/components/schemas/EarningRuleRequestBase, subschema #2` to the `allOf[#/components/schemas/EarningRuleUpdateRequest]/` request property `allOf` list
  - the `allOf[#/components/schemas/EarningRuleUpdateRequest]/` request property type changed from `object` to no type
  - the `allOf[#/components/schemas/EarningRuleResponse]/earnings/items/effects/items/allOf[subschema #3]/then/points_proportional/custom_event` response's property type changed from `object` to no type for status `200`
  - the `allOf[#/components/schemas/EarningRuleResponse]/earnings/items/effects/items/allOf[subschema #3]/then/points_proportional/customer` response's property type changed from `object` to no type for status `200`
  - …23 more
- …earlier changes not shown

[Operation history](https://skmtc.dev/voucherifyio/apis/voucherify-loyalty-v2-api/changes/v2/loyalties/earning-rules/:earningRuleId/put.md)

---

[API](https://skmtc.dev/voucherifyio/apis/voucherify-loyalty-v2-api.md) - [All operations](https://skmtc.dev/voucherifyio/apis/voucherify-loyalty-v2-api/llms.txt) - [OpenAPI document](https://skmtc.dev/voucherifyio/apis/voucherify-loyalty-v2-api/revisions/e0d9f2d2532f?raw)
