Phase 11: Webhooks & Analytics
Implement outbound webhooks with HMAC-SHA256 signatures and an analytics service that detects licensing abuse patterns.
Files Written
Section titled “Files Written”src/Services/WebhookService.phpsrc/Services/AnalyticsService.php
WebhookService
Section titled “WebhookService”Registration
Section titled “Registration”Merchants register webhook endpoints via POST /wplm/v1/webhooks:
{ "url": "https://example.com/webhook", "events": ["license.created", "license.revoked", "subscription.renewed"]}Each endpoint gets a unique per-endpoint HMAC secret (32 random bytes) so different endpoints can be individually invalidated.
Dispatch
Section titled “Dispatch”$webhook_svc->dispatch('license.revoked', $license->to_array());Internally:
- Load all webhook records that subscribe to
license.revoked. - Build JSON payload with
event,data, anddelivered_at. - Compute
HMAC-SHA256(secret, payload). - Send
POSTviawp_remote_post()with headerX-WPLM-Signature: sha256=<hex>. - Store delivery log (status code, response, duration).
Merchants verify:
$expected = hash_hmac('sha256', file_get_contents('php://input'), $secret);hash_equals($expected, $received_sig); // timing-safeWebhook Events
Section titled “Webhook Events”license.created | license.activated | license.deactivated | license.revoked | license.suspended | license.terminated | license.expired | subscription.created | subscription.renewed | subscription.payment_failed | subscription.cancelled
AnalyticsService
Section titled “AnalyticsService”Overview
Section titled “Overview”get_overview() returns aggregate stats with a 10-minute transient cache:
[ 'active_licenses' => int, 'inactive_licenses' => int, 'expiring_soon' => int, // expires within 30 days 'active_machines' => int, 'revenue_mtd' => float, 'renewals_today' => int,]Anomaly Detection
Section titled “Anomaly Detection”detect_anomalies() runs three checks:
| Anomaly | Threshold | Signal |
|---|---|---|
| Fingerprint churn | > 5 new devices for 1 license in 24 h | Possible key sharing / cracking |
| Validation spike | Current-hour rate > 3× 7-day hourly average | Bot scraping or brute force |
| Impossible travel | > 2 distinct countries for 1 license in 1 h | Credential sharing or VPN rotation |
When an anomaly is detected:
do_action('wplm_anomaly_detected', $type, $license_id, $detail);Default handler logs to the audit log. Merchants can hook this action to send Slack alerts, suspend the license automatically, etc.
Both get_overview() and detect_anomalies() are exposed via the REST API at /wplm/v1/analytics/*.