import { NextRequest, NextResponse } from 'next/server' import pool from '@/lib/db' import { getNowPaymentsConfig } from '@/lib/nowpayments' // POST /api/payments/cleanup-expired - Clean up expired pending orders // This endpoint should be called periodically (e.g., via cron job every minute) export async function POST(request: NextRequest) { try { // Optional: Add authentication/authorization check here // For security, you might want to require an API key or admin authentication const authHeader = request.headers.get('authorization') const expectedToken = process.env.CLEANUP_API_TOKEN if (expectedToken && authHeader !== `Bearer ${expectedToken}`) { return NextResponse.json( { error: 'Unauthorized' }, { status: 401 } ) } // Find all expired pending orders const [expiredRows] = await pool.execute( 'SELECT * FROM pending_orders WHERE expires_at < NOW()', ) const expiredOrders = expiredRows as any[] if (expiredOrders.length === 0) { return NextResponse.json({ message: 'No expired orders to clean up', cleaned: 0, }) } const nowPaymentsConfig = getNowPaymentsConfig() let cleanedCount = 0 const errors: string[] = [] // Process each expired order for (const order of expiredOrders) { try { // Try to cancel the NOWPayments invoice if it still exists // Note: NOWPayments may not have a direct cancel endpoint, but we can try // to check the status and handle accordingly try { const statusResponse = await fetch( `${nowPaymentsConfig.baseUrl}/v1/payment/${order.payment_id}`, { method: 'GET', headers: { 'x-api-key': nowPaymentsConfig.apiKey, 'Content-Type': 'application/json', }, } ) if (statusResponse.ok) { const paymentStatus = await statusResponse.json() // If payment is still pending/waiting, we can consider it expired // NOWPayments will handle the expiration on their end based on invoice_timeout console.log(`Payment ${order.payment_id} status:`, paymentStatus.payment_status) } } catch (apiError) { // Invoice might already be expired/cancelled on NOWPayments side console.log(`Could not check status for payment ${order.payment_id}:`, apiError) } // Delete the expired pending order await pool.execute('DELETE FROM pending_orders WHERE id = ?', [order.id]) cleanedCount++ console.log(`Cleaned up expired pending order ${order.id} (payment_id: ${order.payment_id})`) } catch (error) { const errorMsg = `Error cleaning up order ${order.id}: ${error}` console.error(errorMsg) errors.push(errorMsg) } } return NextResponse.json({ message: `Cleaned up ${cleanedCount} expired pending orders`, cleaned: cleanedCount, total: expiredOrders.length, errors: errors.length > 0 ? errors : undefined, }) } catch (error) { console.error('Error in cleanup endpoint:', error) return NextResponse.json( { error: 'Failed to clean up expired orders' }, { status: 500 } ) } } // GET /api/payments/cleanup-expired - Get status of expired orders (for monitoring) export async function GET() { try { const [expiredRows] = await pool.execute( 'SELECT COUNT(*) as count FROM pending_orders WHERE expires_at < NOW()', ) const result = expiredRows as any[] const expiredCount = result[0]?.count || 0 return NextResponse.json({ expired_orders_count: expiredCount, message: expiredCount > 0 ? `There are ${expiredCount} expired pending orders that need cleanup` : 'No expired orders', }) } catch (error) { console.error('Error checking expired orders:', error) return NextResponse.json( { error: 'Failed to check expired orders' }, { status: 500 } ) } }