Skip to content

Referrals

The referral module records who referred whom. It does not pay rewards. A referrer owns a code, a referee applies it, and Storelayer stores a referral record linking the two. Points for either side are paid by rules that react to your business events and read the referral record.

Code typeCreated withreferrerIdTypical use
User-ownedPOST /referrals with referrerIdThe customer who shares it“Invite a friend” codes. One code per referrer: a second create returns error 3100
SystemPOST /referrals without referrerId, or POST /referrals/bulk (1–1000 codes)nullInfluencer, partner or campaign codes. Applying one records a referral with no referrer to reward

A code has status (active or inactive), maxUses (null = unlimited), currentUses, expiresAt and tags. You can supply your own code string or let Storelayer generate one from the project config. Codes are unique per project and matched exactly, including case. Generated codes are upper-case.

StepHowChanges data?Important distinction
ValidatePOST /referrals/validate with code and optionally refereeIdNoUse it to show “code accepted” in a signup form. Pass refereeId to also check self-referral and already-referred
ApplyPOST /referrals/apply with code and refereeId, or the rule action apply_referralYes: creates the referral record and increments currentUsesAttribution only. No points are paid
RewardA rule on your qualifying event (e.g. order_completed) that reads the referral and runs reward actionsWalletsThe only step that moves value

Applying runs the same checks as validating. Failures come back as errors:

CodeErrorMeaning
3101CODE_NOT_FOUNDNo such code (or it was deleted)
3103CODE_NOT_ACTIVECode is inactive
3104CODE_EXPIREDexpiresAt has passed
3105CODE_MAX_USES_REACHEDcurrentUses reached maxUses
3106SELF_REFERRALReferee is the code’s owner
3107REFEREE_ALREADY_REFERREDA customer can be referred only once, by any code
{
"id": "ref_…",
"codeId": "rcode_…",
"code": "K7M2QX9A",
"referrerId": "cus_alice",
"refereeId": "cus_bob",
"completedAt": "2026-10-11T09:30:00.000Z",
"expiresAt": null,
"createdAt": "2026-10-11T09:30:00.000Z",
"updatedAt": "2026-10-11T09:30:00.000Z"
}

A referral has no pending/qualified state: it exists from the moment the code is applied. “Has the referee qualified?” and “has the reward been paid?” are questions your rules answer, for example with a customer metadata flag. See the worked example in the referral program guide. The complete_referral rule action only looks up the referee’s referral and reports its referrerId; it changes nothing.

GET/PUT /projects/{projectId}/referrals/config. PUT merges the fields you send.

FieldDefaultEffect
defaultMaxUsesPerCodenullCap for user-owned codes. Changing it rewrites maxUses on every existing user-owned code
defaultMaxUsesPerSystemCodenullCap applied to new system codes
defaultCodeExpirationDaysnullSets expiresAt on new codes created without one
referralExpirationDaysnullSets expiresAt on new referral records. Stored for your rules to check; Storelayer does not enforce it
codeLength8Total generated length including prefix (4–20)
codePrefix""Upper-case letters/digits, max 10, e.g. "FRIEND"
codeCharsetalphanumericalphanumeric (no look-alike 0 O 1 I), alphabetic, numeric, hex
codeSeparator / codeSeparatorInterval"" / 4"", - or _ inserted every N characters of the random part
  • GET /referrals/stats: totalCodes, activeCodes, totalReferrals
  • GET /referrals/stats/{userId}: codes created and referrals made by one customer
  • GET /referrals/leaderboard: referrers ranked by number of referrals
  • GET /referrals/events: audit log (code.created, code.deactivated, code.reactivated, referral.created)