---
title: 'Manage rule-level points on your side'
description: 'Snag does not store or expose per-rule point totals. Learn how to track and query rule-level points in your own storage using webhooks and periodic sync.'
keywords: ["rule level points", "adjust rule rewards", "custom point values", "per-rule points"]
---

> **For AI agents:** the complete documentation index is at [llms.txt](https://docs.snagsolutions.io/llms.txt). Append `.md` to any page URL for its markdown version.

## Overview

Snag maintains an immutable loyalty ledger and accurate per-currency balances for each user. We do not store or expose the total points a user earned from a single loyalty rule ("rule-level points").

<Warning>
  We don't provide any endpoint to fetch "points by rule" for one user or a list
  of users. If you need rule-level totals, you should track and store them in
  your own system.
</Warning>

<Info>
  What we do provide: a complete transaction stream and balance updates. You can
  reliably derive per-rule totals by consuming transaction events and persisting
  aggregates keyed by `(userId, loyaltyRuleId)` on your side.
</Info>

## Recommended approach

At a high level, you should:

- Ingest new transactions in real time via subscriptions → webhooks
- Periodically reconcile using the transactions listing endpoint
- Maintain idempotent, append-only processing in your datastore

<Steps>
<Step title="Receive new transactions via webhooks">
Enable a subscription for `LoyaltyTransactionEntry` and deliver events to your webhook endpoint. See [Subscriptions](https://docs.snagsolutions.io/stratus/subscriptions) and [Webhooks](https://docs.snagsolutions.io/stratus/webhooks).

<Warning>
`LoyaltyTransactionEntry` may not always include a `loyaltyRuleId` (e.g., manual adjustments). Skip entries without a rule when calculating rule-level totals.
</Warning>
</Step>

<Step title="Reconcile periodically">
  Run a periodic job to fetch recent entries and backfill anything missed by
  your webhook consumer. See [Get Loyalty Transaction
  Entries](https://docs.snagsolutions.io/api-reference/loyalty/get-loyalty-transaction-entries).
</Step>

<Step title="Store minimal aggregates on your side">
- Keep a lightweight aggregate keyed by `(userId, loyaltyRuleId)`
- Apply credits and debits accordingly
- Deduplicate using `entry.id` or `idempotencyKey`
</Step>
</Steps>

## FAQ

<AccordionGroup>
<Accordion title="Can Snag add an endpoint to return points per rule?">
No. Snag's source of truth is the ledger and account balances. Aggregations by rule are intentionally left to partner systems so you can shape them to your business logic and retention needs.
</Accordion>

<Accordion title="How do I avoid counting the same transaction twice?">
  Use `entry.id` or `idempotencyKey` to deduplicate. Keep a simple record of
  processed entries and make your updates idempotent.
</Accordion>

<Accordion title="What about debits or refunds?">
  Entries include a `direction` of `credit` or `debit`. Apply debits as negative
  adjustments to your stored totals.
</Accordion>

<Accordion title="What if a webhook is missed?">
This is why the periodic reconciliation step exists. Use `startingAfter` with the last processed `entry.id` to fetch any missed entries and catch up exactly once.
</Accordion>
</AccordionGroup>

## Related docs

- [Subscriptions](https://docs.snagsolutions.io/stratus/subscriptions)
- [Webhooks](https://docs.snagsolutions.io/stratus/webhooks)
- [Get loyalty transaction entries — API reference](https://docs.snagsolutions.io/api-reference/loyalty/get-loyalty-transaction-entries)
- [Checking Rule Completion Status](https://docs.snagsolutions.io/loyalty/check-rule-completion-status)

<Check>
  You now have a reliable pattern to calculate, store, and query rule-level
  point totals using Snag's transaction stream.
</Check>
