Webhooks
Learn how to setup webhooks to sync articles to your own site.
Webhook Request Payload
When your webhook integration is triggered, Site Mechanic will send a POST
request to the URL you specify. The request will contain a JSON payload with the following structure:
{ //Webhook post request body "id": "aQui898C9go0Cxg", // The unique ID of the article "title": "My Article Title", "contentHtml": "<p>The html content of the article</p>", "featuredImage": "url", // temporary URl for the featured Image which will expire after 1 hour "excerpt": "A plaintext excerpt of the article", "description": "SEO meta description of the article", "slug": "my-article-title", "isDraft": boolean, // true if the article is a draft "keyword": "main keyword", }
- Featured Image: The
featuredImage
URL is only temporary and will expire after 1 hour. You must download the image and store it on your server or CDN of your choice. - isDraft: The
isDraft
field indicates whether the article is a draft or published. You can use this field to determine how to handle the article on your site. - Content Images: The
contentHtml
field may include images with temporary URLs. You must download and store these images on your server or CDN, then replace the URLs in the HTML content before publishing.
Webhook Response
Your webhook endpoint should respond with a 200 OK
status code to acknowledge that the payload was received successfully. Site Mechanic does not retry failed webhook requests.
Optionally, you can return the published url
of the article on your site in the response body. This will allow Site Mechanic to track the article's performance over time.
{ "url": "https://your-site.com/my-article-title" }
Webhook Secret Validation
To ensure that the webhook request is coming from Site Mechanic, you can validate the request by checking the X-SM-Signature
header. The header contains a HMAC SHA256 hash of the request body signed with your Webhook Secret Key
.
Node.js Example:
const crypto = require('crypto'); const express = require('express'); const bodyParser = require('body-parser'); const app = express(); app.use(bodyParser.json()); app.post('/webhook', (req, res) => { const signature = req.headers['x-sm-signature']; const secret = process.env.WEBHOOK_SECRET_KEY;//store your webhook secret in an environment variable if (!signature || !secret) { return res.status(400).send('Missing signature or secret'); } const hash = crypto .createHmac('sha256', secret) .update(JSON.stringify(req.body)) .digest('hex'); if (signature !== hash) { return res.status(403).send('Invalid signature'); } // Process the webhook payload console.log('Webhook payload:', req.body); //const articleUrl = createMyArticle(req.body); //create your article and return the URL res.status(200).json({ url: articleUrl });//optionally include the URL of the article in the response }); const PORT = process.env.PORT || 3000; app.listen(PORT, () => { console.log(`Server is running on port ${PORT}`); });
Python Example:
from flask import Flask, request, abort import hmac import hashlib import os import json app = Flask(__name__) @app.route('/webhook', methods=['POST']) def webhook(): signature = request.headers.get('X-SM-Signature') secret = os.environ.get('WEBHOOK_SECRET_KEY') if not signature or not secret: abort(400, description="Missing signature or secret") # Create the HMAC signature payload = request.data computed_hash = hmac.new(secret.encode('utf-8'), payload, hashlib.sha256).hexdigest() if not hmac.compare_digest(signature, computed_hash): abort(403, description="Invalid signature") # Process the webhook payload payload_dict = json.loads(payload) print("Webhook payload:", payload_dict) #articleUrl = create_my_article(payload_dict) #create your article and return the URL return {"url": articleUrl}, 200 #optionally include the URL of the article in the response if __name__ == '__main__': port = int(os.environ.get('PORT', 5000)) app.run(host='0.0.0.0', port=port)
Troubleshooting and Support
If you encounter any issues setting up your integration, please contact our support team for assistance. We're here to help ensure you have the best possible experience with SiteMechanic.ai .