Skip to content

Webhook Management Portal

A web-based portal for managing webhook endpoints, subscribing to event notifications, rotating signing secrets, and monitoring delivery health.

Environments

EnvironmentWebhook Portal URLPartner Portal URL
Sandboxhttps://webhook-portal-sandbox.k2cyber.cohttps://partners-sandbox.k2cyber.co
Productionhttps://webhook-portal.k2cyber.cohttps://partners.k2cyber.co

Sandbox First

Start your webhook integration in the sandbox environment. Test your endpoint signature verification and event handling before moving to production.

Overview

The Webhook Management Portal provides a user-friendly interface for:

  • Creating and managing HTTPS webhook endpoints (each with its own signing secret)
  • Subscribing to specific event types
  • Viewing delivery logs and monitoring endpoint health
  • Rotating endpoint signing secrets for security

Getting Started

Access Methods

There are two ways to access the Webhook Portal:

If you're already a registered Partner Portal user:

  1. Navigate to the Webhook Portal URL
  2. Click Sign In
  3. Enter your Partner Portal email and password
  4. Your account is automatically provisioned for webhook access

This is the recommended approach for partner administrators who already have Partner Portal credentials.

Option 2: Register with a Webhook Key

For team members who need webhook access but don't have Partner Portal accounts:

  1. Obtain a Webhook Key from your partner administrator (created in the Partner Portal)
  2. Navigate to the Webhook Portal URL
  3. Click Need an account? Register
  4. Enter your email, password, and the webhook key
  5. Complete registration

The webhook key associates your account with your organization's partner account.

Webhook Keys vs Signing Secrets

The Webhook Key from the Partner Portal is only used for registration. The signing secrets used to verify webhook deliveries are generated separately when you create an endpoint in this portal.

Managing Endpoints

Create an Endpoint

  1. Navigate to Endpoints in the dashboard
  2. Click Add Endpoint
  3. Enter your webhook URL (must be HTTPS)
  4. Optionally add a description for reference
  5. Click Create Endpoint

Signing Secret - One-Time Display

When you create an endpoint, a signing secret is generated and displayed once. This is the secret you'll use to verify webhook signatures in your application. Copy and store it securely immediately—it cannot be retrieved later.

After creating an endpoint, you'll be prompted to subscribe to events immediately, or you can skip and add subscriptions later.

Endpoint Requirements

  • Must use HTTPS (no HTTP or self-signed certificates in production)
  • Must be publicly accessible
  • Should respond with HTTP 2xx status codes within 8 seconds
  • Must validate webhook signatures (see Signature Verification below)

Subscribe to Events

After creating an endpoint, subscribe to the events you want to receive:

  1. Click Add Events or Manage Subscriptions from the endpoint actions menu
  2. Select from available event types
  3. Click Subscribe

Available Event Types

Beta Event Types

Only three event types are currently available. More event types will be added soon, and event names and payloads are subject to change during the beta period.

Event TypeDescription
quote.createdTriggered when a new quote is created
policy.createdTriggered when a new policy is created
broker.addedTriggered when a new broker is added to the system

You can subscribe to multiple events on a single endpoint.

Event Topics Catalog

The Webhook Portal dashboard features an Event Topics Catalog that displays:

  • All available event types grouped by category
  • Detailed descriptions for each event
  • Example payloads you can copy for testing

Use this catalog to understand the structure of webhook payloads before implementing your receiver.

Webhook Delivery Format

HTTP Headers

Each webhook delivery includes these headers:

HeaderDescription
Content-TypeAlways application/json
Event-IDUnique event identifier for idempotency
TimestampISO 8601 timestamp of the delivery attempt
X-Platform-SignatureHMAC-SHA256 signature for verification

Sample Payloads

quote.created

json
{
  "type": "quote.created",
  "timestamp": "2025-10-21T15:02:31Z",
  "brokerageId": "your-brokerage-id",
  "data": {
    "quoteId": "QTE-10293",
    "partnerId": "your-partner-id",
    "customer": {
      "name": "Jane Doe",
      "email": "jane.doe@email.com"
    },
    "product": "Cyber Insurance",
    "requestedDate": "2025-10-21",
    "status": "quoted"
  }
}

