ripllo.referral.created.v1

Fires when a new referral attribution is recorded — a customer signed up via someone else's referral link. The attribution is in pending: it'll either fulfil into a real reward (referee buys something) or expire (attributionWindowDays passes).

When it fires

When POST /api/v1/referrals/attributions/signup creates a new ReferralAttribution row. The Storlaunch partner SDK calls this when a new customer signs up via a referral link.

The event is single-shot per attribution. The endpoint is idempotent on (accountId, refereeCustomerId) — a buyer who somehow signs up twice via different referral links is attributed to the first one only, and no second event fires.

Payload

{
  "id": "evt_01HX...",
  "type": "ripllo.referral.created.v1",
  "createdAt": "2026-05-13T10:43:22.187Z",
  "accountId": "acc_01HX...",
  "data": {
    "attribution": {
      "id": "rat_01HX...",
      "accountId": "acc_01HX...",
      "referrerCustomerId": "cus_01HX...",
      "refereeCustomerId": "cus_02HX...",
      "linkId": "rln_01HX...",
      "linkCode": "ALICE-A1B2",
      "status": "pending",
      "expiresAt": "2026-06-12T10:43:22.000Z",
      "externalSource": "storlaunch",
      "externalRef": "storlaunch_cust_983",
      "createdAt": "2026-05-13T10:43:22.140Z"
    },
    "program": {
      "rewardType": "percent",
      "referrerValue": 1000,
      "refereeValue": 500,
      "currency": "IDR",
      "minPurchaseAmount": 100000,
      "rewardExpiryDays": 90,
      "attributionWindowDays": 30
    }
  }
}

The payload bundles both the attribution row and a snapshot of the program config at attribution time. This way, downstream consumers don't need to fetch the program separately just to render "the referrer will earn 10% off when..."

Handler examples

// Node
if (event.type === 'ripllo.referral.created.v1') {
  const { attribution, program } = event.data;
  await emailer.sendReferralWelcome({
    refereeCustomerId: attribution.refereeCustomerId,
    discountValue: program.refereeValue,
    discountType: program.rewardType,
    expiresAt: attribution.expiresAt,
  });
  analytics.track('referral_signup', {
    linkCode: attribution.linkCode,
    referrerCustomerId: attribution.referrerCustomerId,
  });
}
# Python
if event['type'] == 'ripllo.referral.created.v1':
    attribution = event['data']['attribution']
    program = event['data']['program']
    emailer.send_referral_welcome(
        referee_customer_id=attribution['refereeCustomerId'],
        discount_value=program['refereeValue'],
        discount_type=program['rewardType'],
        expires_at=attribution['expiresAt'],
    )
// Go
if event.Type == "ripllo.referral.created.v1" {
    var data struct {
        Attribution ripllo.ReferralAttribution `json:"attribution"`
        Program     ripllo.ReferralProgram     `json:"program"`
    }
    _ = json.Unmarshal(event.Data, &data)
    emailer.SendReferralWelcome(ctx, data.Attribution.RefereeCustomerID, data.Program.RefereeValue, data.Attribution.ExpiresAt)
}

What to do

  • Send the welcome email. The referee has a discount waiting. Email them now — the partner platform's signup confirmation can mention "and here's a referral discount", but a dedicated email gets better engagement.
  • Notify the referrer. "Your friend just signed up! When they make their first purchase, you'll earn X." Drives ongoing engagement.
  • Track signup-by-link metrics. Aggregate by linkCode to see which referrers are productive.
  • Start a fulfilment timer on your side, optionally. Ripllo's cron sweeps pending attributions and emits referral.expired (when wired), but if you want earlier reminders to the referee, kick a delayed task off this event.

Common pitfalls

  • Sending the welcome discount as the referee discount code directly. Don't mint the discount code yourself — the referee's first checkout uses program.refereeValue applied at the partner-platform checkout, not a code-redemption flow. The referrer's reward is the one that gets minted as a dc_… code (on fulfilment).
  • Treating attribution as "they bought". Attribution is "they signed up via this link". Fulfilment requires an actual purchase. Many attributions expire without ever converting.
  • Assuming referrerCustomerId is the same person as the link owner. It always is — that's how the link was created. But don't assume the referrer is necessarily a buyer themselves yet; some referrers earned a link for being a newsletter subscriber, not from a purchase.

Next