> ## 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.

# How Do I Redeem Points at Checkout with Gameball POS (v4)?

> Let customers apply their loyalty points as a discount at checkout

Redemption lets a customer spend their points to reduce what they pay. It builds directly on [Track Orders](https://docs.gameball.co/installation-guides/v4/pos/track-orders.md): you add a **hold** step that locks the points, then submit the **same order call** with a reference to that hold. The hold prevents double-spending and guarantees the points are reserved for this transaction only.

> [!NOTE]
>
> If you haven't implemented [Track Orders](https://docs.gameball.co/installation-guides/v4/pos/track-orders.md) yet, do that first. Redemption is the order call plus one extra step.

## The Redemption Flow

```mermaid theme={null}
sequenceDiagram
    participant C as Cashier / POS
    participant G as Gameball API
    C->>G: GET balance
    G-->>C: availablePointsBalance
    C->>G: POST hold points
    G-->>C: holdReference (locked, time-limited)
    C->>G: POST order + holdReference
    G-->>C: pointsRedeemed, rewardedPoints
```

**1. Check the balance**

Retrieve the customer's [balance](https://docs.gameball.co/installation-guides/v4/pos/customer-balance.md) to confirm they have enough points to redeem.

**2. Hold the points**

Reserve the redemption amount with the Hold Points API. This returns a `holdReference`.

**3. Submit the order with the hold reference**

Place the order using the [Track Orders](https://docs.gameball.co/installation-guides/v4/pos/track-orders.md) call, adding a `redemption` block that references the hold.

## Step 1: Hold the Points

This reserves the points temporarily before checkout completes:

```bash cURL theme={null}
curl -X POST 'https://api.gameball.co/api/v4.0/integrations/transactions/hold' \
  -H 'Content-Type: application/json' \
  -H 'APIKey: YOUR_API_KEY' \
  -H 'SecretKey: YOUR_SECRET_KEY' \
  -d '{
    "customerId": "12345",
    "transactionTime": "2025-10-19T12:00:00Z",
    "pointsToHold": 100
  }'
```

```json Success theme={null}
{
  "customerId": "12345",
  "holdAmount": "10.00",
  "holdEquivalentPoints": 100,
  "holdReference": "HOLD-abc123"
}
```

> [!WARNING]
>
> Holds are **time-limited** (typically 10 minutes). If the order isn't completed in time, the points are automatically released back to the customer. Don't reuse or delay using a `holdReference`.

## Step 2: Submit the Order with the Redemption

This is the standard [Track Orders](https://docs.gameball.co/installation-guides/v4/pos/track-orders.md) call with one addition, a `redemption` block carrying the hold reference. Note that `totalPaid` reflects the discounted amount:

```bash cURL theme={null}
curl -X POST 'https://api.gameball.co/api/v4.0/integrations/orders' \
  -H 'Content-Type: application/json' \
  -H 'APIKey: YOUR_API_KEY' \
  -H 'SecretKey: YOUR_SECRET_KEY' \
  -d '{
    "customerId": "12345",
    "orderId": "ORD000123",
    "orderDate": "2025-10-19T12:10:00Z",
    "totalPaid": 90.00,
    "totalPrice": 100.00,
    "redemption": {
      "pointsHoldReference": "HOLD-abc123"
    }
  }'
```

```json Success theme={null}
{
  "orderId": "ORD000123",
  "customerId": "12345",
  "pointsRedeemed": 100,
  "pointsEarned": 9,
  "rewardedPoints": 9,
  "status": "completed"
}
```

> [!NOTE]
>
> **Behind the scenes**, Gameball verifies the hold reference, deducts the redeemed points, and rewards new points based on the amount actually paid after redemption, then updates the customer's redemption and earning history.

## Tips & Gotchas

* `totalPaid` must reflect the discounted value **after** applying the held points.
* `totalPrice` should always be the original order value **before** discounts.
* If the customer cancels or abandons the transaction, release the hold using the Release Hold API.

## Redemption Methods

> [tab] Standard
>
> The flow above, where the customer is identified by `customerId` (mobile number, email, or CRM ID) and you hold then redeem against their balance.

> [tab] QR Code
>
> Instead of typing a phone number, the cashier scans a QR code the customer shows from their **Gameball widget/app** or their **Virtual Pass**. The QR encodes both *who* the customer is and a *one-time security token*, so the customer is identified and verified in a single scan, no separate lookup needed.
>
> #### How it works
>
> ```mermaid theme={null}
> flowchart TD
>     A[Customer shows QR code] --> B[POS scans and reads the value]
>     B --> C[Split the value into<br/>customerId and hash]
>     C --> D[POST hold points with the hash]
>     D --> E[POST order with the holdReference]
> ```
>
> **1. Scan the QR code**
>
> The scanned value is a single string that joins the customer ID and a rotating 6-digit hash.
>
> **2. Split the value**
>
> The **last 6 digits are always the hash**. Everything before them is the `customerId`. There's no separator, so split by position.
>
> **3. Hold points with the hash**
>
> Pass both the parsed `customerId` and the `hash` to the Hold Points call. The hash proves the request is genuine.
>
> **4. Submit the order**
>
> Complete the order with the returned `holdReference`, exactly like the Standard flow.
>
> #### Anatomy of the scanned value
>
> Take the example value `mobile_966500001234123456`:
>
> | Part | Value | How to extract it |
> | - | - | - |
> | `customerId` | `mobile_966500001234` | Everything **except** the last 6 characters |
> | `hash` | `123456` | The **last 6 characters** |
>
> #### Hold points with the hash
>
> Add the `hash` field to the Hold Points request:
>
> ```bash cURL theme={null}
> curl -X POST 'https://api.gameball.co/api/v4.0/integrations/transactions/hold' \
>   -H 'Content-Type: application/json' \
>   -H 'APIKey: YOUR_API_KEY' \
>   -H 'SecretKey: YOUR_SECRET_KEY' \
>   -d '{
>     "customerId": "mobile_966500001234",
>     "transactionTime": "2025-10-19T12:00:00Z",
>     "pointsToHold": 1000,
>     "hash": "123456"
>   }'
> ```
>
> > [!WARNING]
> >
> > The hash is a **rotating, single-use security token**, it changes regularly and expires. Only send it in the Hold Points call, and never store or reuse an old hash. If a scan fails validation, ask the customer to refresh their QR code and scan again.
>
> > [!TIP]
> >
> > The same hash can also be generated server-side via the [Get Customer Hash API](https://docs.gameball.co/api-reference/customers/management/get-customer-hash.md) if you need to validate a customer without a live scan.

> [tab] Virtual Pass
>
> Gameball Virtual Pass lets customers use QR codes without a mobile app. The pass lives in Apple Wallet (iOS) or PassWallet (Android) and behaves exactly like an app-based QR code.
>
> * No additional API integration needed, use the same QR flow above.
> * Ensure your POS scanners can read digital screens and long string formats.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.