# loyalty (https://docs.salla.dev/twilight/react/api/modules/loyalty)



Use `loyalty` to show the store's loyalty program, or the customer's points on the cart page.

```tsx title="app/components/cart/CartPage.tsx"
import { useQuery } from '@tanstack/react-query';
import { loyalty } from '@salla.sa/twilight-theme-engine/api/loyalty';

export function LoyaltyPoints() {
  const { data: loyaltyPoints } = useQuery(loyalty.queries.points());

  return loyaltyPoints ? <p>{loyaltyPoints} points</p> : null;
}
```

```ts title="app/routes/loyalty.tsx"
import { loyalty } from '@salla.sa/twilight-theme-engine/api/loyalty';

loader: async () => {
  const data = await loyalty.getOrThrow();
  return { page: { slug: 'loyalty', title: data.name }, loyalty: data };
},
```

## Methods [#methods]

| Method                     | Parameters | Returns            | Request                                | Login needed                                               |
| -------------------------- | ---------- | ------------------ | -------------------------------------- | ---------------------------------------------------------- |
| `loyalty.get`              | none       | `Promise<Loyalty>` | `GET loyalty` (reads `data`)           | The module does not check; `customer` is `null` for guests |
| `loyalty.getOrThrow`       | none       | `Promise<Loyalty>` | Same as `get`                          | Same                                                       |
| `loyalty.getPointsBalance` | none       | `Promise<number>`  | `GET balance/points` (reads `balance`) | Yes                                                        |

## Queries [#queries]

| Query                      | Key                     | Notes                                         |
| -------------------------- | ----------------------- | --------------------------------------------- |
| `loyalty.queries.detail()` | `['loyalty']`           | Calls `get`                                   |
| `loyalty.queries.points()` | `['loyalty', 'points']` | Runs only when a token exists; fresh for 30 s |

Neither key includes the locale or the scope. The program text follows the request's language, so after a client-side language switch call `invalidateQueries`.

## Gotchas [#gotchas]

* **Guests and points.** `queries.points()` is off without a token, because the call would fail with `token_not_provided`. Calling `getPointsBalance()` as a guest throws `HTTPError`.
* **`getOrThrow` only handles 404 and 410.** Those become a not-found page; a 401 or a 500 reaches the error boundary as usual.
* **Fresh points.** After an action that changes points (an order, a redeem) call `queryClient.invalidateQueries({ queryKey: loyalty.queries.points().queryKey })`.
* **No mutations.** The module has no redeem or join method.

## See also [#see-also]

* [Loyalty route](https://docs.salla.dev/twilight/react/routes/loyalty)
* [cart](https://docs.salla.dev/twilight/react/api/modules/cart)
* [Authentication and scope](https://docs.salla.dev/twilight/react/api/authentication-and-scope)
