Appearance
Webhook Security
Verify that webhook requests are genuinely from PackEdge using signature verification.
Signing Secret
Each webhook has a unique signing secret (starts with whsec_). This secret is used to sign each webhook payload, allowing you to verify authenticity.
Find your signing secret in Settings > Integrations > [Your Webhook].
Signature Header
Every webhook request includes a X-PackEdge-Signature header containing the HMAC-SHA256 signature of the request body.
X-PackEdge-Signature: sha256=abc123...Verification
PHP Example
php
function verify_webhook_signature($payload, $signature, $secret) {
$expected = 'sha256=' . hash_hmac('sha256', $payload, $secret);
return hash_equals($expected, $signature);
}
// In your webhook handler
$payload = file_get_contents('php://input');
$signature = $_SERVER['HTTP_X_PACKEDGE_SIGNATURE'] ?? '';
$secret = 'whsec_your_signing_secret';
if (!verify_webhook_signature($payload, $signature, $secret)) {
http_response_code(401);
exit('Invalid signature');
}
// Process the webhook
$event = json_decode($payload, true);Node.js Example
javascript
const crypto = require('crypto');
function verifyWebhookSignature(payload, signature, secret) {
const expected = 'sha256=' + crypto
.createHmac('sha256', secret)
.update(payload)
.digest('hex');
return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(signature));
}
// Express.js handler
app.post('/webhook', express.raw({ type: 'application/json' }), (req, res) => {
const signature = req.headers['x-packedge-signature'];
const secret = 'whsec_your_signing_secret';
if (!verifyWebhookSignature(req.body, signature, secret)) {
return res.status(401).send('Invalid signature');
}
const event = JSON.parse(req.body);
// Process the webhook
res.status(200).send('OK');
});Best Practices
- Always verify signatures — Never process webhooks without signature verification
- Use timing-safe comparison — Prevent timing attacks with
hash_equals()(PHP) ortimingSafeEqual()(Node.js) - Use HTTPS — Webhook URLs must use HTTPS to prevent interception
- Return 200 quickly — Process webhooks asynchronously if they take time
- Handle duplicates — Use the event ID to detect and ignore duplicate deliveries
Regenerating Secrets
If your signing secret is compromised:
- Go to Settings > Integrations > [Your Webhook]
- Click Regenerate Secret
- Update your webhook handler with the new secret
- The old secret stops working immediately
Troubleshooting
Signature Mismatch
Common causes:
- Using the wrong signing secret
- Payload was modified (e.g., by middleware)
- Incorrect encoding
Ensure you're verifying the raw request body, not a parsed/modified version.
Request Timeout
PackEdge expects a response within 10 seconds. If your processing takes longer:
- Queue the webhook for background processing
- Return 200 immediately
- Process the event asynchronously
