# Loyalty program configuration
> Source: /guides/patterns/program-configuration
> Manage programs, tiers, benefits, multipliers and join pages as code.

The largest part of the Partner API is loyalty configuration: programs, tiers
and benefits together account for over forty operations. This is the pattern
for managing them from source control rather than by hand.

## The surfaces [#the-surfaces]

<Steps>
  <Step title="Programs">
    `loyalty/programs` — create as a draft, update, then activate. Only an
    active program delivers anything.
  </Step>
  <Step title="Tiers">
    `loyalty/tiers` — the tier ladder, its ordering, and per-tier settings such
    as an earn multiplier or a booking rate code.
  </Step>
  <Step title="Benefits">
    `loyalty/benefits` — benefit definitions, their eligibility rules, and the
    audience that currently qualifies. Benefits are created as drafts and must
    be published.
  </Step>
  <Step title="Earn configuration">
    `point-multipliers` and `rule-attributes` — the multiplier layers and the
    catalogue of attributes eligibility rules can reference.
  </Step>
  <Step title="Public surfaces">
    `pages` and `theme-kits` for the join page, and `custom-domains` to serve
    it on your own domain.
  </Step>
</Steps>

## How earn rates resolve [#how-earn-rates-resolve]

This is the single most misunderstood part of the configuration surface.

<Warning>
  **The most specific configured layer wins — even when it is lower.** It is
  specificity, not maximum. A tier configured at a lower rate than the program
  default will *reduce* earning for members in that tier, not be ignored in
  favour of the larger number.
</Warning>

The layers, most specific first:

1. Program tier
2. Program default
3. Journey admin override
4. Journey membership tier
5. A floor, then a system default

Two more things to hold onto:

- **The configured value is the total rate, not an add-on.** Setting a
  multiplier replaces the rate; it does not stack on top of one.
- **`0.00` is a valid configured value.** It means "no points", and it is
  distinct from leaving a layer unset, which falls through to the next one.

Campaigns are evaluated separately and compete on a best-single-offer basis.
They do not stack with each other.

## Things that catch people out [#things-that-catch-people-out]

- **Drafts do not deliver.** A program must be activated and a benefit must be
  published before either does anything.
- **Changes are additive and compatible.** New response fields appear over
  time; ignore ones you do not recognise.
- **Custom-domain recheck is rate limited** with its own 429. Build a backoff
  rather than a tight retry when verifying DNS.
- **Send an `Idempotency-Key`** on configuration writes. Re-running a
  deployment should not create a second program.

## Scopes [#scopes]

Programs, tiers and benefits each have separate read and write permissions, and
pages, theme kits and custom domains have their own again. The
[API reference](/api-reference/partner/explorer/loyalty/programs/list) shows
the exact requirement per endpoint.
