# Loyalty points
Documentation: next (source: develop).

Install the preview: `pnpm add @aephia/atlas-kit@next`. These docs follow develop and may include changes not yet published to npm.

> The Loyalty Point system — points within your faction, and each epoch's ATLAS split by your share.

Markdown source of https://develop.atlas-kit-docs.pages.dev/guides/loyalty/ — see https://develop.atlas-kit-docs.pages.dev/ai/ for the full machine-readable surface.

Loyalty tracks what a player has contributed to their faction over a period,
and what that has accumulated. Reads and actions are separate capability-only
entries; neither is composed into the root client.

```ts
import {
  getLoyaltyEpoch,
  getLoyaltyContributionsByProfile,
} from '@aephia/atlas-kit/loyalty';
```

:::game[A loyalty epoch is one reward round]
A loyalty epoch is a fixed period in which players earn points for helping
their faction. Every UTC day, the game sets aside a small part of the player
reward treasury for each faction. How much a faction receives that day depends
on how many starbases it controls at the end of the day. Certain activities
earn loyalty points for players during the epoch. When the epoch ends, those
points automatically determine each player's share of their faction's ATLAS
reward.
:::

## Epochs bound everything

A loyalty epoch is a window. Contributions belong to one, and reading a
contribution without knowing its epoch tells you less than it looks like it
does.

```ts
const epochs = await getLoyaltyEpochsByFaction(ctx, factionId);
const contributions = await getLoyaltyContributionsByProfile(
  ctx,
  profileAddress,
);
```

> **Runnable example — Read loyalty epochs and contributions.** The loyalty epochs of a faction, and one profile contributions. Run it in the browser at https://develop.atlas-kit-docs.pages.dev/guides/loyalty/.

## Lifecycle is projected

An epoch's state — upcoming, running, concluded — is **derived deterministically**
from the epoch's own timing rather than read from a status field. The SDK
computes it so that every consumer computes it the same way, rather than each
application inventing slightly different boundary handling.

## ATLAS banks

Accumulated rewards sit in a bank:

```ts
const bank = await maybeGetLoyaltyAtlasBank(ctx, profileAddress, factionId);
```

`maybe` because a profile that has never contributed has no bank. Absence is an
answer.

## Claim the full ATLAS balance

The action entry plans one full-balance claim. It deliberately has no amount
input: the loaded Bank's exact raw balance is the claim amount. Supply an
explicit Unix timestamp for deterministic expiry validation and address-only
authorization:

```ts
import { planClaimLoyaltyAtlas } from '@aephia/atlas-kit/loyalty/actions';

if (bank) {
  const plan = await planClaimLoyaltyAtlas(ctx, bank, {
    atUnixSeconds: 1_786_000_000n,
    authorization,
  });
  console.log(plan.describe());
}
```

The result is an inert `Plan`; planning does not sign or submit. Permission,
final freshness, and concurrent claims remain chain-authoritative.

## Gotchas

**Contributions are per epoch.** Summing across epochs is your job, and whether
that sum is meaningful depends on what you are asking.

**Amounts are `bigint`.** ATLAS values in particular are large.

**A concluded epoch still reads.** Its data does not disappear when it ends.
Check the projected lifecycle rather than assuming a readable epoch is the
current one.

## Reference

- [`loyalty`](/reference/loyalty/) — every export in this entry
- [`loyalty/actions`](/reference/loyalty/actions/) — full-balance claim planning
- [`factions`](/guides/factions/) — the faction being contributed to
- [`rewards`](/guides/rewards/) — the other ATLAS-denominated capability
