pro
Advanced Usage
Headers, worker mode, logging, and programmatic execution.
- Custom Headers
- Common Headers
- Bearer Token Authentication
- Basic Authentication
- API Key Header
- Multiple Headers
- HMAC Signature Verification
- Worker Mode
- Benefits
- Worker Configuration
- Logging & Debugging
- Viewing Logs
- Log Entry Structure
- Common Issues
- Debug Mode
- Programmatic Execution
- Get and Execute Webhook
- Response Structure
- Error Response
- Execute in Background
- Execute All Matching Webhooks
- Conditional Webhooks
- Timeout Configuration
- Rate Limiting
Custom Headers
Add custom headers for authentication and metadata.
Common Headers
| Header | Use Case |
|---|---|
Authorization |
API authentication |
X-Webhook-Secret |
Verify webhook origin |
Content-Type |
Already set to application/json |
X-Custom-Header |
Any custom metadata |
Bearer Token Authentication
Key: Authorization
Value: Bearer ${API_TOKEN}
Basic Authentication
Key: Authorization
Value: Basic ${BASE64_CREDENTIALS}
API Key Header
Key: X-API-Key
Value: ${API_KEY}
Multiple Headers
Add multiple headers for complex authentication:
Authorization: Bearer ${API_TOKEN}
X-Webhook-Secret: ${WEBHOOK_SECRET}
X-Source: cockpit-cms
HMAC Signature Verification
For services requiring signature verification, implement a receiver that validates the payload:
// Example: Node.js webhook receiver
const crypto = require('crypto');
function verifySignature(payload, signature, secret) {
const computed = crypto
.createHmac('sha256', secret)
.update(payload)
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(computed)
);
}
app.post('/webhook', (req, res) => {
const signature = req.headers['x-webhook-signature'];
if (!verifySignature(req.rawBody, signature, process.env.WEBHOOK_SECRET)) {
return res.status(401).send('Invalid signature');
}
// Process webhook...
res.send('OK');
});
Worker Mode
For high-traffic sites, offload webhook execution to background workers:
// config/config.php
return [
'webhooks' => [
'worker' => true
]
];
This requires the worker system to be configured and running.
Benefits
- Non-blocking - Content operations return immediately
- Retry capability - Failed webhooks can be retried
- Rate limiting - Control outbound request rate
- Better performance - Reduced response times for content operations
Worker Configuration
return [
'worker' => [
'enabled' => true,
'driver' => 'redis', // or 'database', 'sync'
'connection' => [
'host' => '127.0.0.1',
'port' => 6379
]
],
'webhooks' => [
'worker' => true,
'retries' => 3,
'retry_delay' => 60 // seconds
]
];
Logging & Debugging
Failed webhooks are logged to the system log.
Viewing Logs
- Navigate to Settings > System > Logs
- Filter by channel:
webhooks - Review error messages and status codes
Log Entry Structure
{
"timestamp": "2024-01-15T10:30:00Z",
"level": "error",
"channel": "webhooks",
"message": "Webhook failed",
"context": {
"webhook": "deploy-trigger",
"url": "https://api.example.com/webhook",
"status_code": 401,
"error": "Unauthorized"
}
}
Common Issues
| Error | Cause | Solution |
|---|---|---|
| Connection timeout | Endpoint slow/unreachable | Check URL, increase timeout |
| 401 Unauthorized | Invalid authentication | Verify API keys/tokens |
| 403 Forbidden | Missing permissions | Check endpoint access |
| 404 Not Found | Wrong URL | Verify webhook URL |
| 500 Server Error | Endpoint error | Check receiving service |
| SSL certificate error | Invalid/expired cert | Fix certificate on endpoint |
Debug Mode
Enable verbose logging temporarily:
// config/config.php
return [
'webhooks' => [
'debug' => true
]
];
Programmatic Execution
Execute webhooks from custom code.
Get and Execute Webhook
// Get webhook by name
$webhook = $app->helper('webhooks')->hook('my-webhook-name');
// Execute with custom payload
$result = $app->module('webhooks')->execute($webhook, [
'custom' => 'data',
'timestamp' => time()
]);
// Check result
if ($result['success']) {
echo "Webhook sent successfully";
echo "Status: " . $result['status_code'];
} else {
echo "Error: " . $result['error']['message'];
}
Response Structure
[
'success' => true,
'status_code' => 200,
'headers' => ['Content-Type' => 'application/json'],
'content' => '{"received": true}',
'duration_ms' => 150
]
Error Response
[
'success' => false,
'status_code' => 0,
'error' => [
'message' => 'Connection timed out',
'code' => 28
],
'duration_ms' => 30000
]
Execute in Background
// Queue webhook for background execution
$app->module('webhooks')->queue('my-webhook-name', [
'custom' => 'payload'
]);
Execute All Matching Webhooks
// Trigger all webhooks listening to an event
$app->trigger('content.item.save', ['posts', $item, false]);
Conditional Webhooks
Implement conditional webhook logic in custom code:
$this->on('content.item.save', function($model, $item, $isNew) use ($app) {
// Only trigger for published items
if ($item['_state'] !== 1) return;
// Only trigger for specific models
if (!in_array($model, ['posts', 'news'])) return;
// Custom webhook logic
$webhook = $app->helper('webhooks')->hook('selective-deploy');
$app->module('webhooks')->execute($webhook, [
'model' => $model,
'item_id' => $item['_id'],
'action' => $isNew ? 'created' : 'updated'
]);
});
Timeout Configuration
Configure webhook timeout settings:
// config/config.php
return [
'webhooks' => [
'timeout' => 30, // Connection timeout (seconds)
'read_timeout' => 60, // Read timeout (seconds)
]
];
Rate Limiting
Implement rate limiting for high-frequency events:
// Custom rate limiting in addon
$this->on('content.item.save', function($model, $item) use ($app) {
$cacheKey = "webhook_rate_{$model}";
$lastCall = $app->dataStorage->getKey('tmp', $cacheKey);
// Only allow one webhook per 5 seconds per model
if ($lastCall && (time() - $lastCall) < 5) {
return;
}
$app->dataStorage->setKey('tmp', $cacheKey, time());
// Execute webhook...
});