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
linkCodeto 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.refereeValueapplied at the partner-platform checkout, not a code-redemption flow. The referrer's reward is the one that gets minted as adc_…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
referrerCustomerIdis 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.
Related events
ripllo.referral.fulfilled.v1— reserved-not-emitted; the "they bought, reward minted" event.ripllo.referral.voided.v1— reserved-not-emitted; the refund reversal.ripllo.referral.expired.v1— reserved-not-emitted; the cron-driven timeout.ripllo.discount_code.redeemed.v1— fires when the referrer eventually uses their reward code.
Next
- Referrals resource — the full CRUD + attribution lifecycle.
- Webhooks reference — envelope, retries, signature verification.