Webhooks allow you to receive real-time notifications about activities in Confidence by sending HTTP POST requests to your specified endpoint. You can configure webhooks as notification channels for activity feeds, enabling integration with external systems, monitoring tools, or custom notification workflows.
Create an Activity Feed with Webhook
Navigate to Settings > Activity Feeds
Click Create to create a new activity feed
Enter a name for your feed
Select which resource types to follow
Choose from Flags, A/B Tests, or Rollouts
Toggle the Webhook switch
Enter the Webhook URI
For example: https://example.com/webhooks/confidence
Enter a Webhook Secret for signature verification
See the Security section for details on signature verification Select the minimum Priority level for notifications
Edit a Feed
Navigate to Settings > Activity Feeds
Click the Edit button on the feed you want to modify
Toggle the Webhook switch to enable webhook notifications
Configure the webhook URI and secret
When editing an existing webhook, you must re-enter the secret. The secret is write-only and never returned from the server for security reasons.
Webhook Payload
Confidence sends activity notifications as JSON in the ListActivitiesResponse format. Each webhook request contains an array of activities.
Example Payload
{
"activities": [
{
"name": "activityTypes/experiment-started/activities/abc123",
"primaryResource": "workflows/abtest/instances/my-experiment",
"relatedResources": ["surfaces/global"],
"priority": "MEDIUM",
"actor": "identities/user@example.com",
"title": "Experiment started",
"body": "The A/B test 'Homepage Button Test' has been started.",
"activityTime": "2024-02-26T10:30:00Z",
"createTime": "2024-02-26T10:30:00Z",
"updateTime": "2024-02-26T10:30:00Z",
"creator": "identities/user@example.com",
"updater": "identities/user@example.com"
}
]
}
Activity Fields
name: Unique identifier for the activity
primaryResource: The main resource this activity relates to
relatedResources: Other resources involved in the activity
priority: Activity priority level (LOW, MEDIUM, HIGH)
actor: The identity that performed the activity
title: Human-readable activity title
body: Detailed description in Markdown format
activityTime: When the activity occurred
createTime: When Confidence created the activity
updateTime: When the activity was last updated
creator: Identity that created the activity record
updater: Identity that last updated the activity record
The title and body fields are designed for human-readable display and may change without notice. Do not parse or depend on these fields for automation logic. Instead, use the primaryResource field to fetch the authoritative resource data via the corresponding API endpoint.
Security
Webhooks use HMAC-SHA256 signatures to ensure authenticity and integrity of messages. Every webhook request includes three custom headers for verification.
| Header | Description |
|---|
Confidence-Webhook-Signature | HMAC-SHA256 signature of the payload |
Confidence-Webhook-Id-Signature | Webhook configuration ID |
Confidence-Webhook-Timestamp | Unix timestamp (seconds) when Confidence sent the request |
Signature Generation
Confidence computes the signature as:
HMAC-SHA256(secret, "{timestamp}.{payload}")
Where:
secret: The webhook secret you provided during configuration
timestamp: The value from the Confidence-Webhook-Timestamp header
payload: The raw JSON request body
Verify Signatures
To verify a webhook request is authentic:
Extract headers from the incoming request
Confidence-Webhook-Signature
Confidence-Webhook-Timestamp
Validate timestamp to prevent replay attacks
- Check that the timestamp is recent (within ±5 minutes of current time)
- Reject requests with timestamps too far in the past or future
Compute expected signature
- Concatenate timestamp and payload:
"{timestamp}.{payload}"
- Compute HMAC-SHA256 using your webhook secret
- Convert result to hexadecimal string
Compare signatures
- Use constant-time comparison to prevent timing attacks
- If signatures match, the request is authentic
Example Verification
const crypto = require('crypto');
function verifyWebhook(request, secret) {
const signature = request.headers['confidence-webhook-signature'];
const timestamp = request.headers['confidence-webhook-timestamp'];
const payload = request.body; // Raw JSON string
// Validate timestamp (within 5 minutes)
const now = Math.floor(Date.now() / 1000);
const requestTime = parseInt(timestamp);
if (Math.abs(now - requestTime) > 300) {
throw new Error('Timestamp too old or too far in the future');
}
// Compute expected signature
const signedPayload = `${timestamp}.${payload}`;
const expectedSignature = crypto
.createHmac('sha256', secret)
.update(signedPayload)
.digest('hex');
// Compare signatures (constant-time)
if (!crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expectedSignature)
)) {
throw new Error('Invalid signature');
}
return true;
}
Best Practices
Secret Management
Endpoint Implementation
Error Handling
Security Considerations
- Generate strong secrets: Use cryptographically random strings (at least 32 characters)
- Rotate secrets regularly: Update webhook secrets periodically
- Store securely: Never commit secrets to version control or expose in logs
- Use environment variables: Store secrets in environment variables or secret management systems
- Return quickly: Respond with HTTP 200 within a few seconds to avoid timeouts
- Process asynchronously: Queue webhook payloads for background processing
- Implement retries: Confidence does not automatically retry failed webhooks
- Log webhook ID: Store the
Confidence-Webhook-Id-Signature for debugging
- Validate signatures first: Always verify signatures before processing payload
- Handle malformed JSON: Gracefully handle invalid JSON payloads
- Monitor failures: Track webhook failures and set up alerts
- Return appropriate status codes:
200 OK: Successfully received and validated
400 Bad Request: Invalid signature or malformed payload
500 Internal Server Error: Processing error (avoid if possible)
- Validate timestamp: Prevent replay attacks by checking timestamp freshness
- Use constant-time comparison: Prevent timing attacks when comparing signatures
- Rate limiting: Implement rate limiting on your webhook endpoint
- IP allowlisting: Consider restricting webhook requests to known Confidence IP ranges
Troubleshoot Common Issues
Webhook not receiving notifications
Signature verification failing
Activities missing from webhook
- Verify the webhook is enabled (toggle switched on)
- Check that the priority filter allows the activity level
- Ensure your endpoint is publicly accessible via HTTPS
- Verify your endpoint returns HTTP 200 status
- Confirm you’re using the correct secret
- Verify you’re computing the signature over
"{timestamp}.{payload}"
- Check that you’re using the raw request body (not parsed JSON)
- Ensure timestamp format is Unix seconds (not milliseconds)
- Check the activity priority matches your webhook configuration
- Verify the resource type is followed by the activity feed
- Ensure the activity feed is subscribed to the relevant resources