policy.created

json
{
  "type": "policy.created",
  "timestamp": "2025-10-21T15:02:31Z",
  "brokerageId": "your-brokerage-id",
  "data": {
    "policyId": "POL-10293",
    "partnerId": "your-partner-id",
    "customer": {
      "name": "Jane Doe",
      "email": "jane.doe@email.com"
    },
    "product": "Cyber Insurance",
    "effectiveDate": "2025-11-01",
    "status": "active"
  }
}

broker.added

json
{
  "type": "broker.added",
  "timestamp": "2025-10-21T15:02:31Z",
  "brokerageId": "your-brokerage-id",
  "data": {
    "brokerId": "BRK-78945",
    "brokerageName": "Acme Insurance Brokers",
    "contact": {
      "name": "John Smith",
      "email": "john.smith@acme-insurance.example"
    },
    "licensedStates": ["CA", "NY", "TX"],
    "addedDate": "2025-10-21"
  }
}

Signature Verification

Verify the X-Platform-Signature header to ensure webhooks are genuinely from K2. Use the signing secret that was generated when you created the endpoint.

Signature Format

The signature is computed as:

HMAC-SHA256(secret, "${Event-ID}.${Timestamp}.${RequestBody}")

The signature input is the concatenation of:

  1. The Event-ID header value
  2. A period (.)
  3. The Timestamp header value
  4. A period (.)
  5. The raw request body (JSON string)

Verification Example (Node.js)

javascript
const crypto = require('crypto');

function verifyWebhookSignature(req, secret) {
  const eventId = req.headers['event-id'];
  const timestamp = req.headers['timestamp'];
  const signature = req.headers['x-platform-signature'];
  const body = JSON.stringify(req.body);
  
  // Reconstruct the signed payload
  const signedPayload = `${eventId}.${timestamp}.${body}`;
  
  // Compute expected signature
  const expectedSignature = crypto
    .createHmac('sha256', secret)
    .update(signedPayload)
    .digest('hex');
  
  // Use timing-safe comparison
  return crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(expectedSignature)
  );
}

// Express.js example
const ENDPOINT_SIGNING_SECRET = process.env.WEBHOOK_SIGNING_SECRET;

app.post('/webhooks', express.json(), (req, res) => {
  if (!verifyWebhookSignature(req, ENDPOINT_SIGNING_SECRET)) {
    console.error('Invalid webhook signature');
    return res.status(401).send('Invalid signature');
  }
  
  // Signature valid - process the webhook
  const eventId = req.headers['event-id'];
  const eventType = req.body.type;
  
  console.log(`Received ${eventType} event: ${eventId}`);
  
  // Acknowledge receipt immediately
  res.status(200).send('OK');
  
  // Process asynchronously if needed...
});

Verification Example (Python)

python
import hmac
import hashlib
from flask import Flask, request, jsonify

app = Flask(__name__)
ENDPOINT_SIGNING_SECRET = os.environ.get('WEBHOOK_SIGNING_SECRET')

def verify_webhook_signature(request):
    event_id = request.headers.get('Event-ID')
    timestamp = request.headers.get('Timestamp')
    signature = request.headers.get('X-Platform-Signature')
    body = request.get_data(as_text=True)
    
    # Reconstruct the signed payload
    signed_payload = f"{event_id}.{timestamp}.{body}"
    
    # Compute expected signature
    expected_signature = hmac.new(
        ENDPOINT_SIGNING_SECRET.encode(),
        signed_payload.encode(),
        hashlib.sha256
    ).hexdigest()
    
    # Use timing-safe comparison
    return hmac.compare_digest(signature, expected_signature)

@app.route('/webhooks', methods=['POST'])
def handle_webhook():
    if not verify_webhook_signature(request):
        return jsonify({'error': 'Invalid signature'}), 401
    
    # Process the webhook
    event_type = request.json.get('type')
    event_id = request.headers.get('Event-ID')
    
    print(f"Received {event_type} event: {event_id}")
    
    return jsonify({'status': 'ok'}), 200

