Skip to main content

Webhooks

Real-time notifications for RegPilot events.
Webhook support is coming soon in Q1 2026. This documentation describes the planned implementation.

Overview

Webhooks allow you to receive real-time notifications when events occur in RegPilot.

Supported Events

Alert Events

  • alert.created - New alert triggered
  • alert.acknowledged - Alert acknowledged by user
  • alert.resolved - Alert marked as resolved

Case Events

  • case.created - New case opened
  • case.updated - Case status changed
  • case.resolved - Case closed

Compliance Events

  • violation.detected - New violation found
  • violation.resolved - Violation fixed
  • compliance.score_changed - Compliance score updated

Usage Events

  • usage.threshold_reached - Credit usage milestone
  • usage.limit_exceeded - Credit limit hit

Setup (Coming Soon)

Register Webhook

const response = await fetch('https://regpilot.dev/api/webhooks', {
  method: 'POST',
  headers: {
    'X-API-Key': process.env.REGPILOT_API_KEY!,
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    url: 'https://your-app.com/webhooks/regpilot',
    events: ['alert.created', 'case.created', 'violation.detected'],
    secret: 'your_webhook_secret' // For signature verification
  })
});

Webhook Payload

{
  id: string,              // Event ID
  type: string,           // Event type (e.g., 'alert.created')
  timestamp: string,      // ISO 8601 timestamp
  project_id: string,     // Project ID
  data: {
    // Event-specific data
  }
}

Example Payloads

alert.created:
{
  "id": "evt_abc123",
  "type": "alert.created",
  "timestamp": "2025-11-17T12:00:00Z",
  "project_id": "proj_xyz789",
  "data": {
    "alert_id": "alert_123",
    "severity": "HIGH",
    "title": "High risk content detected",
    "message": "AI response had risk score of 85"
  }
}
violation.detected:
{
  "id": "evt_def456",
  "type": "violation.detected",
  "timestamp": "2025-11-17T12:00:00Z",
  "project_id": "proj_xyz789",
  "data": {
    "violation_id": "viol_456",
    "type": "PRIVACY",
    "severity": "CRITICAL",
    "description": "PII detected in response"
  }
}

Receiving Webhooks

Basic Handler

// app/api/webhooks/regpilot/route.ts (Next.js)
export async function POST(request: Request) {
  const payload = await request.json();
  
  // Verify signature (recommended)
  const signature = request.headers.get('x-regpilot-signature');
  if (!verifySignature(payload, signature)) {
    return Response.json({ error: 'Invalid signature' }, { status: 401 });
  }
  
  // Handle event
  switch (payload.type) {
    case 'alert.created':
      await handleAlertCreated(payload.data);
      break;
    
    case 'violation.detected':
      await handleViolationDetected(payload.data);
      break;
    
    default:
      console.log('Unhandled event:', payload.type);
  }
  
  return Response.json({ received: true });
}

Express Handler

app.post('/webhooks/regpilot', express.json(), async (req, res) => {
  const payload = req.body;
  
  // Verify signature
  const signature = req.headers['x-regpilot-signature'];
  if (!verifySignature(payload, signature)) {
    return res.status(401).json({ error: 'Invalid signature' });
  }
  
  // Handle event
  try {
    switch (payload.type) {
      case 'alert.created':
        await handleAlert(payload.data);
        break;
      
      case 'case.created':
        await handleCase(payload.data);
        break;
    }
    
    res.json({ received: true });
  } catch (error) {
    console.error('Webhook error:', error);
    res.status(500).json({ error: 'Processing failed' });
  }
});

Signature Verification

import crypto from 'crypto';

function verifySignature(payload: any, signature: string | null): boolean {
  if (!signature) return false;
  
  const secret = process.env.WEBHOOK_SECRET!;
  const expectedSignature = crypto
    .createHmac('sha256', secret)
    .update(JSON.stringify(payload))
    .digest('hex');
  
  return crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(expectedSignature)
  );
}

Best Practices

1. Verify Signatures

Always verify webhook signatures to ensure authenticity:
if (!verifySignature(payload, signature)) {
  return Response.json({ error: 'Unauthorized' }, { status: 401 });
}

2. Respond Quickly

Return 200 OK immediately, process asynchronously:
export async function POST(request: Request) {
  const payload = await request.json();
  
  // Queue for async processing
  await queue.add(payload);
  
  // Respond immediately
  return Response.json({ received: true });
}

3. Handle Retries

RegPilot will retry failed webhooks:
  • Retry Schedule: 1min, 5min, 15min, 1hr, 6hr
  • Max Attempts: 5
  • Status Codes: 200-299 considered success

4. Idempotency

Handle duplicate deliveries:
const processedEvents = new Set<string>();

async function handleWebhook(payload: any) {
  if (processedEvents.has(payload.id)) {
    return; // Already processed
  }
  
  // Process event
  await processEvent(payload);
  
  processedEvents.add(payload.id);
}

Testing

Local Testing with ngrok

# Start ngrok
ngrok http 3000

# Use ngrok URL for webhook
# https://abc123.ngrok.io/webhooks/regpilot

Test Event (Coming Soon)

// Trigger test webhook
await fetch('https://regpilot.dev/api/webhooks/test', {
  method: 'POST',
  headers: {
    'X-API-Key': process.env.REGPILOT_API_KEY!,
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    webhook_id: 'webhook_123',
    event_type: 'alert.created'
  })
});

Management

List Webhooks

GET https://regpilot.dev/api/webhooks

Update Webhook

PATCH https://regpilot.dev/api/webhooks/{webhook_id}

Delete Webhook

DELETE https://regpilot.dev/api/webhooks/{webhook_id}

Status: Coming Q1 2026
Contact: webhooks@regpilot.dev for early access
Related: Best Practices | Troubleshooting