fix: update checkout endpoint to accept tier_level from website

Changed endpoint parameters from (priceId, discordId) to just (tier_level).

ISSUE:
Website sends: { tier_level: 1 }
Endpoint expected: { priceId, discordId }
Result: 400 error 'Missing priceId or discordId'

FIX:
- Accept tier_level from request body
- Look up stripe_price_id from stripe_products table
- Determine billing_type (one-time vs subscription)
- Create checkout session without requiring discordId
- Simplified for public checkout flow (no user tracking yet)

SIMPLIFIED CHECKOUT:
- No user verification required
- No Discord linking required
- Stripe collects email during checkout
- Webhook will handle subscription creation later

FILES MODIFIED:
- services/arbiter-3.0/src/routes/stripe.js (45 lines changed)

TESTING:
- Click Subscribe button on website
- Should now create Stripe checkout session successfully
- Should redirect to Stripe payment page

Signed-off-by: Claude (Chronicler #57) <claude@firefrostgaming.com>
This commit is contained in:
Claude (Chronicler #57)
2026-04-03 16:28:11 +00:00
parent 543167fbce
commit 9de3e6e074

View File

@@ -31,33 +31,24 @@ router.options('/create-checkout-session', cors(corsOptions));
*/
router.post('/create-checkout-session', cors(corsOptions), async (req, res) => {
try {
const { priceId, discordId } = req.body;
const { tier_level } = req.body;
if (!priceId || !discordId) {
return res.status(400).json({ error: 'Missing priceId or discordId' });
if (!tier_level) {
return res.status(400).json({ error: 'Missing tier_level' });
}
// Verify user exists
const userResult = await db.query(
'SELECT discord_id, username FROM users WHERE discord_id = $1',
[discordId]
);
if (userResult.rows.length === 0) {
return res.status(404).json({ error: 'User not found. Please link your Discord account first.' });
}
// Lookup product to determine billing mode
// Get Stripe Price ID from database based on tier level
const productResult = await db.query(
'SELECT tier_level, tier_name, billing_type FROM stripe_products WHERE stripe_price_id = $1',
[priceId]
'SELECT stripe_price_id, tier_name, billing_type FROM stripe_products WHERE tier_level = $1',
[tier_level]
);
if (productResult.rows.length === 0) {
return res.status(400).json({ error: 'Invalid product selected' });
return res.status(404).json({ error: 'Invalid tier level' });
}
const product = productResult.rows[0];
const priceId = product.stripe_price_id;
const billingMode = product.billing_type === 'one-time' ? 'payment' : 'subscription';
// Create Stripe Checkout Session
@@ -65,39 +56,17 @@ router.post('/create-checkout-session', cors(corsOptions), async (req, res) => {
payment_method_types: ['card'],
line_items: [{ price: priceId, quantity: 1 }],
mode: billingMode,
success_url: `${process.env.BASE_URL || 'https://discord-bot.firefrostgaming.com'}/checkout/success?session_id={CHECKOUT_SESSION_ID}`,
cancel_url: `${process.env.BASE_URL || 'https://discord-bot.firefrostgaming.com'}/checkout/cancel`,
client_reference_id: discordId,
customer_email: userResult.rows[0].username ? `${userResult.rows[0].username}@firefrost.local` : undefined
success_url: 'https://firefrostgaming.com/success',
cancel_url: 'https://firefrostgaming.com/subscribe',
metadata: {
tier_level: tier_level.toString(),
tier_name: product.tier_name
}
};
// Metadata placement differs by mode
if (billingMode === 'subscription') {
sessionConfig.subscription_data = {
metadata: {
discord_id: discordId,
tier_level: product.tier_level.toString()
}
};
} else {
sessionConfig.payment_intent_data = {
metadata: {
discord_id: discordId,
tier_level: product.tier_level.toString()
}
};
}
const session = await stripe.checkout.sessions.create(sessionConfig);
// Log checkout creation
await db.query(
`INSERT INTO admin_audit_log (action_type, target_identifier, details, actor_discord_id)
VALUES ('CHECKOUT_CREATED', $1, $2, $3)`,
[discordId, JSON.stringify({ tier: product.tier_name, mode: billingMode }), discordId]
);
res.json({ url: session.url });
res.json({ checkout_url: session.url });
} catch (error) {
console.error('Checkout session error:', error);