| title | description |
|---|---|
Webhooks |
Automate HTTP callbacks from Corgea to any external system |
Webhooks are automated HTTP callbacks that allow Corgea to send real-time notifications to your external systems when specific events occur. Instead of continuously polling our API to check for updates, webhooks push event data directly to your specified endpoint the moment something happens.
- Real-time notifications - Receive instant updates when security issues are found, status changes occur, or scans complete
- Automation - Trigger workflows in external tools like Slack, Zapier, or custom applications
- Efficiency - No need to poll APIs - we push data to you when events happen
- Flexibility - Subscribe only to the events you care about and filter by project or status
- Reliability - Built-in retry logic and delivery tracking ensure your notifications get through
Corgea supports webhooks for the following events:
Issue Events:
issue.status_changed- Triggered when an issue's status is updated (e.g., open → fixed)issue.assigned- Triggered when an issue is assigned to a team member
Scan Events:
scan.started- Triggered when a security scan beginsscan.completed- Triggered when a scan finishes successfullyscan.failed- Triggered when a scan encounters an error
User Auth Events:
user.login- Triggered when a user successfully logs inuser.login_failed- Triggered when a user login attempt fails
Something happens in Corgea (e.g., a scan completes, an issue status changes) The system identifies all webhooks subscribed to that event type Project and status filters determine if the webhook should fire By default, a standardized JSON payload is constructed with event details (or your custom body template is used, if configured) The payload is sent to your webhook URL with security headers If the request fails, automatic retries occur with exponential backoff All attempts are tracked in the delivery history for troubleshooting
By default, webhook payloads follow a standardized structure:
{
"event_id": "550e8400-e29b-41d4-a716-446655440000",
"event_type": "scan.completed",
"timestamp": "2025-01-15T14:30:00.000Z",
"data": {
"company": "company-uuid",
"scan_id": "scan-uuid",
"project": {
"id": "project-uuid",
"name": "My Application"
},
"issues_found": 12,
...
}
}If you configure Custom Body during webhook setup, Corgea sends your rendered JSON object instead of the default payload structure.
- When you provide a secret key, Corgea includes an `X-Corgea-Signature` header - This header contains an HMAC-SHA256 hash of the payload - Verify the signature to ensure the webhook came from Corgea - Include headers required by your endpoint (e.g., authentication tokens) - Configure custom headers during webhook setup - All webhook URLs must use HTTPS for secure transmission - Non-HTTPS URLs will be rejected to protect sensitive dataIf webhook delivery fails, Corgea automatically retries with the following strategy:
- Initial attempt + 2 retries = 3 total attempts
- Exponential backoff: 2 seconds, 4 seconds between retries
- Timeout: 10 seconds per request
- Auto-pause: After 10 consecutive failures, the webhook is automatically paused
Content-Type: application/json
X-Corgea-Event: issue.status_changed
X-Corgea-Delivery: <delivery-uuid>
X-Corgea-Timestamp: <unix-timestamp>
X-Corgea-Signature: <hmac-signature> (if secret configured)
User-Agent: Corgea-Webhooks/1.0
Admin or integration management permissions in your Corgea account A webhook endpoint URL that accepts POST requests HTTPS endpoint (required for security)
- Go to your Corgea dashboard - Click on "Integrations" in the navigation menu - Select "Webhooks" or "Create New Webhook"- **Name**: Give your webhook a descriptive name (e.g., "Slack Notifications", "Production Scan Alerts")
- **Webhook URL**: Enter your HTTPS endpoint URL
- **Type**: Select the integration type:
- `Slack` - For Slack webhook integrations
- `Zapier` - For Zapier zaps
- `Other` - For custom integrations
**Status Change Filter** (for `issue.status_changed` events)
- Leave empty to receive all status changes
- Select specific statuses (e.g., `fixed`, `false_positive`) to only receive those changes
- Reduces noise by filtering out irrelevant status updates
**Custom Headers**
Add headers required by your webhook destination. Each service has different requirements:
<AccordionGroup>
<Accordion title="Jira Automation" icon="jira">
**Required Header:**
```text
X-Automation-Webhook-Token: <your-jira-webhook-secret>
```
**How to get your token:**
1. In Jira, create an automation rule with an "Incoming webhook" trigger
2. Copy the secret token provided by Jira
3. Add it as the header value in Corgea
[Jira Webhook Documentation](https://support.atlassian.com/cloud-automation/docs/configure-the-incoming-webhook-trigger-in-atlassian-automation/)
</Accordion>
<Accordion title="Slack" icon="slack">
**No custom headers needed** - Slack webhook URLs include authentication in the URL itself.
Just paste your Slack webhook URL (format: `https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXXXXXXXX`)
<Note>Slack incoming webhooks do not validate custom headers. Security is provided by keeping the webhook URL secret.</Note>
[Slack Webhook Documentation](https://api.slack.com/messaging/webhooks)
</Accordion>
<Accordion title="Microsoft Teams" icon="microsoft">
**No custom headers needed** - Teams webhook URLs include authentication in the URL itself.
Just paste your Teams webhook URL (format: `https://xxx.webhook.office.com/webhookb2/xxx/IncomingWebhook/xxx`)
<Note>Teams incoming webhooks do not validate custom headers. Security is provided by keeping the webhook URL secret.</Note>
[Teams Webhook Documentation](https://learn.microsoft.com/en-us/microsoftteams/platform/webhooks-and-connectors/how-to/add-incoming-webhook)
</Accordion>
<Accordion title="Custom API with Bearer Token" icon="key">
**Header:**
```text
Authorization: Bearer <your-api-token>
```
Common for REST APIs that use JWT or OAuth tokens.
</Accordion>
<Accordion title="Splunk HEC" icon="bolt">
**Header:**
```text
Authorization: Splunk <your-hec-token>
```
Use this when sending webhook events to a Splunk HTTP Event Collector (HEC) endpoint.
</Accordion>
<Accordion title="Custom API with API Key" icon="lock">
**Headers (choose one):**
```text
X-API-Key: <your-api-key>
```
or
```text
Authorization: ApiKey <your-api-key>
```
Common for simple API key authentication.
</Accordion>
<Accordion title="PagerDuty" icon="bell">
**No custom headers needed** - PagerDuty Events API v2 uses the `routing_key` in the JSON payload for authentication.
Use the PagerDuty Events API endpoint: `https://events.pagerduty.com/v2/enqueue`
<Note>PagerDuty does not validate custom headers. Authentication is handled via the routing_key in the request body.</Note>
[PagerDuty Webhook Documentation](https://developer.pagerduty.com/docs/ZG9jOjExMDI5NTgw-events-api-v2-overview)
</Accordion>
<Accordion title="Zapier" icon="bolt">
**No custom headers needed** - Zapier webhook URLs include authentication in the URL itself.
Create a "Webhooks by Zapier" trigger and use the provided URL.
<Note>Zapier Catch Hook does not validate custom headers by default. Security is provided by keeping the webhook URL secret. You can add header validation logic within your Zap if needed.</Note>
[Zapier Webhook Documentation](https://zapier.com/help/create/code-webhooks/trigger-zaps-from-webhooks)
</Accordion>
</AccordionGroup>
<Tip>
If your service isn't listed here, check the service's webhook or incoming webhook documentation for required headers.
</Tip>
<Warning>
**Important:** While Corgea will send any custom headers you configure, not all webhook destinations validate them. Services like Slack, Teams, and Zapier rely on secret URLs rather than header validation. Only add custom headers if your destination service actually requires or validates them (like Jira, custom APIs, etc.).
</Warning>
**Custom Body**
- Optionally provide a JSON object template for the webhook request body
- Leave blank to use Corgea's default payload structure
- Supported placeholders:
- `{{payload}}` (full default payload object)
- `{{time}}` (Unix seconds)
- `{{timestamp}}` (ISO 8601 timestamp)
- `{{event_type}}`
- `{{event_id}}`
- If the rendered template is invalid JSON, delivery fails and the error appears in webhook history
If you configured a secret key, verify the signature in your endpoint to ensure authenticity.
```python verify-signature.py import hmac import hashlibdef verify_webhook_signature(payload, signature, secret):
"""Verify Corgea webhook signature"""
expected_signature = hmac.new(
secret.encode('utf-8'),
payload.encode('utf-8'),
hashlib.sha256
).hexdigest()
return hmac.compare_digest(expected_signature, signature)
# In your webhook handler:
if not verify_webhook_signature(request.body, request.headers['X-Corgea-Signature'], SECRET_KEY):
return HttpResponse(status=403) # Reject invalid signatures
```
function verifyWebhookSignature(payload, signature, secret) {
const expectedSignature = crypto
.createHmac('sha256', secret)
.update(payload)
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(expectedSignature),
Buffer.from(signature)
);
}
```
Scenario: Notify your security team in Slack when high-severity issues are found
Setup:
- Create a Slack incoming webhook URL in your Slack workspace
- In Corgea, create a webhook with:
- Type:
Slack - URL: Your Slack webhook URL
- Events:
scan.completed - Project Filter: Critical production projects
- Type:
Result: Your #security channel gets instant notifications when scans complete
Scenario: Automatically create tickets in Jira/Linear when critical issues are detected
Setup:
- Create a Zapier zap or custom endpoint that creates tickets
- In Corgea, create a webhook with:
- Events:
scan.completed,issue.status_changed - Status Filter: Only
openstatus (to avoid duplicate tickets) - Project Filter: Production projects
- Events:
Result: High/critical issues automatically become tickets in your project management tool
Scenario: Automatically document accepted risks in Jira or Linear when security issues are marked as "Accepted Risk"
Setup:
- Create an endpoint or Zapier integration that creates documentation tickets
- In Corgea, create a webhook with:
- Events:
issue.status_changed - Status Filter: Only
accepted_riskstatus - Project Filter: All projects or specific high-compliance projects
- Events:
- Configure the integration to:
- Create a ticket documenting the risk acceptance
- Include issue details (classification, file path, urgency)
- Tag with "risk-acceptance" label
- Assign to security lead for review
Result: Every accepted risk is automatically logged in your project management system with full context, creating an audit trail for compliance and risk management reviews
Scenario: Display real-time security metrics on your internal dashboard
Setup:
- Build an endpoint that receives webhook data and updates your dashboard
- In Corgea, create a webhook with:
- Events: All scan and issue events
- No filters (receive everything)
Result: Your dashboard shows live security scan results and issue trends
Scenario: Route different project notifications to different teams
Setup:
- Create separate webhooks for each team:
- Backend Team Webhook: Project filter = backend projects, Slack channel #backend-security
- Frontend Team Webhook: Project filter = frontend projects, Slack channel #frontend-security
- DevOps Team Webhook: Project filter = infrastructure projects, Slack channel #devops-security
Result: Each team only sees security issues relevant to their projects
Scenario: Automatically log all security findings to a compliance system
Setup:
- Create an endpoint that writes to your compliance database
- In Corgea, create a webhook with:
- Events:
scan.completed - All projects
- Store webhook delivery history for audit trail
- Events:
Result: Complete audit trail of all security scans for compliance purposes
Navigate to **Integrations** → **Webhooks**
<img src="/images/webhooks/webhook_history.png" alt="Webhook delivery history showing recent webhook attempts" />
View all webhook delivery attempts with:
- Event type and timestamp
- HTTP status code
- Request/response details
- Error messages (if any)
- Retry attempts
**Solutions:**
1. Check webhook status - ensure it's active (not paused)
2. Verify event subscriptions are selected
3. Review filters - temporarily remove filters to test
4. Check your endpoint logs for incoming requests
5. Test the webhook using the "Test Webhook" button
**Solutions:**
1. Check the delivery history for error details
2. Verify your endpoint URL is correct and accessible
3. Ensure your endpoint returns 2xx status codes
4. Check for firewall/security rules blocking Corgea's requests
5. Fix the underlying issue, then **manually re-activate** the webhook
6. Use "Test Webhook" to verify it's working before re-enabling
**Solutions:**
1. Verify you're using the exact secret key from Corgea
2. Ensure you're using HMAC-SHA256 algorithm
3. Use the raw request body (not parsed JSON) for verification
4. Check for UTF-8 encoding on both sides
5. Use `hmac.compare_digest()` (Python) or `crypto.timingSafeEqual()` (Node.js) for timing-safe comparison
<Tip>Log both the received signature and your computed signature to compare</Tip>
**Solutions:**
1. **Acknowledge Immediately**: Return 200 OK immediately, then process asynchronously
2. **Use a Queue**: Add webhook payloads to a queue for background processing
3. **Optimize Processing**: Speed up your webhook handler logic
4. **Increase Resources**: Scale up your endpoint infrastructure
**Best Practice Pattern:**
```python webhook-handler.py
@app.route('/webhook', methods=['POST'])
def handle_webhook():
payload = request.json
# Immediately acknowledge receipt
queue.add(process_webhook, payload)
# Return quickly
return '', 200
def process_webhook(payload):
# Do time-consuming work here
...
```
**Solutions:**
1. Check for duplicate webhook configurations
2. Use `event_id` field for idempotency - store processed event IDs and skip duplicates
3. Implement idempotency keys in your endpoint
**Idempotency Pattern:**
```python idempotency.py
processed_events = set() # Or use Redis/database
@app.route('/webhook', methods=['POST'])
def handle_webhook():
event_id = request.json['event_id']
if event_id in processed_events:
return '', 200 # Already processed
# Process event...
processed_events.add(event_id)
return '', 200
```
View performance metrics for your webhooks:
- Navigate to Integrations → Webhooks
- View each webhook's statistics:
- Total Deliveries: Total number of webhook calls
- Successful Deliveries: Calls that returned 2xx
- Failed Deliveries: Calls that failed or timed out
- Success Rate: Percentage of successful deliveries
- Consecutive Failures: Current failure streak
- Last Triggered: When the webhook last fired
If a webhook delivery failed, you can manually retry it:
- Go to Integrations → Webhooks → History
- Find the failed delivery
- Click Retry
- A new delivery attempt will be created and sent immediately
For compliance or debugging, export webhook delivery history:
- Navigate to Integrations → Webhooks → History
- Apply filters (date range, event type, status, webhook)
- Click Export to download CSV
- Use the export for:
- Compliance audits
- Performance analysis
- Debugging patterns
- Issue resolution tracking
1. Use [webhook.site](https://webhook.site) or [RequestBin](https://requestbin.com) to inspect payloads 2. Test with low-volume projects first 3. Monitor delivery success rate for the first few days 4. Set up alerting for webhook failures in your own system - Webhook URL is correct and accessible - Endpoint returns 2xx status code within 10 seconds - Firewall allows Corgea's requests - Event subscriptions are selected - Filters are configured correctly (or removed for testing) - Signature verification works (if using secret) - Webhook is active (not paused)
```json issue-status-changed.json { "event_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "event_type": "issue.status_changed", "timestamp": "2025-01-15T14:30:00.000Z", "data": { "company": "comp-uuid-1234", "issue_id": "issue-uuid-5678", "classification": "SQL Injection", "urgency": "HI", "status": "fixed", "previous_status": "open", "file_path": "src/controllers/user.py", "line_num": 45, "project": { "id": "proj-uuid-9012", "name": "Production API" }, "scan_id": "scan-uuid-3456", "url": "https://app.corgea.com/issue/issue-uuid-5678/" } } ``` ```json scan-completed.json { "event_id": "b2c3d4e5-f6a7-8901-bcde-f12345678901", "event_type": "scan.completed", "timestamp": "2025-01-15T15:45:00.000Z", "data": { "company": "comp-uuid-1234", "scan_id": "scan-uuid-7890", "run_id": "run-12345", "project": { "id": "proj-uuid-9012", "name": "Production API" }, "branch": "main", "engine": "corgea-blast", "scan_type": "full", "issues_found": 8, "processed_at": "2025-01-15T15:45:00.000Z", "created_at": "2025-01-15T15:40:00.000Z" } } ``` ```json issue-assigned.json { "event_id": "c3d4e5f6-a7b8-9012-cdef-123456789012", "event_type": "issue.assigned", "timestamp": "2025-01-15T16:00:00.000Z", "data": { "company": "comp-uuid-1234", "issue_id": "issue-uuid-5678", "classification": "Cross-Site Scripting (XSS)", "urgency": "ME", "status": "open", "assigned_to": { "id": "user-uuid-1111", "email": "jane.doe@company.com", "name": "Jane Doe" }, "previously_assigned_to": { "id": "user-uuid-2222", "email": "john.smith@company.com", "name": "John Smith" }, "project": { "id": "proj-uuid-9012", "name": "Production API" }, "url": "https://app.corgea.com/issue/issue-uuid-5678/" } } ``` ```json user-login.json { "event_id": "d4e5f6a7-b8c9-0123-def0-123456789012", "event_type": "user.login", "timestamp": "2025-01-15T16:10:00.000Z", "data": { "company": "comp-uuid-1234", "user_id": 123, "username": "jane.doe", "email": "jane.doe@company.com", "first_name": "Jane", "last_name": "Doe", "user_agent": "Mozilla/5.0", "path": "/login/" } } ``` ```json user-login-failed.json { "event_id": "e5f6a7b8-c9d0-1234-ef01-234567890123", "event_type": "user.login_failed", "timestamp": "2025-01-15T16:12:00.000Z", "data": { "company": "comp-uuid-1234", "username": "jane.doe", "user_agent": "Mozilla/5.0", "path": "/login/" } } ```
Yes! Your endpoint will receive an `X-Corgea-Event` header and `event_type` field to identify the event. There's no hard limit, but we recommend organizing by purpose (e.g., one per team or tool). Corgea will retry 3 times with exponential backoff. After 10 consecutive failures, the webhook auto-pauses. Yes! Use the "Test Webhook" button to send a sample payload without waiting for real events. Yes! Use custom headers to include authentication tokens, or use HMAC signature verification. Not directly, but you can filter by project. You can also filter on the received payload in your endpoint. Payloads are sent over HTTPS (TLS), providing encryption in transit. Use HMAC signatures for verification. Delivery logs are retained for compliance and debugging. Check with your plan for specific retention periods. Yes! Go to the webhook delivery history and click "Retry" on any failed delivery. Contact support for the current list of IP addresses to whitelist in your firewall.
Questions or issues? Contact Corgea Support



