| import { NextResponse } from 'next/server'; |
| import { supabase } from '@/lib/db'; |
| import crypto from 'crypto'; |
|
|
| |
| 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; |
| |
| |
| const signature = headersList.get('x-sellapp-signature'); |
|
|
| if (!signature) { |
| return NextResponse.json({ error: 'Missing signature' }, { status: 401 }); |
| } |
|
|
| |
| 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); |
| |
| |
| if (data.event !== 'order:paid' && data.event !== 'order:completed') { |
| return NextResponse.json({ received: true }); |
| } |
|
|
| const order = data.data; |
| const additionalInfo = order.additional_information || []; |
| |
| |
| 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 }); |
| } |
|
|
| |
| 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; |
| } |
|
|
| |
| 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 }); |
| } |
| } |
|
|