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 .