import { NextResponse } from 'next/server'; import { supabase } from '@/lib/db'; import crypto from 'crypto'; // The webhook secret from your Sell.app developer dashboard const SELLAPP_SECRET = process.env.SELLAPP_WEBHOOK_SECRET || 'dummy_secret'; export async function POST(request: Request) { try { const rawBody = await request.text(); const headersList = request.headers; // Sell.app uses the standard 'x-sellapp-signature' header. const signature = headersList.get('x-sellapp-signature'); if (!signature) { return NextResponse.json({ error: 'Missing signature' }, { status: 401 }); } // Verify Sell.app Signature const hmac = crypto.createHmac('sha256', SELLAPP_SECRET); hmac.update(rawBody); const calculatedSignature = hmac.digest('hex'); if (signature !== calculatedSignature && process.env.NODE_ENV === 'production') { return NextResponse.json({ error: 'Invalid signature' }, { status: 403 }); } const data = JSON.parse(rawBody); // Safety check: is it an order completion? if (data.event !== 'order:paid' && data.event !== 'order:completed') { return NextResponse.json({ received: true }); } const order = data.data; const additionalInfo = order.additional_information || []; // We search through the additional_information array for the "discord_id" custom field. const discordField = additionalInfo.find((field: any) => field.name?.toLowerCase() === 'discord_id'); const discordId = discordField ? discordField.value : null; if (!discordId) { console.error("Webhook Error: Discord ID was not provided in custom fields."); return NextResponse.json({ error: 'Missing Discord ID' }, { status: 400 }); } // Sell.app typically returns total in major units (e.g., 25.00 instead of 2500) const price = parseFloat(order.total_amount || order.total); let expiresAt: string | null = null; const now = new Date(); if (price === 3) { now.setDate(now.getDate() + 7); expiresAt = now.toISOString(); } else if (price === 7) { now.setDate(now.getDate() + 30); expiresAt = now.toISOString(); } else if (price === 15) { now.setFullYear(now.getFullYear() + 1); expiresAt = now.toISOString(); } else if (price === 25) { expiresAt = null; } else { console.warn(`Unrecognized price tier: $${price}. Applying lifetime by default.`); expiresAt = null; } // Save to database using Supabase const { error: upsertError } = await supabase .from('vip_users') .upsert({ discord_id: discordId, expires_at: expiresAt, purchased_at: new Date().toISOString() }, { onConflict: 'discord_id' }); if (upsertError) throw upsertError; console.log(`[SELLAPP WEBHOOK] Successfully unlocked VIP for Discord ID: ${discordId}`); return NextResponse.json({ success: true }); } catch (error) { console.error('Webhook processing failed:', error); return NextResponse.json({ error: 'Internal Server Error' }, { status: 500 }); } }