Delivery & Retry Logic

Timeout

K2 expects a 2xx HTTP response within 8 seconds. If your endpoint takes longer to respond, the delivery will be marked as failed and retried.

Retry Behavior

Failed deliveries are retried with exponential backoff:

AttemptDelay Before Retry
1Immediate
21 second
32 seconds
44 seconds
58 seconds
616 seconds
732 seconds
8+60 seconds (max)
  • Maximum of 10 delivery attempts per event
  • After 10 failed attempts, the delivery is marked as permanently failed

Circuit Breaker

To protect both your endpoint and our system, K2 implements a circuit breaker:

  • If an endpoint fails 5 times within 5 minutes, it is automatically disabled
  • Disabled endpoints stop receiving webhook deliveries
  • You can re-enable endpoints from the Webhook Portal after resolving the issue

Endpoint Disabled

If your endpoint is consistently failing, check the delivery logs for error details. Common issues include:

  • Endpoint not responding within 8 seconds
  • Endpoint returning non-2xx status codes
  • Network connectivity issues
  • Invalid SSL certificates

Monitoring Delivery Logs

The Logs page shows:

  • Recent delivery attempts for all endpoints
  • Success/failure status
  • HTTP response codes and response times
  • Retry attempt counts
  • Event payloads for debugging

Use the Event-ID header value to track specific deliveries and implement idempotency in your system.

Rotating Endpoint Signing Secrets

To rotate an endpoint's signing secret:

  1. Navigate to the endpoint in your Endpoints list
  2. Click the actions menu (⋮) and select Rotate Secret
  3. Click Rotate Secret to confirm
  4. Copy the new signing secret immediately
  5. Update your application's signature verification with the new secret

Grace Period

When you rotate a secret, both the old and new secrets are valid for a short grace period. Update your application to accept the new secret during this period, then remove the old secret configuration.

Managing Subscriptions

From the endpoint details or actions menu:

  • Add Events: Subscribe to new event types
  • Manage Subscriptions: View and manage current subscriptions
  • Remove Subscription: Unsubscribe from an event type by clicking the delete icon

Deleting Endpoints

To remove an endpoint:

  1. Navigate to the Endpoints page
  2. Click the actions menu (⋮) for the endpoint
  3. Select Delete Endpoint

Permanent Deletion

Deleting an endpoint removes all subscriptions and delivery history. This action cannot be undone.

Best Practices

Security

  • Store signing secrets securely (use environment variables or secrets management)
  • Always verify webhook signatures before processing
  • Never commit secrets to version control
  • Rotate secrets quarterly or after team changes

Reliability

  • Implement idempotency using the Event-ID header to handle duplicate deliveries
  • Respond with 2xx immediately (within 8 seconds), then process asynchronously
  • Log all webhook deliveries for debugging and auditing
  • Use a queue or background job processor for time-consuming operations

Handling Failures

  • Monitor for circuit breaker events (endpoint disabled notifications)
  • Set up alerts for repeated delivery failures
  • Check delivery logs regularly for error patterns
  • Test endpoints after deploying changes

Idempotency

Webhooks may be delivered more than once due to retries. Use the Event-ID header to ensure you only process each event once:

javascript
const processedEvents = new Set(); // Use Redis/database in production

app.post('/webhooks', (req, res) => {
  const eventId = req.headers['event-id'];
  
  // Check if already processed
  if (processedEvents.has(eventId)) {
    console.log(`Event ${eventId} already processed, skipping`);
    return res.status(200).send('OK');
  }
  
  // Mark as processed
  processedEvents.add(eventId);
  
  // Process the event...
  res.status(200).send('OK');
});

Support

If you encounter issues with webhook delivery:

  1. Check the Logs page for error details
  2. Verify your endpoint is accessible and responding within 8 seconds
  3. Confirm you're validating signatures correctly (including Event-ID and Timestamp in the signature)
  4. Check if your endpoint was disabled by the circuit breaker
  5. Contact support at ray@k2cyber.ai with the Event-ID

Maintained by the K2 Cyber Insurance engineering team.