Skip to main content
Softcrum Loyalty is a headless engine for customer loyalty and incentives. A company connects its own systems — point of sale, ecommerce, ERP, billing — and behavioural events start flowing in. From those events the engine awards points, issues coupons, moves customers between tiers, pays out referrals and triggers campaigns, all from rules the company configures itself. It runs either inside our own console and member portal, or entirely embedded in the company’s own experience through the public API. The engine is the product; the interface is a choice.

Who this is for

The problem today

Companies that want a loyalty program choose between two bad options. Packaged ecommerce loyalty apps are fast to install but lock the experience into a widget and a vertical — they cannot model a subscription business’s payment behaviour or a services company’s anniversaries. Enterprise engines are genuinely flexible but are enterprise purchases: long sales cycles, opaque pricing, and integration projects rather than an afternoon. Underneath both sits a pricing wound the market talks about constantly. The dominant engagement platforms bill for every profile stored whether or not it is contacted, and at least one applies a ratchet that keeps billing a peak long after usage falls. The result is that importing your own history — the single thing that makes a loyalty program work on day one — is financially punished. Being the platform that does not do that is a positioning decision, not a discount.

What it does (normative)

  • A tenant defines a program: its point currencies, its earning rules, its reward catalog, its tiers.
  • Behavioural events award points through a rules engine whose contract is event → conditions → effects, with versioned campaigns and budgets.
  • Points live in an immutable ledger with two separate currencies — redeemable points and status points — and FIFO lots with real expiration. Balances are a projection, never a mutable column.
  • Points and coupons are redeemed through an idempotent API a point of sale can call safely, with parent/child redemptions and an explicit rollback policy.
  • Referrals pay both sides, released by a qualifying event rather than by signup, with anti-fraud controls.
  • Tiers qualify over a defined window, with an explicit downgrade policy and per-tier overrides on earning, pricing and expiration.
  • Everything emits domain events that the messaging module turns into campaigns, and that a tenant can consume as outgoing webhooks.

Non-goals (normative)

  • Not a promotions engine in F1. Dynamic cart discounts (apply_discount) are ratified for F2 (DEC-H4); F1 leaves the effect catalog open so adding it costs nothing.
  • Not a payments system. Mixed points-plus-money redemption is a confirmed requirement (DEC-H3), but F1 only reserves the seam — a nullable money_component and a domain event.
  • Not a CDP. Profiles, identities, consents, events and segments belong to customer-core. Loyalty is a consumer of that core, never an owner of it.
  • No cross-program aggregation. Multi-program ships in F1 (ADR-021), but each program reports on itself. Aggregating across programs raises questions — whose points, which currency, which tier ladder — that get their own decision when a customer actually needs it.
  • Not gamification in F1. Badges and challenges have reserved schema and land in F2.
  • No vertical hardcoding. Event taxonomies ship as installable data, not code (DEC-H7). The product must apply to any industry.

Success

Commercial shape

The billable base is the marketable contact — a contact with active consent on at least one channel and not suppressed (ADR-014). Stored history is free and unlimited: importing years of customers costs nothing, which is the adoption lever. There is no ratchet; the count re-evaluates each cycle in both directions. Loyalty itself meters on volume: tracked events and messages, with published unit prices and allowances per plan (ADR-016). Two capabilities are sold rather than included. The data freshness add-on raises the frequency of heavy recomputes — drift reconciliation, full RFM, analytical snapshots — from nightly to as often as hourly (DEC-G5). And program count is an entitlement (ADR-021): the base plan includes a number of programs, and needing another is a concrete reason to move up a tier. Exceeding it is blocked, never billed as overage — a hard limit is the right shape for a capability the tenant chooses to adopt, unlike consumption their own customers drive. contact_balances is never part of that add-on. A member sees their balance the instant it changes; charging for that would be charging for correctness.

Phases

Compliance and risk

Loyalty stores behavioural and transactional data about identified people, which is exactly what profiling regulation targets. Two consequences are already fixed and constrain the design:
  • Erasure is asymmetric. A data subject exercising deletion has their profile and events deleted, but ledger rows are anonymized to a tombstone, never destroyed (DEC-J3) — accounting integrity and the right to erasure are reconciled by anonymization, not by deletion. Committed execution is ≤30 days, automated.
  • The ledger is the evidence. Ley 21.719 audits operational evidence rather than policies. The append-only ledger plus the audit log is what we would show.
Main product risk: a rules engine expressive enough to be useful and restricted enough to stay predictable. The mitigation is that effects are a parametric catalog — adding a row does not add behaviour, and the API rejects codes the business does not yet support.

Dependencies

customer-core for contacts, identities, consents, events and segments — a hard dependency, and one-way. messaging for every notification, through domain events only. QueuePort for asynchronous effects, NotificationChannelPort for delivery. Postgres partitioning for the event stream feeding the rules engine.

Open questions

None outstanding. Every question this spec carried was answered in the consolidated register (../../../design/open-questions-v1.md, v1.1) and folded into the normative sections above.

Changelog