What Is a Referral Service?
A Referral Service incentivizes existing users to invite new users by rewarding both parties when a successful conversion occurs. It must accurately track who referred whom, prevent self-referrals and fraud, detect when a referral has converted (signed up, made a purchase, etc.), and trigger reward payouts reliably without double-counting.
Data Model
TABLE referral_codes (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
user_id BIGINT NOT NULL UNIQUE, -- one code per user
code VARCHAR(32) UNIQUE NOT NULL,
created_at DATETIME DEFAULT NOW()
);
TABLE referrals (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
referrer_id BIGINT NOT NULL, -- user who shared the code
referee_id BIGINT NOT NULL UNIQUE, -- new user; one referrer only
code VARCHAR(32) NOT NULL,
status ENUM('pending', 'converted', 'rewarded', 'voided') DEFAULT 'pending',
conversion_event VARCHAR(64), -- e.g. 'first_purchase'
converted_at DATETIME,
rewarded_at DATETIME,
created_at DATETIME DEFAULT NOW(),
INDEX idx_referrer (referrer_id),
INDEX idx_code (code)
);
TABLE referral_rewards (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
referral_id BIGINT NOT NULL REFERENCES referrals(id),
user_id BIGINT NOT NULL,
reward_type ENUM('credit', 'coupon', 'points') NOT NULL,
amount DECIMAL(10,2),
issued_at DATETIME DEFAULT NOW()
);
Core Workflow
- Code generation: On user signup, generate a unique alphanumeric code (e.g., 8 characters, base-36) and insert into
referral_codes. - Attribution: When a new visitor lands via a referral link, store the code in a cookie or session. On signup, look up the code, validate the referrer exists and is not the same account, then insert a
referralsrow withstatus = pending. - Conversion detection: The service subscribes to domain events (e.g.,
order.completed) via a message queue. On receiving a qualifying event for a referee, it updatesreferrals.statustoconvertedand recordsconverted_at. - Reward issuance: A worker transitions status to
rewardedand inserts rows intoreferral_rewardsfor both referrer and referee, then calls the appropriate reward subsystem (credit, coupon, or points service).
Failure Handling
- Duplicate conversion events: The message consumer must be idempotent. Use the
referee_id UNIQUEconstraint and a conditional update:UPDATE referrals SET status='converted' WHERE referee_id=? AND status='pending'. Zero rows affected means already processed. - Reward delivery failure: Issue rewards inside a database transaction alongside the status update. If the downstream call fails, roll back and rely on the queue to redeliver. Use an outbox pattern to guarantee at-least-once reward delivery.
- Fraud / self-referral: At attribution time, reject if
referrer_id = new_user_id, if the referrer account is flagged, or if the device fingerprint matches the referrer. - Code expiry: Support optional
expires_atonreferral_codesfor campaign-limited programs.
Scalability Considerations
- Event-driven architecture: Decoupling conversion detection from the order flow via a message queue (Kafka, SQS) prevents the referral logic from adding latency to checkout.
- Code lookup caching: Cache the
referral_codestable in Redis. A read-through cache with a long TTL works well since codes rarely change. - Analytics separation: Aggregate referral metrics (conversion rates, top referrers) in a read replica or data warehouse rather than querying the operational database.
- Horizontal scaling: The reward worker pool can scale independently based on queue depth.
Summary
A Referral Service is fundamentally an event-driven state machine: codes are minted, referrals are attributed, conversion events trigger status transitions, and rewards are issued exactly once. The UNIQUE constraint on referee_id is the single most important correctness guarantee in the schema.
{
“@context”: “https://schema.org”,
“@type”: “FAQPage”,
“mainEntity”: [
{
“@type”: “Question”,
“name”: “What is a referral service in low-level system design?”,
“acceptedAnswer”: {
“@type”: “Answer”,
“text”: “A referral service tracks user invite links, attributes sign-ups or purchases to the referring user, and triggers reward payouts when defined conditions are met. It requires reliable attribution logic, fraud prevention, and integration with notification and payment systems.”
}
},
{
“@type”: “Question”,
“name”: “How do you design a referral code generation system?”,
“acceptedAnswer”: {
“@type”: “Answer”,
“text”: “Referral codes can be generated as a short hash of the user’s ID combined with a random salt, or as a Base62-encoded unique token stored in a referral_codes table keyed by user. Codes must be unique, URL-safe, and short enough for sharing. A lookup index on the code column ensures fast attribution at sign-up time.”
}
},
{
“@type”: “Question”,
“name”: “How do you prevent referral fraud in a referral service?”,
“acceptedAnswer”: {
“@type”: “Answer”,
“text”: “Fraud prevention layers include device fingerprinting, IP-based rate limiting, email domain validation to block disposable addresses, and a minimum qualifying action (e.g., first purchase above a threshold) before rewards are issued. Self-referrals are blocked by comparing user identifiers and payment methods at reward time.”
}
},
{
“@type”: “Question”,
“name”: “What are the key components of a scalable referral service?”,
“acceptedAnswer”: {
“@type”: “Answer”,
“text”: “Key components include a referral code store (DB + cache), an attribution engine that links referred users to referrers, an event consumer that listens for qualifying actions via a message queue, a reward engine that calculates and queues payouts, and an idempotency layer to ensure rewards aren’t issued more than once per qualifying event.”
}
}
]
}
See also: Uber Interview Guide 2026: Dispatch Systems, Geospatial Algorithms, and Marketplace Engineering
See also: Airbnb Interview Guide 2026: Search Systems, Trust and Safety, and Full-Stack Engineering
See also: Shopify Interview Guide