Camwhores.v «No Login»

Camwhores.v «No Login»

-- Plans (subscription tiers) CREATE TABLE subscription_plans ( id BIGSERIAL PRIMARY KEY, name VARCHAR(100) NOT NULL, price_cents INTEGER NOT NULL, -- stored in cents interval VARCHAR(10) NOT NULL, -- 'month' or 'year' description TEXT );

if (loading) return <p>Loading…</p>;

// 2️⃣ Create Stripe Checkout session const session = await stripe.checkout.sessions.create( payment_method_types: ['card'], line_items: [ price_data: currency: 'usd', product_data: name: `PPV: $stream.title`, , unit_amount: stream.price_cents, , quantity: 1, ], mode: 'payment', success_url: `$process.env.FRONTEND_URL/stream/$stream.id?session_id=CHECKOUT_SESSION_ID`, cancel_url: `$process.env.FRONTEND_URL/stream/$stream.id`, metadata: userId, streamId: stream.id, , ); camwhores.v

-- Subscriptions (active recurring) CREATE TABLE user_subscriptions ( id BIGSERIAL PRIMARY KEY, user_id BIGINT REFERENCES users(id) ON DELETE CASCADE, plan_id BIGINT REFERENCES subscription_plans(id), stripe_sub_id VARCHAR(255) UNIQUE, status VARCHAR(20) CHECK (status IN ('active','canceled','past_due')), current_period_end TIMESTAMP, created_at TIMESTAMP DEFAULT NOW() ); name VARCHAR(100) NOT NULL

router.post('/webhooks/stripe', express.raw(type: 'application/json'), async (req, res) => const sig = req.headers['stripe-signature']; let event; price_cents INTEGER NOT NULL