> ## Documentation Index
> Fetch the complete documentation index at: https://docs.gameball.co/llms.txt
> Use this file to discover all available pages before exploring further.

# Order Points Breakdown

> Explain how a customer earned their points on a specific order, item by item.

Retrieve a line-by-line explanation of how a customer earned points on a specific order: which items were eligible, the earning rate applied to each one, any campaign multiplier that boosted it, and how the per-item points add up to the total recorded on the order.

Use it to power a "why did I get these points?" receipt in your order-details screen, and to reconcile a customer's balance against a specific purchase.

This endpoint is available on `v4.0` and `v4.1`.

<Info>
  **Security:** Requires **apikey** and **secretkey** headers. The secret key is required on both `v4.0` and `v4.1`, whether or not High Security Mode is enabled on your account.
</Info>

### Headers

| Header      | Required | Value                                                                                                                                                       |
| ----------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `apikey`    | **Yes**  | Your Gameball API key.                                                                                                                                      |
| `secretkey` | **Yes**  | Your Gameball secret key. Always required on this endpoint, on both `v4.0` and `v4.1`.                                                                      |
| `lang`      | No       | Language code for localized names in the response (e.g. `en`, `ar`, `fr`). Defaults to your account's default language — see [Localization](#localization). |

### What the breakdown is built from

The breakdown explains the order's **earning** transaction — the `PaymentReward` transaction recorded when the order was processed. It is a read-only explanation of points that were already awarded, not a quote:

* To quote points **before** checkout, use [Calculate Order Cashback](/api-reference/order/calculate-order-cashback) or [Preview Order Rewards](/api-reference/order/preview-order-rewards).
* To list **every** transaction tied to an order (rewards, refunds, redemptions), use [Order Transactions](/api-reference/order/order-transactions).

An order that never earned points returns `404`. That happens when the order was never tracked, was dropped, had every line excluded from earning, or has not finished processing yet.

<Note>
  Orders are processed asynchronously. Immediately after [Order Tracking](/api-reference/order/order-tracking) returns `202`, the earning transaction may not exist yet and this endpoint returns `404`. Retry, or call it from a screen the customer opens after the order is complete.
</Note>

### Reading the item math

Each entry in `items` carries the full trace for one product line:

<Steps>
  <Step title="Eligibility">
    `eligible` says whether the line earned anything, and `eligibilityMode` says which rule decided it (`General`, `Include`, `Exclude`, `Merchant`, or `Custom`). When a line earned nothing, `ineligibleReason` explains why in plain language.
  </Step>

  <Step title="Money base">
    `eligibleAmount` is the amount points were calculated on, after `discount` and any tax or non-product exclusions. `lineSubtotal` is the pre-discount total, and `pricePerUnit` is that divided by `quantity`.
  </Step>

  <Step title="Rate">
    `baseRate` comes from the rule named by `sourceKind` and `sourceLabel` (the account's base rate, the customer's tier rate, or a custom rule). It is the dashboard rule expressed per unit of currency: a rule reading "earn **5** points for every **10** spent" arrives as `rewardFactor: 5`, `amountThreshold: 10`, and `baseRate: 0.5`. When a campaign applies, `campaignMultiplier` boosts it into `effectiveRate`.
  </Step>

  <Step title="Points">
    `basePoints` is what the line would have earned with no campaign; `itemPoints` is what it actually contributed.
  </Step>
</Steps>

### Rounding and reconciliation

`earnedPoints` is authoritative — it is the value recorded on the transaction and reflected in the customer's balance. `itemsExactTotal` is the exact, unrounded sum of the eligible lines, so the two can differ by a fraction of a point:

* **Campaign lines** are floored to whole points per line. `roundedPerLine` marks a line that lost a fraction this way.
* **Non-campaign lines** stay fractional and are floored once at the order total. `roundedDownAtOrderLevel` and `roundedDownAmount` report that drop.

`reconciles` is `true` when the item breakdown explains the recorded total. A `false` value means the stored line items do not fully account for `earnedPoints`, so present the order-level figures rather than the per-item math.

### Orders without line items

Orders recorded without line items return `hasItemBreakdown: false` and an empty `items` array. The order-level fields (`earnedPoints`, `orderAmount`, `tierName`, `redeemedPoints`, and the rest) are still populated.

### Redemptions

Points the customer redeemed on the order are reported at order level through `redeemedPoints`, `redeemedAmount`, and `hasRedemption`. Redemption value is already folded into the line discounts, so it is never attributed to a single item.

### Localization

Send the optional `lang` header to localize `tierName` and `items[].campaignName`. If the language is omitted or not configured in your account, the response falls back to your account's default language.


## OpenAPI

