================================================================================ SPEEDots Payment Flow - Complete Explanation ================================================================================ PRODUCT_ID SYSTEM - Your Proof of Purchase ================================================================================ Each purchase generates a UNIQUE product_id that serves as proof of ownership: FORMAT: GAME{game_id}_USER{user_hash}_TIME{timestamp} Example: GAME7_USER1a2b3c4d_TIME1760147434 This product_id is: ✓ Unique per transaction ✓ Stored in receipts table ✓ Sent to PayPal as item_number ✓ Returned by PayPal IPN ✓ Your permanent proof of purchase For FREE games: FORMAT: GAME{game_id}_USER{user_hash}_FREE_TIME{timestamp} ================================================================================ PAYMENT FLOW - Step by Step ================================================================================ STEP 1: User Clicks "Buy Now" Button ------------------------------------- Client: speedotslauncher.py calls get_paypal_payment_url() Server: speedstore.php -> getPayPalButton() - Generates unique product_id - Returns PayPal URL with parameters: • item_number = product_id • item_name = game title • amount = price • custom = JSON with {user_email, game_id, product_id} STEP 2: PayPal Checkout ------------------------------------- User is redirected to PayPal sandbox/live PayPal URL contains all purchase data User logs in and completes payment STEP 3: PayPal Success Redirect ------------------------------------- PayPal redirects to: payment_success.php?token=XXX&PayerID=YYY&... Success page displays: ✓ PayPal Token (transaction identifier) ✓ Product ID (your proof of purchase) ✓ Amount paid ✓ Game name ✓ User email STEP 4: PayPal IPN (Background - Most Important!) ------------------------------------- PayPal sends IPN notification to: paypal_ipn.php IPN Handler (paypal_ipn.php): 1. Receives POST data from PayPal 2. Verifies with PayPal (VERIFIED or INVALID) 3. Extracts data: - txn_id = PayPal transaction ID - item_number = our product_id - custom = JSON with {user_email, game_id, product_id} 4. Checks for duplicates (by txn_id OR product_id) 5. Validates payment status = "Completed" 6. Looks up game by game_id 7. Verifies amount paid matches game price 8. Creates receipt with: - receipt_token (64-char hex) - product_id (from PayPal) - game_id - user_email - transaction_id (from PayPal) - amount_paid - status = 'active' 9. Creates purchase record 10. Increments download counter STEP 5: Receipt Created ------------------------------------- Database now has: - receipts table: permanent ownership record - purchases table: transaction history User can verify ownership by: - receipt_token - product_id - user_email ================================================================================ DATABASE TABLES ================================================================================ published_games --------------- - id (server game ID) - title, developer, price - local_game_id (client's local ID) - executable_path (for launching) - vendor_paypal_email - vendor_payout_percentage (85%) - platform_fee_percentage (15%) receipts -------- - id - receipt_token (64-char unique token) - product_id (GAME{X}_USER{Y}_TIME{Z}) ← YOUR PROOF - game_id (links to published_games) - user_email - game_title, game_developer - amount_paid - is_free (0 for paid, 1 for free) - transaction_id (PayPal txn_id) - status (active/revoked/expired) purchases --------- - id - game_id - buyer_email - amount_paid - vendor_amount (85% of price) - platform_fee (15% of price) - transaction_id - status ================================================================================ VERIFICATION SYSTEM ================================================================================ Users can verify their ownership by: 1. Receipt Token: GET receipt_verify.html?token=RECEIPT_TOKEN 2. User Email (all games): GET receipt_verify.html?email=user@example.com 3. Product ID (proof of purchase): Query: SELECT * FROM receipts WHERE product_id = 'GAME7_USER1a2b_TIME1760...' Each method returns: - game_title, game_developer - amount_paid - claimed_at (purchase date) - transaction_id (PayPal verification) - status (active/revoked) ================================================================================ CLIENT INTEGRATION ================================================================================ When launcher starts: 1. Fetch receipts for current user email 2. Match receipts to local published_games by server_id 3. Mark games as "owned" in UI 4. Allow download/launch for owned games When user buys game: 1. Click PayPal button 2. Browser opens PayPal checkout 3. User completes payment 4. PayPal redirects to success page 5. User closes browser 6. Launcher polls for new receipts 7. Game appears in library automatically ================================================================================ SECURITY FEATURES ================================================================================ ✓ PayPal IPN verification (PayPal confirms transaction is real) ✓ Unique product_id prevents replay attacks ✓ Transaction ID prevents duplicates ✓ Amount verification (paid amount must match game price) ✓ Receipt tokens are cryptographically random (64 hex chars) ✓ Custom field uses JSON to prevent tampering ✓ Receipts have status field (can be revoked) ================================================================================ FREE GAMES FLOW ================================================================================ Same flow but simplified: 1. User clicks "Play for Free" 2. Client calls claim_game API 3. Server checks price == 0 4. Generates product_id with "_FREE_" marker 5. Creates receipt immediately (no PayPal) 6. Returns receipt_token 7. Client saves to local receipts table ================================================================================ TROUBLESHOOTING ================================================================================ "Game not found" when clicking PayPal button: → Store tab is passing local game ID instead of server ID → FIX: Updated store_games query to use server_id field "Receipt not created after payment": → PayPal IPN might be failing → CHECK: paypal_ipn.log file on server → CHECK: PayPal IPN history in PayPal account → CHECK: IPN URL is accessible (not localhost) "Product ID not matching": → custom field not being parsed correctly → FIX: Updated IPN to json_decode custom field Payment successful but game not in library: → Receipt created but client not polling → FIX: Restart launcher or manually call verify_receipt ================================================================================ TESTING WITH SANDBOX ================================================================================ 1. Create PayPal Sandbox account at developer.paypal.com 2. Create test buyer and seller accounts 3. Set USE_SANDBOX = true in paypal_ipn.php 4. Use sandbox email in vendor_paypal_email 5. Use sandbox.paypal.com URL in getPayPalButton() 6. Test with sandbox credentials 7. Check IPN simulator: developer.paypal.com/developer/ipnSimulator ================================================================================ PRODUCTION CHECKLIST ================================================================================ Before going live: □ Set USE_SANDBOX = false in paypal_ipn.php □ Use real PayPal email in vendor_paypal_email □ Use live PayPal URL (https://www.paypal.com/cgi-bin/webscr) □ Set live IPN URL (https://ipnpb.paypal.com/cgi-bin/webscr) □ Test IPN is publicly accessible □ Enable IPN in PayPal account settings □ Set up email notifications for receipts □ Monitor paypal_ipn.log regularly □ Test with small amounts first □ Have refund policy ready ================================================================================