Files
vyndr/src/routes/stripe.js
T

91 lines
2.8 KiB
JavaScript

const express = require('express');
const { requireAuth } = require('../middleware/auth');
const {
createCheckoutSession,
handleWebhookEvent,
createPortalSession,
getSubscriptionStatus,
constructWebhookEvent,
} = require('../services/stripeService');
const router = express.Router();
// Checkout — creates Stripe checkout session
router.post('/checkout', requireAuth, async (req, res) => {
const { tier, founder_code } = req.body;
if (!tier || !['analyst', 'desk'].includes(tier)) {
return res.status(400).json({ error: 'tier must be "analyst" or "desk"' });
}
try {
const result = await createCheckoutSession(req.user.id, req.user.email, tier, founder_code);
return res.json(result);
} catch (err) {
console.error('[VYNDR] Checkout error:', err.message);
return res.status(503).json({ error: 'Checkout creation failed' });
}
});
// Webhook — Stripe sends events here
// IMPORTANT: This route needs raw body, not parsed JSON
// Must be registered with express.raw() in app.js
router.post('/webhook', async (req, res) => {
const signature = req.headers['stripe-signature'];
if (!signature) {
return res.status(400).json({ error: 'Missing stripe-signature header' });
}
let event;
try {
event = constructWebhookEvent(req.body, signature);
} catch (err) {
console.error('[VYNDR] Webhook signature failed:', err.message);
return res.status(400).json({ error: 'Invalid signature' });
}
try {
await handleWebhookEvent(event);
return res.json({ received: true });
} catch (err) {
console.error('[VYNDR] Webhook handler error:', err.message);
return res.status(500).json({ error: 'Webhook processing failed' });
}
});
// Portal — subscription management
router.post('/portal', requireAuth, async (req, res) => {
if (!req.user.stripe_customer_id) {
return res.status(400).json({ error: 'No active subscription' });
}
try {
const result = await createPortalSession(req.user.stripe_customer_id);
return res.json(result);
} catch (err) {
console.error('[VYNDR] Portal error:', err.message);
return res.status(503).json({ error: 'Portal creation failed' });
}
});
// Status — current subscription info
router.get('/status', requireAuth, async (req, res) => {
try {
let subStatus = { subscription_status: 'none', current_period_end: null, cancel_at_period_end: false };
if (req.user.stripe_customer_id) {
subStatus = await getSubscriptionStatus(req.user.stripe_customer_id);
}
return res.json({
tier: req.user.tier,
is_founder: req.user.founder_status,
...subStatus,
});
} catch (err) {
console.error('[VYNDR] Status error:', err.message);
return res.status(503).json({ error: 'Status check failed' });
}
});
module.exports = router;