````yaml GET /api/v4.0/integrations/orders/{orderId}/points-breakdown
openapi: 3.1.0
info:
  title: Gameball API
  description: >-
    Gameball REST API v4.0 - Complete API reference for integrating loyalty,
    gamification, and customer engagement features
  version: 4.0.0
servers:
  - url: https://api.gameball.co
security:
  - bearerAuth: []
paths:
  /api/v4.0/integrations/orders/{orderId}/points-breakdown:
    get:
      tags:
        - Orders
      summary: Order Points Breakdown
      description: >-
        Returns a line-by-line explanation of how a customer earned their points
        on a specific order: which items were eligible, the earning rate applied
        to each one, any campaign multiplier that boosted it, and how the
        per-item points add up to the total recorded on the order's earning
        transaction.


        Use it to answer "why did I get these points?" in a receipt or
        order-details screen, and to reconcile a customer's balance against a
        specific purchase.


        The breakdown is built from the order's **earning** transaction
        (`PaymentReward`). An order that never earned points — dropped, fully
        excluded, or not yet processed — returns `404`.


        This endpoint is available on `v4.0` and `v4.1`.


        **Security:** Requires both `apikey` and `secretkey` headers. The secret
        key is required on both versions, whether or not High Security Mode is
        enabled on the account.


        **Localization:** Send the optional `lang` header to localize `tierName`
        and `items[].campaignName`.
      operationId: getOrderPointsBreakdown
      parameters:
        - name: orderId
          in: path
          required: true
          schema:
            type: string
          description: >-
            The order identifier in your system, the same value sent as
            `orderId` when the order was tracked. Case-sensitive.
          example: ORD12345
        - name: lang
          in: header
          required: false
          schema:
            type: string
          description: >-
            Language code used to localize `tierName` and `items[].campaignName`
            (e.g., `en`, `ar`, `fr`). If omitted or not configured in your
            account, the response falls back to your account's default language.
      responses:
        '200':
          description: Points breakdown retrieved successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/OrderPointsBreakdownResponse'
              examples:
                sample:
                  value:
                    transactionId: 11034754
                    transactionType: Payment Reward
                    isReversed: false
                    earnedPoints: 192
                    pointsValue: 19.2
                    orderAmount: 230
                    currency: SAR
                    customerId: '1214'
                    tierName: Gold
                    transactionTime: '2026-09-01T08:13:29.29'
                    expiryDate: '2027-09-01T00:00:00'
                    pointsBalanceBefore: 1340
                    excludeTaxes: true
                    excludeNonProductCosts: true
                    usedCouponCodes:
                      - WELCOME10
                    redeemedPoints: 200
                    redeemedAmount: 20
                    hasRedemption: true
                    items:
                      - title: Running Shoes
                        productId: P-100
                        sku: SHOE-42-BLK
                        quantity: 1
                        eligible: true
                        eligibilityMode: General
                        ineligibleReason: null
                        pricePerUnit: 180
                        lineSubtotal: 180
                        discount: 20
                        taxInDiscount: 0
                        totalDiscount: 20
                        eligibleAmount: 160
                        sourceKind: level
                        sourceLabel: Gold earning rate
                        ruleCondition: null
                        rewardFactor: 1
                        amountThreshold: 1
                        baseRate: 1
                        basePoints: 160
                        hasCampaign: true
                        campaignName: Double Points Week
                        campaignTierBand: 100–500 SAR
                        campaignCondition: order total price at least 100
                        campaignMultiplier: 1.2
                        effectiveRate: 1.2
                        itemPoints: 192
                        roundedPerLine: false
                      - title: Gift Card 50
                        productId: P-900
                        sku: GC-50
                        quantity: 1
                        eligible: false
                        eligibilityMode: Exclude
                        ineligibleReason: 'Excluded by the store''s rule: item product id is P-900'
                        pricePerUnit: 50
                        lineSubtotal: 50
                        discount: 0
                        taxInDiscount: 0
                        totalDiscount: 0
                        eligibleAmount: 50
                        sourceKind: base
                        sourceLabel: Base rate
                        ruleCondition: null
                        rewardFactor: 1
                        amountThreshold: 1
                        baseRate: 1
                        basePoints: 50
                        hasCampaign: false
                        campaignName: null
                        campaignTierBand: null
                        campaignCondition: null
                        campaignMultiplier: null
                        effectiveRate: 1
                        itemPoints: 0
                        roundedPerLine: false
                    itemsExactTotal: 192
                    roundedDownAtOrderLevel: false
                    roundedDownAmount: 0
                    reconciles: true
                    hasItemBreakdown: true
        '400':
          description: The `orderId` path parameter is missing or empty.
        '401':
          description: Missing or invalid API key or secret key.
        '404':
          description: >-
            No points-earning transaction exists for this order id. The order
            was never tracked, was dropped, earned nothing, or has not finished
            processing yet.
        '500':
          description: Internal server error.
      security:
        - apiKey: []
          secretKey: []
