Skip to main content

Attribution System

PromoStack uses a two-phase attribution system: early mapping (metacode redemption) and confirmation (RevenueCat webhook).

Attribution Phases

Phase 1: Early Mapping (Metacode Redemption)

When a referee redeems a metacode in your app:
POST /referee-redeem
{
  "referee_uid": "user_123",
  "metacode": "abc123",
  "platform": "ios"
}
PromoStack immediately:
  1. Maps codes.redeemed_by_uid = "user_123"
  2. Links code to referrer via codes.referrer_id
  3. Creates referral event with status code_assigned
At this point, attribution is established - we know who referred whom.

Phase 2: Confirmation (RevenueCat Webhook)

When the referee subscribes, RevenueCat sends webhook:
{
  "app_user_id": "user_123",
  "event_type": "initial_purchase"
}
PromoStack:
  1. Finds code by codes.redeemed_by_uid = "user_123"
  2. Updates codes.status = 'redeemed_confirmed'
  3. Updates referral_events.status = 'redeemed'
  4. Checks if referrer reached threshold → creates reward

Why Two Phases?

Early Attribution

Know who referred whom immediately, before payment

Payment Confirmation

Only count confirmed subscriptions toward rewards

Anti-Fraud

Prevent duplicate redemptions at metacode phase

Flexibility

Works with any payment provider, not just RevenueCat

Referral Event Lifecycle

StatusTriggerMeaning
clickedLanding page visitUser clicked referral link
code_assigned/referee-redeemMetacode redeemed, code issued
redeemedRevenueCat webhookSubscription confirmed
qualifiedThreshold checkCounted toward referrer’s reward

Anti-Fraud Measures

Duplicate Prevention

The /referee-redeem endpoint checks if referee_uid already redeemed a code for this campaign:
SELECT id FROM codes
WHERE campaign_id = ? AND redeemed_by_uid = ?
If found, returns 409 ALREADY_REDEEMED error.

One Code Per Campaign

Each referee can only redeem one code per campaign, preventing:
  • Multiple redemptions by same user
  • Gaming the system with multiple accounts (requires unique app_user_id)

Matching Logic

Primary Match (Metacode Flow)

-- Find code by referee UID
SELECT * FROM codes
WHERE redeemed_by_uid = 'user_123'
AND status = 'issued'

Fallback Match (Legacy)

If primary match fails, try matching by code value:
-- Fallback to code value
SELECT * FROM codes
WHERE code_value = 'PROMO-ABC-123'
AND status = 'issued'
This ensures backward compatibility with pre-metacode implementations.

Best Practices

Ensure referee_uid is unique per user. Use your app’s internal user ID or RevenueCat’s app_user_id.
RevenueCat may send duplicate webhooks. PromoStack handles this with idempotent updates (only updates if status = 'issued').
Track ratio of code_assignedredeemed events to identify drop-off points.