MMOLove Docs
Referral Kit

Concepts

The referral lifecycle and state machine, the durable anchor, first-touch attribution, the attribution window, and who owns what.

The Referral Kit is built on a few small ideas. Understand these and the REST contract reads like common sense.

The conduit model — who owns what

MMOLove is the conduit. The split never moves:

MMOLove (us)Server owner (you)
Owns the /r/<server> link + the signed mmref tokenDefines what "qualified" means (level 10, 2h played, first purchase — your call)
Tracks the lifecycle: clicks, registrations, milestonesReports lifecycle events from your kit
Mints + holds the per-server signing secretGrants the in-game reward
Surfaces analytics, the funnel, and the referrers leaderboardResolves who to reward via your chosen identity field

We do the attribution; you own the payout. MMOLove never touches your economy and never hands out rewards.

The lifecycle

A referral moves through a small state machine. Two inbound events drive the forward path — registered and qualified — and a couple of states model reversal and expiry.

                    registered             qualified
   ┌─────────┐      (your kit)    ┌──────────────┐   (your kit)    ┌───────────┐
   │ clicked │ ───────────────▶   │  registered  │ ─────────────▶  │ qualified │
   └─────────┘                    └──────────────┘                 └───────────┘
        │                            │        │                        │
        │ /r link followed           │        │  reversed (owner)      │
        │ (mmref minted)             │        ▼                        │
        │                            │   ┌──────────┐                  │
        │                            └──▶│ reversed │◀─────────────────┘
        │                                └──────────┘

        │  maturation window elapses

   ┌─────────┐
   │ expired │     rejected (anti-abuse) is also terminal
   └─────────┘
StateMeaningHow it's reached
clickedThe /r/<server> link was followed — a click row + mmref token exist.Player follows the share link.
registeredThe anchor is minted; referrer ↔ referee are bound.Your registered event.
qualifiedThe referee hit your milestone — reward time.Your qualified event.
reversedAn owner reversal (refund / chargeback / abuse).Your reversed event (modelled; see note).
expiredThe attribution window elapsed before qualification.Time-driven (modelled).
rejectedAnti-abuse rejection.System (modelled).

The endpoint accepts registered, qualified, and reversed. The current phase acts on registered and qualified; reversed and the time-driven expired / rejected states are modelled so the table is complete. expired and rejected are terminal — no inbound event advances them.

The state machine is strict, so out-of-order events fail loudly instead of corrupting attribution:

  • registered from clickedadvance to registered (mints the anchor).
  • registered when already registered / qualifiedno-op (idempotent).
  • qualified from registeredadvance to qualified.
  • qualified when already qualifiedno-op.
  • qualified from clicked (no anchor yet) → invalid422. You must send registered first.
  • reversed from registered / qualified → advance to reversed.
  • Anything into a terminal state → invalid (a repeat of the same terminal event is a no-op).

See Errors & troubleshooting for how each maps to a status code.

The durable anchor

When your registered event lands, MMOLove mints a long-lived referral_id — the anchor. Every later event (qualified, reversed) keys off it.

The anchor is deliberately decoupled from the click token's expiry. The mmref token in the link is signed and time-bounded; the anchor it mints is durable, so a referee who registers near the edge of the click window still qualifies weeks later without the original token being "live."

The anchor row carries the referrer, the referee identity, the originating token, the current state, and the registered_at / qualified_at timestamps.

First-touch — one referrer per referee

Attribution is first-touch: the first referrer to register a given referee wins, permanently. The anchor is unique per (server_id, referee_identity), so:

  • The first registered for a referee mints the anchor and binds that referrer.
  • A different referrer sending registered for the same referee collides on that uniqueness and is acknowledged with 200 and ignored ({ "ignored": "first_touch_conflict" }). The original anchor is never overwritten.

This is why referee_identity must be stable — the same player must always map to the same identity value, or first-touch can't hold.

Pick an identity that never changes for a player (an internal account id is ideal). A renamable display name will break first-touch the day a player renames.

The attribution window — maturation_days

Each server config carries a maturation_days window (the industry default is 90 days; configurable 1–730 on the Referrals tab). It's the period in which a registered referral can still mature to qualified and count. Once it elapses without qualification, the referral is considered expired.

Set it to match how long it realistically takes a new player to reach your milestone — generous enough that genuine referrals land, tight enough to keep the funnel honest.

Idempotency & dedup

Every event you send carries a server_event_idyour idempotency key. Dedup is on the tuple (token, type, server_event_id), never on token alone, so registered and qualified can both land for one referral. Resending the exact same event is absorbed and returns 200. This makes retries completely safe — see Signing & security.

Anti-abuse caps

The config also supports anti-abuse caps (per referrer, per IP, per month; 0 = unlimited) and a display-only reward_description. These are owner-set on the Referrals tab. As with everything else: MMOLove records and surfaces; you decide and grant.

Where to go next

On this page