A crowdfunding platform must coordinate campaign lifecycle, pledge collection, payment authorization, and backer communication — with significantly different flows depending on the funding model. This article covers the low-level design.
Campaign Schema
The campaign table captures creator intent and tracks progress:
CREATE TABLE campaign (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
creator_id BIGINT NOT NULL,
title VARCHAR(255) NOT NULL,
goal_amount DECIMAL(12,2) NOT NULL,
pledged_amount DECIMAL(12,2) NOT NULL DEFAULT 0,
status ENUM('draft','active','funded','failed','cancelled') NOT NULL DEFAULT 'draft',
end_date DATETIME NOT NULL,
model ENUM('all_or_nothing','keep_it_all') NOT NULL
);
Reward Tier Schema
Campaigns offer tiered rewards to incentivize higher pledge amounts:
CREATE TABLE reward_tier ( id BIGINT PRIMARY KEY AUTO_INCREMENT, campaign_id BIGINT NOT NULL, min_pledge DECIMAL(12,2) NOT NULL, description TEXT NOT NULL, estimated_delivery DATE, qty_available INT, qty_claimed INT NOT NULL DEFAULT 0 );
qty_available is nullable — NULL means unlimited. Tier selection at pledge time must atomically increment qty_claimed with a guard: UPDATE reward_tier SET qty_claimed = qty_claimed + 1 WHERE id = ? AND qty_claimed < qty_available.
Pledge Schema
CREATE TABLE pledge (
pledge_id BIGINT PRIMARY KEY AUTO_INCREMENT,
campaign_id BIGINT NOT NULL,
backer_id BIGINT NOT NULL,
amount DECIMAL(12,2) NOT NULL,
reward_tier_id BIGINT,
status ENUM('pending','captured','refunded','voided') NOT NULL DEFAULT 'pending',
payment_intent VARCHAR(255),
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
);
payment_intent stores the Stripe (or equivalent) payment intent ID. Pledge status transitions are driven by payment provider webhooks and the end-of-campaign settlement job.
All-or-Nothing Flow
This is the classic crowdfunding model: backers are only charged if the campaign reaches its goal.
- At pledge time, create a payment intent in
authorizemode — the card is validated and funds are reserved but not captured - Store the pledge with status
pendingand incrementcampaign.pledged_amountatomically - At
end_date, the settlement job evaluates: ifpledged_amount >= goal_amount, capture allpendingpayment intents and setcampaign.status = funded - If the goal is not met, void all authorizations and set
campaign.status = failed
Authorization holds typically last 7 days, so long campaigns must re-authorize periodically or switch to a delayed capture strategy using the payment provider’s extended auth window.
Keep-It-All Flow
In the keep-it-all model, creators receive funds regardless of whether the goal is met:
- Payment is captured immediately at pledge time
- No settlement job is needed — funds transfer on pledge confirmation
- Refund policy is creator-defined and handled manually or via a refund window
Goal Tracking
pledged_amount is updated on every new pledge using an atomic increment:
UPDATE campaign SET pledged_amount = pledged_amount + ? WHERE id = ? AND status = 'active'
A Redis counter can mirror this value for low-latency reads on the campaign page, with the database as the authoritative source. Milestone events (25%, 50%, 75%, 100% of goal) are fired when the increment crosses a threshold, triggering backer notifications and social proof updates.
Backer Notifications
An event-driven notification service subscribes to campaign lifecycle events:
- Milestone reached: notify all backers when goal percentage thresholds are crossed
- Campaign successful: confirmation email with reward details and estimated delivery
- Campaign failed: notification that the authorization was voided and no charge was made
- Reward update: creator-initiated updates on production or shipping status
Notifications are queued via a message broker (e.g., SQS or RabbitMQ) to decouple delivery latency from the campaign state transition.
Creator Dashboard
The creator-facing analytics surface is read from a materialized view or reporting replica to avoid impacting the transactional database:
- Pledge count and total amount updated in near-real-time
- Amount by reward tier: breakdown of which tiers are most popular and how many slots remain
- Backer geography: country-level distribution derived from billing address or IP geolocation
- Daily pledge velocity: time-series chart to identify traffic spikes from press coverage or social sharing
This data helps creators optimize their campaigns mid-run — adjusting stretch goals, adding reward tiers, or launching targeted promotion when pledge velocity drops.
{ “@context”: “https://schema.org”, “@type”: “FAQPage”, “mainEntity”: [ { “@type”: “Question”, “name”: “What is the difference between all-or-nothing and keep-it-all crowdfunding models?”, “acceptedAnswer”: { “@type”: “Answer”, “text”: “In the all-or-nothing (AON) model, pledges are only captured if the campaign reaches its funding goal by the deadline; otherwise all payment authorizations are voided and backers are not charged. This reduces risk for backers and motivates creators to set realistic goals. In the keep-it-all (KIA) model, the creator receives whatever funds are raised regardless of whether the goal is met. KIA suits creators who can deliver partial value at any funding level. The system must track goal, deadline, and model type per campaign and run a settlement job at deadline that either captures or voids charges accordingly.” } }, { “@type”: “Question”, “name”: “How do you handle payment authorization holds for an all-or-nothing campaign?”, “acceptedAnswer”: { “@type”: “Answer”, “text”: “When a backer pledges, place an authorization hold (not a capture) on their payment method for the pledge amount. Store the authorization ID, amount, and expiry in the pledge record. Authorization holds typically expire in 7 days, so for campaigns longer than 7 days, schedule a re-authorization job that runs every 5 days to refresh the hold before it lapses. At campaign end, the settlement job either captures all held authorizations (goal met) or voids them (goal not met). This avoids charging backers before the outcome is known while still confirming their payment method is valid at pledge time.” } }, { “@type”: “Question”, “name”: “How do you model reward tiers and track backer selections?”, “acceptedAnswer”: { “@type”: “Answer”, “text”: “Each campaign has a one-to-many relationship with reward tiers. A tier record contains: minimum_pledge_amount, title, description, estimated_delivery_date, quantity_limit (null for unlimited), and quantity_claimed (atomic counter). When a backer selects a tier, atomically increment quantity_claimed and reject the pledge if it would exceed quantity_limit. Store the selected tier ID on the pledge record. This allows the creator dashboard to show real-time availability per tier and lets the fulfillment system group backers by tier for shipping and digital delivery workflows.” } }, { “@type”: “Question”, “name”: “Can backers cancel a pledge, and how should cancellations be handled?”, “acceptedAnswer”: { “@type”: “Answer”, “text”: “Allow cancellations up to a configurable cutoff (e.g., 48 hours before campaign end). On cancellation: (1) void the payment authorization immediately via the payment gateway API; (2) mark the pledge as CANCELLED in the database; (3) decrement the campaign’s total_pledged counter atomically; (4) release the backer’s claimed reward tier slot by decrementing quantity_claimed. After the cutoff window, pledges are locked to give the creator a reliable funding snapshot before settlement runs. If a cancellation request arrives after cutoff, return a 409 with an explanation rather than silently failing.” } }, { “@type”: “Question”, “name”: “How does the campaign settlement batch job work?”, “acceptedAnswer”: { “@type”: “Answer”, “text”: “A scheduled job runs shortly after each campaign’s deadline. It queries for campaigns in FUNDING state whose deadline has passed. For each campaign: (1) compute total_pledged by summing all non-cancelled pledges; (2) compare against the funding goal and the campaign model (AON vs KIA); (3) for AON campaigns that met the goal, or any KIA campaign, issue capture requests to the payment gateway for each pledge authorization in batches (respecting gateway rate limits); (4) for failed AON campaigns, issue void requests; (5) transition the campaign to FUNDED, FAILED, or PARTIALLY_FUNDED state and trigger creator payout and backer notification events via a message queue. All steps are idempotent so the job can be safely retried on failure.” } } ] }Frequently Asked Questions
Q: What is the difference between all-or-nothing and keep-it-all crowdfunding models?
A: In the all-or-nothing (AON) model, pledges are only captured if the campaign reaches its funding goal by the deadline; otherwise all payment authorizations are voided and backers are not charged. This reduces risk for backers and motivates creators to set realistic goals. In the keep-it-all (KIA) model, the creator receives whatever funds are raised regardless of whether the goal is met. KIA suits creators who can deliver partial value at any funding level. The system must track goal, deadline, and model type per campaign and run a settlement job at deadline that either captures or voids charges accordingly.
Q: How do you handle payment authorization holds for an all-or-nothing campaign?
A: When a backer pledges, place an authorization hold (not a capture) on their payment method for the pledge amount. Store the authorization ID, amount, and expiry in the pledge record. Authorization holds typically expire in 7 days, so for campaigns longer than 7 days, schedule a re-authorization job that runs every 5 days to refresh the hold before it lapses. At campaign end, the settlement job either captures all held authorizations (goal met) or voids them (goal not met). This avoids charging backers before the outcome is known while still confirming their payment method is valid at pledge time.
Q: How do you model reward tiers and track backer selections?
A: Each campaign has a one-to-many relationship with reward tiers. A tier record contains: minimum_pledge_amount, title, description, estimated_delivery_date, quantity_limit (null for unlimited), and quantity_claimed (atomic counter). When a backer selects a tier, atomically increment quantity_claimed and reject the pledge if it would exceed quantity_limit. Store the selected tier ID on the pledge record. This allows the creator dashboard to show real-time availability per tier and lets the fulfillment system group backers by tier for shipping and digital delivery workflows.
Q: Can backers cancel a pledge, and how should cancellations be handled?
A: Allow cancellations up to a configurable cutoff (e.g., 48 hours before campaign end). On cancellation: (1) void the payment authorization immediately via the payment gateway API; (2) mark the pledge as CANCELLED in the database; (3) decrement the campaign’s total_pledged counter atomically; (4) release the backer’s claimed reward tier slot by decrementing quantity_claimed. After the cutoff window, pledges are locked to give the creator a reliable funding snapshot before settlement runs. If a cancellation request arrives after cutoff, return a 409 with an explanation rather than silently failing.
Q: How does the campaign settlement batch job work?
A: A scheduled job runs shortly after each campaign’s deadline. It queries for campaigns in FUNDING state whose deadline has passed. For each campaign: (1) compute total_pledged by summing all non-cancelled pledges; (2) compare against the funding goal and the campaign model (AON vs KIA); (3) for AON campaigns that met the goal, or any KIA campaign, issue capture requests to the payment gateway for each pledge authorization in batches (respecting gateway rate limits); (4) for failed AON campaigns, issue void requests; (5) transition the campaign to FUNDED, FAILED, or PARTIALLY_FUNDED state and trigger creator payout and backer notification events via a message queue. All steps are idempotent so the job can be safely retried on failure.
See also: Stripe Interview Guide 2026: Process, Bug Bash Round, and Payment Systems
See also: Scale AI Interview Guide 2026: Data Infrastructure, RLHF Pipelines, and ML Engineering
See also: Coinbase Interview Guide