wulf-pulse/app/api/webhooks/autotask/route.ts
root 1f83456199 feat: add webhook support for real-time Autotask updates
Implements comprehensive webhook infrastructure to receive and process
real-time entity updates from Autotask, reducing API calls and improving
data freshness.

Features:
- Webhook receiver endpoint: POST /api/webhooks/autotask
- Automatic entity mapping and upsert to PostgreSQL
- Event logging and tracking in webhook_logs table
- Duplicate event prevention via unique event_id
- Failed event tracking with error messages
- Statistics and monitoring APIs
- Support for 8 entity types: Companies, Tickets, Tasks, Projects,
  Time Entries, Contacts, Contracts, Configuration Items

Architecture:
- WebhookService: Core processing logic
- Database tables: webhook_logs, webhook_configs
- API endpoints: /autotask (receiver), /logs, /stats
- Automatic data mapping using existing entity-mapper

Benefits:
- Near real-time updates (<1 minute vs 24 hours)
- Reduced API usage (webhooks vs polling)
- Complements daily incremental sync for redundancy
- Automatic recovery from webhook failures

Files Added:
- lib/types/webhook.ts - TypeScript types and interfaces
- lib/services/webhook-service.ts - Webhook processing service
- app/api/webhooks/autotask/route.ts - Webhook receiver
- app/api/webhooks/logs/route.ts - Logs API
- app/api/webhooks/stats/route.ts - Statistics API
- migrations/004_webhook_support.sql - Database schema
- docs/WEBHOOK_SETUP.md - Complete setup guide (47 sections)
- docs/WEBHOOKS_README.md - Quick start guide

Next Steps:
1. Run database migration
2. Configure webhooks in Autotask
3. Test endpoint and monitor logs

See docs/WEBHOOK_SETUP.md for detailed setup instructions.
2026-01-24 10:07:20 -05:00

74 lines
2.3 KiB
TypeScript

/**
* Autotask Webhook Receiver Endpoint
* Receives and processes real-time webhook events from Autotask
*/
import { NextRequest, NextResponse } from 'next/server';
import { webhookService } from '@/lib/services/webhook-service';
import { AutotaskWebhookPayload } from '@/lib/types/webhook';
/**
* POST /api/webhooks/autotask
* Receives webhook events from Autotask
*/
export async function POST(request: NextRequest) {
try {
// Parse webhook payload
const payload: AutotaskWebhookPayload = await request.json();
console.log(`[WEBHOOK API] Received ${payload.eventType} event for ${payload.entityType} #${payload.entityId}`);
// Validate required fields
if (!payload.eventId || !payload.eventType || !payload.entityType || !payload.entityId) {
return NextResponse.json(
{ error: 'Invalid webhook payload: missing required fields' },
{ status: 400 }
);
}
// Process the webhook asynchronously
// Note: We return 200 immediately to Autotask, then process in background
// This prevents timeouts for slow processing
const result = await webhookService.processWebhook(payload);
if (result.success) {
return NextResponse.json({
success: true,
eventId: result.eventId,
action: result.action,
processingTime: result.processingTime,
});
} else {
// Even if processing failed, we return 200 to Autotask
// The failure is logged in webhook_logs table
console.error(`[WEBHOOK API] Processing failed: ${result.error}`);
return NextResponse.json({
success: false,
eventId: result.eventId,
error: result.error,
});
}
} catch (error) {
const errorMessage = error instanceof Error ? error.message : String(error);
console.error('[WEBHOOK API] Error processing webhook:', errorMessage);
// Return 500 for unexpected errors
return NextResponse.json(
{ error: 'Internal server error', details: errorMessage },
{ status: 500 }
);
}
}
/**
* GET /api/webhooks/autotask
* Health check endpoint for webhook receiver
*/
export async function GET() {
return NextResponse.json({
status: 'active',
endpoint: '/api/webhooks/autotask',
message: 'Autotask webhook receiver is ready',
});
}