Webhook Integration
Connect any custom CMS to BlogShoot using standard webhooks. Receive AI-generated articles automatically through secure HTTP callbacks.
Overview
Section titled “Overview”Webhook integration allows you to receive BlogShoot articles in any custom CMS or platform that can handle HTTP POST requests. Instead of manually copying content, BlogShoot automatically pushes articles to your webhook endpoint when they’re ready.
How It Works
Section titled “How It Works”BlogShoot generates article → You select Webhook push →BlogShoot sends HTTP POST → Your CMS receives and processesKey Features
Section titled “Key Features”- Standard HTTP webhooks - Works with any platform that accepts POST requests
- Secure delivery - HMAC-SHA256 signature verification prevents forgery
- Automatic retries - Failed deliveries retry up to 3 times automatically
- Custom headers - Add authentication tokens or API keys
- Delivery history - Track all webhook deliveries and troubleshoot issues
Prerequisites
Section titled “Prerequisites”Before setting up webhook integration, you’ll need:
- A publicly accessible HTTPS endpoint (webhook URL)
- Ability to receive and process HTTP POST requests
- Basic understanding of JSON and API authentication
- Development resources to implement the webhook receiver
Setting Up Your Webhook
Section titled “Setting Up Your Webhook”Step 1: Create Webhook Endpoint
Section titled “Step 1: Create Webhook Endpoint”First, create an endpoint in your CMS that can receive HTTP POST requests. This endpoint should:
- Accept POST requests with JSON payload
- Return 2xx status code (200-299) on success
- Process requests quickly (respond within 10 seconds)
- Verify webhook signatures (see security section)
Step 2: Configure in BlogShoot
Section titled “Step 2: Configure in BlogShoot”- Navigate to Integrations → Webhook
- Click “Add Webhook Connection”
- Fill in connection details:
Connection Name: My Custom CMSWebhook URL: https://your-cms.com/webhooks/blogshootWebhook Secret: [generate a strong random string]-
(Optional) Add custom HTTP headers:
- Click “Add Custom Header”
- Example:
Authorization: Bearer your-api-token
-
Click “Test Connection”
- ✅ Success: Connection verified
- ❌ Failed: Check troubleshooting section
-
Click “Save Connection”
Step 3: Event Configuration
Section titled “Step 3: Event Configuration”Configure which events trigger webhooks:
- article.created - New article published
- article.updated - Existing article modified
- article.deleted - Article removed
You can also set:
- Timeout - Maximum wait time for response (default: 10 seconds)
- Custom Headers - Additional authentication or metadata
Understanding Webhook Payload
Section titled “Understanding Webhook Payload”Standard Payload Format
Section titled “Standard Payload Format”BlogShoot sends a structured JSON payload containing all article data:
{ "event_id": "unique-uuid-v4", "event_type": "article.created", "timestamp": "2025-12-04T10:30:00Z", "workspace": { "id": "workspace_id", "name": "My Company" }, "article": { "id": "blogshoot_article_id", "title": "Your Article Title", "slug": "article-url-slug", "content": { "html": "<p>Full HTML content...</p>", "markdown": "# Article Title\n\nContent...", "plain_text": "Plain text version" }, "excerpt": "Brief article summary", "featured_image": { "url": "https://cdn.blogshoot.com/image.jpg", "alt": "Image description", "width": 1200, "height": 630 }, "images": [ { "url": "https://...", "alt": "Image description", "position": 1 } ], "seo": { "title": "SEO-optimized title", "description": "Meta description", "keywords": ["keyword1", "keyword2"] }, "categories": ["Category1", "Category2"], "tags": ["tag1", "tag2"], "author": { "name": "Author Name", }, "status": "publish", "published_at": "2025-12-04T10:30:00Z", "created_at": "2025-12-04T10:00:00Z", "updated_at": "2025-12-04T10:30:00Z" }, "metadata": { "source": "blogshoot", "version": "1.0" }}HTTP Headers
Section titled “HTTP Headers”Each webhook request includes these headers:
Content-Type: application/jsonUser-Agent: BlogShoot-Webhook/1.0X-BlogShoot-Signature: [hmac-sha256-hex-signature]X-BlogShoot-Event: article.createdX-BlogShoot-Delivery-ID: [unique-uuid]Implementing Webhook Receiver
Section titled “Implementing Webhook Receiver”Security: Verifying Signatures
Section titled “Security: Verifying Signatures”Always verify webhook signatures to ensure requests come from BlogShoot:
PHP Example
Section titled “PHP Example”<?php// Read raw request body$payload = file_get_contents('php://input');$signature = $_SERVER['HTTP_X_BLOGSHOOT_SIGNATURE'] ?? '';
// Your webhook secret from BlogShoot dashboard$webhook_secret = 'your-webhook-secret-from-blogshoot';
// Calculate expected signature$expected_signature = hash_hmac('sha256', $payload, $webhook_secret);
// Verify signatureif (!hash_equals($expected_signature, $signature)) { http_response_code(401); die(json_encode(['error' => 'Invalid signature']));}
// Signature verified - safe to process$data = json_decode($payload, true);processWebhook($data);?>Node.js Example
Section titled “Node.js Example”const crypto = require('crypto');
app.post('/webhook/blogshoot', (req, res) => { // Get signature from header const signature = req.headers['x-blogshoot-signature']; const webhookSecret = process.env.BLOGSHOOT_WEBHOOK_SECRET;
// Calculate expected signature from raw body const expectedSignature = crypto .createHmac('sha256', webhookSecret) .update(req.rawBody) // Must use raw body! .digest('hex');
// Verify signature if (signature !== expectedSignature) { return res.status(401).json({ error: 'Invalid signature' }); }
// Process webhook processWebhook(req.body); res.status(200).json({ success: true });});Processing Events
Section titled “Processing Events”Handle different event types:
<?php$data = json_decode($payload, true);
switch ($data['event_type']) { case 'article.created': createPost($data['article']); break;
case 'article.updated': updatePost($data['article']); break;
case 'article.deleted': deletePost($data['article']['id']); break;
case 'test': // Test connection - just return success break;}
// Return 200 OKhttp_response_code(200);echo json_encode([ 'success' => true, 'event_id' => $data['event_id']]);?>Handling Images
Section titled “Handling Images”Articles include a featured image and additional images. You can:
- Store URLs directly - Reference BlogShoot’s CDN
- Download and host - Upload images to your own storage
Example: Downloading Images (PHP)
Section titled “Example: Downloading Images (PHP)”function downloadImage($url, $alt = '') { $image_data = file_get_contents($url); $filename = basename(parse_url($url, PHP_URL_PATH)); $filepath = '/uploads/' . $filename;
file_put_contents($filepath, $image_data);
return [ 'path' => $filepath, 'alt' => $alt ];}
// Process featured imageif (!empty($article['featured_image']['url'])) { $image = downloadImage( $article['featured_image']['url'], $article['featured_image']['alt'] ); setFeaturedImage($post_id, $image);}Delivery & Retry Mechanism
Section titled “Delivery & Retry Mechanism”Automatic Retry Strategy
Section titled “Automatic Retry Strategy”If webhook delivery fails, BlogShoot automatically retries:
| Attempt | Delay | Total Time |
|---|---|---|
| 1st failure | 5 seconds | 5s |
| 2nd failure | 30 seconds | 35s |
| 3rd failure | 5 minutes | 5m 35s |
| After 3 failures | Manual retry needed | - |
Success Criteria
Section titled “Success Criteria”Delivery is considered successful when:
- HTTP status code is 200-299
- Response received within timeout (default: 10 seconds)
Manual Retry
Section titled “Manual Retry”For permanently failed deliveries:
- Go to Integrations → Webhook
- Click “View Delivery History”
- Find the failed delivery
- Click “Retry”
Monitoring Deliveries
Section titled “Monitoring Deliveries”Viewing Delivery History
Section titled “Viewing Delivery History”Track all webhook deliveries:
- Navigate to Integrations → Webhook
- Select your connection
- Click “Delivery History”
You’ll see:
- Event type and timestamp
- Delivery status (Success/Failed)
- HTTP status code
- Response time
- Error messages (if failed)
- Retry count
Delivery Status Types
Section titled “Delivery Status Types”- Success ✅ - Delivered successfully
- Pending ⏳ - Scheduled for retry
- Failed ❌ - Permanent failure (needs manual retry)
Best Practices
Section titled “Best Practices”Performance
Section titled “Performance”-
Respond quickly - Process webhook asynchronously if possible:
// Respond immediatelyhttp_response_code(200);echo json_encode(['success' => true]);fastcgi_finish_request(); // PHP-FPM only// Then process in backgroundprocessArticleInBackground($data); -
Set appropriate timeout - Match your CMS processing speed:
- Simple insert: 5-10 seconds
- Complex processing: 15-30 seconds
- Image downloads: 20-60 seconds
Security
Section titled “Security”- Always verify signatures - Never trust unsigned webhooks
- Use HTTPS - Encrypt data in transit
- Store secrets securely - Use environment variables
- Rotate secrets periodically - Every 6-12 months
- Add custom auth headers - Additional authentication layer
Reliability
Section titled “Reliability”-
Implement idempotency - Use
event_idto prevent duplicates:$event_id = $data['event_id'];if (eventAlreadyProcessed($event_id)) {http_response_code(200);die(json_encode(['success' => true, 'duplicate' => true]));}markEventProcessed($event_id); -
Log all webhooks - Keep audit trail for debugging
-
Handle errors gracefully - Return 5xx for temporary failures
-
Monitor delivery history - Set up alerts for failures
Testing Your Integration
Section titled “Testing Your Integration”Using Test Connection
Section titled “Using Test Connection”- Click “Test Connection” in BlogShoot dashboard
- BlogShoot sends a test event:
{ "event_type": "test", ... } - Your endpoint should:
- Verify signature
- Return 200 OK
- Log the test event
Using Webhook Testing Tools
Section titled “Using Webhook Testing Tools”Before connecting to BlogShoot, test your endpoint with:
- Webhook.site - Inspect incoming requests
- RequestBin - Capture and debug webhooks
- Postman - Send test POST requests manually
Example Test Request
Section titled “Example Test Request”curl -X POST https://your-cms.com/webhooks/blogshoot \ -H "Content-Type: application/json" \ -H "X-BlogShoot-Signature: [calculated-signature]" \ -H "X-BlogShoot-Event: test" \ -d '{ "event_type": "test", "event_id": "test-123", "timestamp": "2025-12-04T10:30:00Z" }'Troubleshooting
Section titled “Troubleshooting”Connection Test Failed
Section titled “Connection Test Failed”Possible causes:
-
Endpoint not accessible
- Verify URL is publicly accessible
- Check firewall rules
- Ensure HTTPS is configured
-
Signature verification failed
- Check webhook secret matches
- Verify you’re using raw request body
- Check for encoding issues
-
Timeout
- Increase timeout setting
- Optimize endpoint response time
- Implement async processing
-
Invalid response
- Ensure 200-299 status code
- Return valid JSON
- Check for error handling
Deliveries Failing
Section titled “Deliveries Failing”Troubleshooting steps:
- Check delivery history for error messages
- Verify endpoint logs - Is request received?
- Test signature - Calculate locally and compare
- Check response time - Too slow? Optimize or increase timeout
- Review error logs - Server errors, database issues?
Images Not Downloading
Section titled “Images Not Downloading”- Check image URLs are accessible
- Verify sufficient storage space
- Check file permissions on upload directory
- Ensure firewall allows outbound HTTPS
Duplicate Articles
Section titled “Duplicate Articles”Implement idempotency using event_id:
// Check if already processed$event_id = $data['event_id'];if (eventExists($event_id)) { return ['success' => true, 'duplicate' => true];}
// Process and mark as handledprocessArticle($data['article']);saveEventId($event_id);Advanced Configuration
Section titled “Advanced Configuration”Custom Headers for Authentication
Section titled “Custom Headers for Authentication”Add custom headers for additional security:
Authorization: Bearer your-api-tokenX-API-Key: your-api-keyX-Custom-Header: custom-valueAccess in your endpoint:
$api_key = $_SERVER['HTTP_X_API_KEY'] ?? '';if ($api_key !== 'your-api-key') { http_response_code(401); die('Unauthorized');}Webhook Payload Filtering
Section titled “Webhook Payload Filtering”Currently, all article data is sent. If you need specific fields only, process the payload and extract what you need:
function processArticle(article) { // Extract only what you need return { title: article.title, content: article.content.html, excerpt: article.excerpt, featured_image: article.featured_image?.url, categories: article.categories, tags: article.tags };}Multiple Webhooks
Section titled “Multiple Webhooks”You can create multiple webhook connections:
- Development - Test endpoint for staging
- Production - Live CMS endpoint
- Backup - Secondary CMS or archive system
Each connection has independent:
- URL and secret
- Event configuration
- Custom headers
- Delivery history
Security Considerations
Section titled “Security Considerations”Webhook Secret Management
Section titled “Webhook Secret Management”- Never commit secrets to version control
- Use environment variables or secret management systems
- Rotate secrets regularly every 6-12 months
- Use different secrets for dev/staging/production
IP Whitelisting
Section titled “IP Whitelisting”For additional security, whitelist BlogShoot’s IP addresses:
Contact [email protected] for current IP rangesRate Limiting
Section titled “Rate Limiting”BlogShoot respects reasonable rate limits:
- Maximum 5 webhooks per second per connection
- Exponential backoff on errors
- Automatic retry with delays
If you need higher limits, contact support.
Next Steps
Section titled “Next Steps”Need Help?
Section titled “Need Help?”- Check Frequently Asked Questions
- View Troubleshooting Guide
- Contact support: [email protected]