diff --git a/README.md b/README.md index 41b9ee9..e69ca77 100644 --- a/README.md +++ b/README.md @@ -217,6 +217,34 @@ All application and email settings are now managed through the **Settings** page 4. Copy the webhook URL 5. Add it in the notification group settings +#### 🌐 Webhook (Custom) + +Send JSON payloads to any HTTP endpoint (e.g., n8n, Zapier, Make, your own API): + +1. Go to Notification Groups → Edit → Add Channel +2. Choose "Webhook (Custom)" +3. Paste your endpoint URL (HTTPS recommended) +4. Click "Test Channel" to verify + +Payload example sent on domain alerts: + +```json +{ + "event": "domain_expiration_alert", + "message": "⚠️ WARNING: Domain 'example.com' expires in 7 days (January 30, 2026)!\n\nRegistrar: Example Registrar\nPlease renew soon.", + "data": { + "domain": "example.com", + "domain_id": 123, + "days_left": 7, + "expiration_date": "2026-01-30", + "registrar": "Example Registrar" + }, + "sent_at": "2025-10-17T12:34:56Z" +} +``` + +Use this with n8n's "Webhook" trigger to start flows. + ## 📅 Setting Up Cron Jobs The application requires a cron job to check domains periodically. diff --git a/app/Controllers/NotificationGroupController.php b/app/Controllers/NotificationGroupController.php index db5eefd..d4fd843 100644 --- a/app/Controllers/NotificationGroupController.php +++ b/app/Controllers/NotificationGroupController.php @@ -214,6 +214,7 @@ class NotificationGroupController extends Controller break; case 'discord': case 'slack': + case 'webhook': $missingField = 'webhook URL'; break; } @@ -427,6 +428,17 @@ class NotificationGroupController extends Controller } return ['webhook_url' => $webhookUrl]; + case 'webhook': + $webhookUrl = trim($data['webhook_url'] ?? ''); + if (empty($webhookUrl) || !filter_var($webhookUrl, FILTER_VALIDATE_URL)) { + return null; + } + // Optional: Allow any HTTPS URL; prefer HTTPS for security + if (!str_starts_with($webhookUrl, 'https://') && !str_starts_with($webhookUrl, 'http://')) { + return null; + } + return ['webhook_url' => $webhookUrl]; + default: return null; } diff --git a/app/Services/Channels/WebhookChannel.php b/app/Services/Channels/WebhookChannel.php new file mode 100644 index 0000000..7900f7a --- /dev/null +++ b/app/Services/Channels/WebhookChannel.php @@ -0,0 +1,48 @@ +httpClient = new Client(['timeout' => 10]); + } + + public function send(array $config, string $message, array $data = []): bool + { + $url = trim($config['webhook_url'] ?? ''); + if (empty($url)) { + return false; + } + + // Build a sane, generic JSON payload for automation tools (n8n, Zapier, etc.) + $payload = [ + 'event' => 'domain_expiration_alert', + 'message' => $message, + 'data' => $data, + 'sent_at' => date('c') + ]; + + try { + $response = $this->httpClient->post($url, [ + 'headers' => [ + 'Content-Type' => 'application/json' + ], + 'json' => $payload + ]); + + $status = $response->getStatusCode(); + return $status >= 200 && $status < 300; + } catch (\Exception $e) { + error_log('Webhook send failed: ' . $e->getMessage()); + return false; + } + } +} + + diff --git a/app/Services/NotificationService.php b/app/Services/NotificationService.php index 7badf6a..cef98db 100644 --- a/app/Services/NotificationService.php +++ b/app/Services/NotificationService.php @@ -6,6 +6,7 @@ use App\Services\Channels\EmailChannel; use App\Services\Channels\TelegramChannel; use App\Services\Channels\DiscordChannel; use App\Services\Channels\SlackChannel; +use App\Services\Channels\WebhookChannel; class NotificationService { @@ -18,6 +19,7 @@ class NotificationService 'telegram' => new TelegramChannel(), 'discord' => new DiscordChannel(), 'slack' => new SlackChannel(), + 'webhook' => new WebhookChannel(), ]; } diff --git a/app/Views/groups/edit.php b/app/Views/groups/edit.php index fbec48b..424e2d3 100644 --- a/app/Views/groups/edit.php +++ b/app/Views/groups/edit.php @@ -78,9 +78,9 @@ ob_start();
+ Will receive JSON payload compatible with n8n/Zapier/Make. +
+Configure 2FA policy and security settings
+Configure 2FA policy and security settings
+