components:
  schemas:
    OrderPointsBreakdownResponse:
      type: object
      description: Item-by-item explanation of the points earned on one order.
      properties:
        transactionId:
          type: integer
          format: int64
          description: >-
            Gameball's internal identifier for the earning transaction this
            breakdown explains.
          example: 11034754
        transactionType:
          type: string
          description: Display name of the transaction type the breakdown was built from.
          example: Payment Reward
        isReversed:
          type: boolean
          description: >-
            `true` when the transaction type is a deduction (a reversal) rather
            than an earning.
          example: false
        earnedPoints:
          type: integer
          description: >-
            The points actually recorded on the transaction. This is the
            authoritative total; `itemsExactTotal` explains it.
          example: 192
        pointsValue:
          type:
            - number
            - 'null'
          description: >-
            Monetary value of the earned points, when the transaction recorded
            one.
          example: 19.2
        orderAmount:
          type:
            - number
            - 'null'
          description: The order amount the reward was calculated on.
          example: 230
        currency:
          type:
            - string
            - 'null'
          description: Currency of `orderAmount` and `pointsValue`.
          example: SAR
        customerId:
          type: string
          description: The customer's unique identifier in your system.
          example: '1214'
        tierName:
          type:
            - string
            - 'null'
          description: >-
            The tier the customer was in when the order was rewarded, localized
            by the `lang` header when available.
          example: Gold
        transactionTime:
          type: string
          format: date-time
          description: When the earning transaction was recorded.
          example: '2026-09-01T08:13:29.29'
        expiryDate:
          type:
            - string
            - 'null'
          format: date-time
          description: When these earned points expire, when points expiry is enabled.
          example: '2027-09-01T00:00:00'
        pointsBalanceBefore:
          type: integer
          description: The customer's points balance immediately before this transaction.
          example: 1340
        excludeTaxes:
          type: boolean
          description: Whether taxes were excluded from the earning base for this order.
          example: true
        excludeNonProductCosts:
          type: boolean
          description: >-
            Whether shipping and other non-product costs were excluded from the
            earning base.
          example: true
        usedCouponCodes:
          type: array
          description: Coupon codes applied to the order.
          items:
            type: string
          example:
            - WELCOME10
        redeemedPoints:
          type: integer
          description: >-
            Points the customer redeemed on this order. Redemption value is
            already folded into the line discounts, so it is reported at order
            level rather than attributed to any single line.
          example: 200
        redeemedAmount:
          type: number
          description: Monetary value of the redeemed points.
          example: 20
        hasRedemption:
          type: boolean
          description: '`true` when the order included a redemption.'
          example: true
        items:
          type: array
          description: >-
            Per-line breakdown. Empty when the order was recorded without line
            items.
          items:
            type: object
            description: >-
              One product line on the order and the full trace of how it
              contributed points.
            properties:
              title:
                type: string
                description: Product title as sent on the order line item.
                example: Running Shoes
              productId:
                type: string
                description: Product identifier in your system, as sent on the order.
                example: P-100
              sku:
                type:
                  - string
                  - 'null'
                description: >-
                  SKU taken from the stored order line item. `null` when the
                  order did not carry a SKU for this product.
                example: SHOE-42-BLK
              quantity:
                type: number
                description: >-
                  Quantity purchased on this line. Defaults to `1` when the
                  order did not specify one.
                example: 1
              eligible:
                type: boolean
                description: >-
                  Whether this line earned points. A line can be ineligible
                  because it matched an exclusion rule or failed an inclusion
                  rule.
                example: true
              eligibilityMode:
                type: string
                description: >-
                  Which earning-eligibility rule was evaluated for this line.
                  **General** - no include/exclude list applies. **Include** -
                  only listed products earn. **Exclude** - listed products are
                  skipped. **Merchant** - merchant-scoped rule. **Custom** - a
                  custom cashback rule.
                enum:
                  - General
                  - Include
                  - Exclude
                  - Merchant
                  - Custom
                example: General
              ineligibleReason:
                type:
                  - string
                  - 'null'
                description: >-
                  Human-readable reason the line earned nothing, built from the
                  stored rule conditions. `null` when `eligible` is `true`.
                example: 'Excluded by the store''s rule: item product id is P-900'
              pricePerUnit:
                type: number
                description: >-
                  Unit price before the line discount (`lineSubtotal` divided by
                  `quantity`).
                example: 180
              lineSubtotal:
                type: number
                description: >-
                  Line total before the discount was applied (`eligibleAmount` +
                  `discount`).
                example: 180
              discount:
                type: number
                description: >-
                  Product discount applied to this line, which reduced the
                  amount points were earned on.
                example: 20
              taxInDiscount:
                type: number
                description: Portion of the discount attributable to tax.
                example: 0
              totalDiscount:
                type: number
                description: '`discount` + `taxInDiscount`.'
                example: 20
              eligibleAmount:
                type: number
                description: >-
                  The money base points were actually calculated on for this
                  line, after discounts and any tax or non-product exclusions.
                example: 160
              sourceKind:
                type: string
                description: >-
                  Which earning rule supplied the base rate. **base** - the
                  account's default earning rate. **level** - the customer's
                  tier earning rate. **custom** - a custom cashback rule.
                enum:
                  - base
                  - level
                  - custom
                example: level
              sourceLabel:
                type: string
                description: >-
                  Display label for `sourceKind`, e.g. `Base rate`, `Gold
                  earning rate`, `Custom rule`.
                example: Gold earning rate
              ruleCondition:
                type:
                  - string
                  - 'null'
                description: >-
                  For a line that earned through a conditional custom rule, the
                  condition it satisfied. `null` for plain base or tier rules,
                  which apply to everything.
                example: null
              rewardFactor:
                type: number
                description: >-
                  The points figure configured on the dashboard rule. In a rule
                  reading "earn 5 points for every 10 spent", this is the 5.
                example: 1
              amountThreshold:
                type: number
                description: >-
                  The spend interval configured on the dashboard rule. In a rule
                  reading "earn 5 points for every 10 spent", this is the 10.
                  `baseRate` = `rewardFactor` / `amountThreshold`.
                example: 1
              baseRate:
                type: number
                description: >-
                  Points earned per single unit of currency spent, before any
                  campaign multiplier. For "5 points per 10 spent" this is
                  `0.5`.
                example: 1
              basePoints:
                type: number
                description: >-
                  `eligibleAmount` x `baseRate` - what the line would have
                  earned with no campaign.
                example: 160
              hasCampaign:
                type: boolean
                description: Whether a points-multiplier campaign boosted this line.
                example: true
              campaignName:
                type:
                  - string
                  - 'null'
                description: >-
                  Name of the campaign that boosted the line, localized by the
                  `lang` header when available. `null` when `hasCampaign` is
                  `false`.
                example: Double Points Week
              campaignTierBand:
                type:
                  - string
                  - 'null'
                description: >-
                  The campaign tier the order fell into, rendered as a readable
                  band (e.g. `100-500 SAR`, `201+ SAR`). `null` when the
                  campaign has no tiers.
                example: 100-500 SAR
              campaignCondition:
                type:
                  - string
                  - 'null'
                description: >-
                  The campaign condition the order matched, so the multiplier is
                  not unexplained. `null` when the campaign had no conditions.
                example: order total price at least 100
              campaignMultiplier:
                type:
                  - number
                  - 'null'
                description: >-
                  The multiplier the campaign applied on top of `baseRate`.
                  `null` when `hasCampaign` is `false`.
                example: 1.2
              effectiveRate:
                type: number
                description: >-
                  `baseRate` x `campaignMultiplier` - the rate actually used for
                  this line.
                example: 1.2
              itemPoints:
                type: number
                description: >-
                  Points this line contributed. `0` for ineligible lines.
                  Campaign lines are floored to whole points per line;
                  non-campaign lines stay fractional and are floored once at the
                  order level.
                example: 192
              roundedPerLine:
                type: boolean
                description: >-
                  `true` when this campaign line lost a fraction of a point to
                  per-line flooring.
                example: false
        itemsExactTotal:
          type: number
          description: >-
            Exact, unrounded sum of `items[].itemPoints` for eligible lines.
            Compare against `earnedPoints` to see rounding.
          example: 192
        roundedDownAtOrderLevel:
          type: boolean
          description: >-
            `true` when a non-campaign order lost a sub-point fraction to
            flooring at the order total.
          example: false
        roundedDownAmount:
          type: number
          description: >-
            The fraction of a point dropped by order-level flooring. `0` when
            nothing was dropped.
          example: 0
        reconciles:
          type: boolean
          description: >-
            `true` when `itemsExactTotal` explains `earnedPoints` (within one
            point). `false` means the stored line items do not fully account for
            the recorded total.
          example: true
        hasItemBreakdown:
          type: boolean
          description: >-
            `false` when the order was recorded without line items, in which
            case `items` is empty and only the order-level figures are
            meaningful.
          example: true
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
    apiKey:
      type: apiKey
      in: header
      name: apikey
    secretKey:
      type: apiKey
      in: header
      name: secretkey

````