Top-up (one-time purchase) functionality is now fully implemented and deployed!
Location: droid@192.168.178.30:/home/droid/.ssh/sprite-pipeline-backend
Configuration (app/config.py):
- Added
stripe_topup_100_price_id - Added
stripe_topup_250_price_id - Added
topup_100_units: int = 100 - Added
topup_250_units: int = 250
Environment Variables (.env):
SPRITE_STRIPE_TOPUP_100_PRICE_ID=price_1SziYe43zM5TljobOZybQDpn
SPRITE_STRIPE_TOPUP_250_PRICE_ID=price_1SziZI43zM5TljobS2qSK2dZBilling Routes (app/routes/billing.py):
- Updated
_get_price_id()to supporttopup_100andtopup_250 - Added
_get_units()helper function for credit allocation - Updated
/billing/checkoutto supportmode="payment"for top-ups - Updated webhook
checkout.session.completedto allocate credits for one-time purchases - Logs "topup_processed" events for monitoring
Backend Commit: e6e1b70 - "Add top-up support"
Status: Restarted and operational ✅
Location: C:\Users\fbrmp\Projekte\sprite-pipeline-web
New Component (src/components/react/TopUpButton.tsx):
- React component for one-time purchase buttons
- Calls
createCheckout(plan, returnUrl)API - Redirects to Stripe checkout
- Shows loading state during redirect
Dashboard Update (src/components/react/DashboardOverview.tsx):
- Added "Need More Pictures?" section
- Two top-up options displayed:
- 100 pictures for $9 (topup_100)
- 250 pictures for $20 (topup_250)
- Buttons use branded styling
Frontend Commit: 19dcf1f - "Implement top-up (one-time purchase) support"
Deployment: Vercel (auto-deployed) ✅
- Free: 0 pictures/month (BYOK only)
- Starter (Tier 1): $9/month → 100 pictures = $0.09/picture
- Pro (Tier 2): $29/month → 500 pictures = $0.058/picture
- 100 pictures: $9 = $0.09/picture (same as Starter monthly)
- 250 pictures: $20 = $0.08/picture (better value for larger purchase)
Pricing Strategy:
- Top-ups slightly more expensive per-picture than subscriptions
- Encourages subscriptions for regular users
- Provides flexibility for occasional users
- No subscription commitment required
- User clicks "Get Started" on Starter/Pro plan
- Redirected to Stripe checkout (
mode=subscription) - Enters payment details
- Subscription created
- Monthly credits allocated via webhook
- Auto-renewal every month
- User visits dashboard
- Sees "Need More Pictures?" section
- Clicks "100 pictures $9" or "250 pictures $20"
- Redirected to Stripe checkout (
mode=payment) - Enters payment details (one-time charge)
- Payment completed
checkout.session.completedwebhook fires- Credits immediately added to user quota
- No subscription created
- User can purchase again anytime
✅ Dashboard top-ups - Buy 100 or 250 pictures anytime ✅ One-time payment - No subscription required ✅ Immediate credits - Available right after payment ✅ Works with any plan - Free, Starter, or Pro users can top up ✅ Stripe checkout - Secure payment via Stripe ✅ Credit tracking - Shows in dashboard quota
✅ Webhook logging - See "topup_processed" in backend logs
✅ Stripe dashboard - Track one-time payments separately
✅ Revenue tracking - Both subscriptions and top-ups visible
✅ Credit ledger - All allocations recorded with topup_ prefix
# 1. Login to dashboard
open https://fabslabssprites.com/dashboard
# 2. Scroll to "Need More Pictures?" section
# 3. Click "100 pictures $9" button
# 4. Use Stripe test card
# Card: 4242 4242 4242 4242
# Date: Any future date
# CVC: Any 3 digits
# 5. Complete payment
# 6. Redirect to dashboard
# 7. Check quota increased by 100
# 8. Verify backend logs
ssh droid@192.168.178.30
docker compose logs backend | grep "topup_processed"# See all top-up events
docker compose logs backend | grep "topup_processed"
# See recent top-ups
docker compose logs backend | grep "topup_processed" | tail -10
# Watch for new top-ups
docker compose logs backend -f | grep "topup_processed"- topup_100:
price_1SziYe43zM5TljobOZybQDpn - topup_250:
price_1SziZI43zM5TljobS2qSK2dZ
POST /billing/checkout
Query params: plan=topup_100 or plan=topup_250
Event: checkout.session.completed
Mode: payment (not subscription)
Metadata: { user_id, plan: "topup_100" }
Payment Intent: pi_xxxxx
# In webhook handler
units = _get_units(plan) # 100 or 250
await add_quota(db, user.id, units, f"topup_{payment_intent}")- Credits added to user's
units_totalandunits_remaining - Recorded in credit ledger with reason:
topup_pi_xxxxx - No subscription or plan change
Top-up functionality is fully operational!
Users can now:
- ✅ Purchase credits without subscribing
- ✅ Choose between 100 ($9) or 250 ($20) pictures
- ✅ Get instant access to purchased credits
- ✅ Top up as many times as needed
- ✅ Works alongside subscriptions
No additional setup needed!
The system handles:
- ✅ Payment processing via Stripe
- ✅ Credit allocation via webhooks
- ✅ Quota updates in real-time
- ✅ Logging for monitoring
Implementation Date: 2026-02-12 Status: ✅ LIVE Both subscriptions AND top-ups working! 🎉