Skip to main content

Reciprocity & Stacking

Deep dive into reciprocity agreements, defaults, and how stacking works.

Agreement types

  • Bilateral (type: BILATERAL): between two clubs (clubAId, clubBId) with direction A_TO_B, B_TO_A, or BOTH.
  • Network (type: NETWORK): any clubs sharing networkCode (e.g., SAGA_NETWORK) can honor the network agreement. Membership is tracked in ClubNetworkMembership.

Rate configuration (ReciprocityRateConfig)

FieldMeaningDefaults
discountTypePERCENT, FIXED_AMOUNT, FIXED_RATE, RATE_TIERrequired
discountValue% (0–100) or cents off (for PERCENT/FIXED_AMOUNT)0
fixedRateCentsFinal price in cents (FIXED_RATE)falls back to base price
rateTierCodeTier code for RATE_TIER passthroughundefined
priorityLower = chosen first (ties break on updatedAt)10_000
validDaysOfWeekArray of MON..SUN (case-insensitive)all days
validTimeStart / validTimeEndHH:MM window (24h)none
blackoutDatesYYYY-MM-DD listnone
minHandicap / maxHandicapInclusive rangenone

Restrictions block the agreement with reasons DAY_RESTRICTED, TIME_RESTRICTED, BLACKOUT_DATE, HANDICAP_OUT_OF_RANGE.

Resolution flow (ReciprocityService)

  1. Require membershipNumber; ensure club policy reciprocityEnabled.
  2. Resolve home club (provider code → membership/homeClubCode hint). Home club == target → no reciprocity.
  3. Gather applicable agreements:
    • Bilateral(s): home ↔ target.
    • Network: only if both clubs share networkCode.
  4. Apply rate config(s) respecting restrictions.
  5. Return pricing + appliedAgreements[] audit trail.

Stacking behavior

  • stackingMode (input): BEST_PRICE (default) or STACK.
  • BEST_PRICE: pick the first applicable agreement (bilateral preferred, otherwise network). Matches previous behavior.
  • STACK: apply all eligible bilaterals (priority-sorted) then the network agreement if present. Discounts are applied sequentially to the running price. The response includes appliedAgreements with each discount delta.
  • If every candidate is blocked (no rate config/restriction), the service returns the last reason and no discount.

Defaults & safeguards

  • Provider default: SAGA_NETWORK when no providerCode is supplied.
  • Policy fetch failure → reciprocity treated as enabled with visitor access (logs a warning, never fails the request).
  • Unknown discountType falls back to base price (no-op).
  • Errors in home-club lookup degrade to NO_AGREEMENT without failing pricing/streams.

Inputs you must forward

Send these in pricing/search calls to activate reciprocity:

{
"tenantId": "tenant-uuid",
"membershipNumber": "ABC123",
"providerCode": "SAGA_NETWORK",
"homeClubCode": "HOME123", // optional hint
"handicap": 9 // optional, for handicap-gated deals
}

Outputs to expect

Response fields (when applicable):

  • finalPriceCents, discountCents, agreementId, rateType, source (BILATERAL|NETWORK)
  • appliedAgreements[]: ordered list of all applied agreements with per-step discountCents
  • reason when not applicable (see denial reasons above)

Operational checklist

  • Create bilateral/network agreements with priorities where multiple should stack.
  • Ensure ClubNetworkMembership exists for every club expected to use a network agreement.
  • Populate day/time/handicap limits to match business rules; leave empty to allow all.
  • Prefer STACK mode when you want bilateral overrides + network fallback together.