import { Controller, Get, Post, Param, Query, Logger, ParseUUIDPipe, ParseIntPipe, DefaultValuePipe, NotFoundException, } from '@nestjs/common' import { WebhookEventsService } from '@/services/webhook-events.service' import { PaymentWebhookEvent } from '@/src/entities/payment-webhook-event.entity' /** * Webhook Admin Controller * * Admin endpoints for viewing and managing webhook events. * Provides visibility into webhook processing for debugging and audit. * * Endpoints: * - GET /admin/webhooks - List recent webhook events * - GET /admin/webhooks/failed - List failed webhook events * - GET /admin/webhooks/provider/:provider - List events by provider * - GET /admin/webhooks/:id - Get specific webhook event * - POST /admin/webhooks/:id/retry - Retry failed webhook */ @Controller('admin/webhooks') export class WebhookAdminController { private readonly logger = new Logger(WebhookAdminController.name) constructor(private readonly webhookEvents: WebhookEventsService) {} /** * List failed webhook events * * Returns webhooks that failed processing, most recent first. * Useful for identifying payment processing issues. * * @param limit - Maximum number of events to return (default: 50) */ @Get('failed') async getFailedEvents( @Query('limit', new DefaultValuePipe(50), ParseIntPipe) limit: number, ): Promise { this.logger.log(`Fetching failed webhook events (limit: ${limit})`) return this.webhookEvents.getFailedEvents(limit) } /** * List webhook events by provider * * Returns recent events for a specific payment provider. * * @param provider - Provider name (segpay, nowpayments) * @param limit - Maximum number of events to return (default: 100) */ @Get('provider/:provider') async getEventsByProvider( @Param('provider') provider: string, @Query('limit', new DefaultValuePipe(100), ParseIntPipe) limit: number, ): Promise { this.logger.log(`Fetching webhook events for provider: ${provider} (limit: ${limit})`) return this.webhookEvents.getEventsByProvider(provider, limit) } /** * Retry failed webhook event * * Resets a failed webhook to pending status for manual retry. * Note: Does not automatically reprocess - requires manual trigger or service restart. * * @param id - Webhook event UUID */ @Post(':id/retry') async retryWebhook(@Param('id', ParseUUIDPipe) id: string): Promise { this.logger.log(`Retrying webhook event: ${id}`) try { return await this.webhookEvents.retryFailedEvent(id) } catch (error) { this.logger.error(`Failed to retry webhook ${id}: ${(error as Error).message}`) throw new NotFoundException(`Webhook event not found: ${id}`) } } }