{"id":1214,"date":"2023-07-17T06:45:06","date_gmt":"2023-07-17T06:45:06","guid":{"rendered":"https:\/\/feeder.co\/help\/?p=1214"},"modified":"2026-02-07T13:29:38","modified_gmt":"2026-02-07T13:29:38","slug":"build-your-own-integrations-using-webhooks","status":"publish","type":"post","link":"https:\/\/feeder.co\/help\/account\/automation\/build-your-own-integrations-using-webhooks\/","title":{"rendered":"Build your own integrations using Webhooks"},"content":{"rendered":"\n<p>The &#8220;Post to Webhook&#8221; rule enables you to automate the process of sending new RSS feed posts to your specified webhook endpoint, as soon as they become available. You can also fine-tune what posts are being sent by setting up keywords to filter on. When a new post matches your criteria, it will be sent to your webhook endpoint as a JSON formatted POST request.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>JSON payload format<\/strong><\/h2>\n\n\n\n<p>Each POST request sent to your webhook will contain two main elements: the <code>post<\/code> and the <code>feed<\/code>.<\/p>\n\n\n\n<p>It also contains metadata elements to identify the webhook message. The <code>version<\/code> field states which version of the Feeder webhook API is being sent. The version is constant to <code>2023-06-26<\/code> and will be updated if breaking changes are made.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>{\n  \"version\": \"2023-06-26\",\n  \"message_id\": \"a unique UUID for this message, will be constant during retries\",\n  \"feed\": { ... },\n  \"post\": { ... }\n}<\/code><\/pre>\n\n\n\n<p>The <code>post<\/code> element contains information about the individual post:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>{\n  \"id\": \"The unique identifier of the post\",\n  \"title\": \"The title of the post\",\n  \"url\": \"The URL where the post can be accessed\",\n  \"published\": \"The date and time when the post was published\",\n  \"content\": \"The content of the post\",\n  \"audio_url\": \"link to mp3 attached to post (if present)\",\n  \"image_url\": \"link to image attached to post (if present)\n}<\/code><\/pre>\n\n\n\n<p>Note: <code>published<\/code> will be <code>null<\/code> if the RSS feed did not specify a valid published date.<\/p>\n\n\n\n<p>The <code>feed<\/code> element provides information about the feed from which the post originates:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>{\n  \"id\": \"The unique identifier of the feed\",\n  \"source_url\": \"The URL of the source, for example RSS\/Atom feed URL\",\n  \"public_url\": \"The source's self identified public URL\",\n  \"title\": \"The title of the feed\",\n  \"favicon\": \"The URL of the feed's favicon\"\n}<\/code><\/pre>\n\n\n\n<p>We might make additions to these objects in the future. If you are missing anything, please let us know.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Retry logic<\/strong><\/h2>\n\n\n\n<p>We have built-in robustness with a retry mechanism. If a POST request does not receive a HTTP response code between 200 and 399, we will attempt to resend it based on a specific schedule, defined in seconds:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Retry 1: After 5 seconds<\/li>\n\n\n\n<li>Retry 2: After 30 seconds<\/li>\n\n\n\n<li>Retry 3: After 60 seconds<\/li>\n\n\n\n<li>Retry 4: 5 minutes<\/li>\n\n\n\n<li>Retry 5: 10 minutes<\/li>\n\n\n\n<li>Retry 6: 30 minutes<\/li>\n\n\n\n<li>Retry 7: 30 minutes<\/li>\n\n\n\n<li>Retry 8: 30 minutes<\/li>\n<\/ul>\n\n\n\n<p>Please note that this retry mechanism is only triggered upon real post events and it does not apply to test notifications. The timings are also subject to change.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Debugging<\/strong><\/h2>\n\n\n\n<p>If errors occur you can find them in the action run log. Simply visit the rule that is not working and press &#8220;Open error log&#8221;<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"379\" src=\"https:\/\/feeder.co\/help\/wp-content\/uploads\/sites\/2\/2023\/06\/image-1024x379.png\" alt=\"\" class=\"wp-image-1220\" srcset=\"https:\/\/feeder.co\/help\/wp-content\/uploads\/sites\/2\/2023\/06\/image-1024x379.png 1024w, https:\/\/feeder.co\/help\/wp-content\/uploads\/sites\/2\/2023\/06\/image-300x111.png 300w, https:\/\/feeder.co\/help\/wp-content\/uploads\/sites\/2\/2023\/06\/image-768x284.png 768w, https:\/\/feeder.co\/help\/wp-content\/uploads\/sites\/2\/2023\/06\/image-1536x568.png 1536w, https:\/\/feeder.co\/help\/wp-content\/uploads\/sites\/2\/2023\/06\/image-2048x757.png 2048w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>There you will see more details about the webhooks that failed.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"895\" height=\"1024\" src=\"https:\/\/feeder.co\/help\/wp-content\/uploads\/sites\/2\/2023\/06\/Screenshot-2023-06-26-at-14.51.08-895x1024.png\" alt=\"\" class=\"wp-image-1221\" srcset=\"https:\/\/feeder.co\/help\/wp-content\/uploads\/sites\/2\/2023\/06\/Screenshot-2023-06-26-at-14.51.08-895x1024.png 895w, https:\/\/feeder.co\/help\/wp-content\/uploads\/sites\/2\/2023\/06\/Screenshot-2023-06-26-at-14.51.08-262x300.png 262w, https:\/\/feeder.co\/help\/wp-content\/uploads\/sites\/2\/2023\/06\/Screenshot-2023-06-26-at-14.51.08-768x879.png 768w, https:\/\/feeder.co\/help\/wp-content\/uploads\/sites\/2\/2023\/06\/Screenshot-2023-06-26-at-14.51.08-1342x1536.png 1342w, https:\/\/feeder.co\/help\/wp-content\/uploads\/sites\/2\/2023\/06\/Screenshot-2023-06-26-at-14.51.08.png 1344w\" sizes=\"auto, (max-width: 895px) 100vw, 895px\" \/><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Setting up your webhook<\/strong><\/h2>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"586\" src=\"https:\/\/feeder.co\/help\/wp-content\/uploads\/sites\/2\/2023\/06\/webhook_setup-1024x586.png\" alt=\"\" class=\"wp-image-1215\" srcset=\"https:\/\/feeder.co\/help\/wp-content\/uploads\/sites\/2\/2023\/06\/webhook_setup-1024x586.png 1024w, https:\/\/feeder.co\/help\/wp-content\/uploads\/sites\/2\/2023\/06\/webhook_setup-300x172.png 300w, https:\/\/feeder.co\/help\/wp-content\/uploads\/sites\/2\/2023\/06\/webhook_setup-768x439.png 768w, https:\/\/feeder.co\/help\/wp-content\/uploads\/sites\/2\/2023\/06\/webhook_setup-1536x879.png 1536w, https:\/\/feeder.co\/help\/wp-content\/uploads\/sites\/2\/2023\/06\/webhook_setup-2048x1172.png 2048w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>To set up your webhook:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Navigate to the <a href=\"https:\/\/feeder.co\/settings\/actions\">Rules<\/a> page.<\/li>\n\n\n\n<li>Create a new Rule<\/li>\n\n\n\n<li>Add your name, feeds and criteria<\/li>\n\n\n\n<li>In the &#8220;What should happen?&#8221; section, choose &#8220;Post to Webhook&#8221;<\/li>\n\n\n\n<li>Enter your webhook URL in the text field provided.<\/li>\n\n\n\n<li>To ensure that everything is set up correctly, you can use the &#8220;Post test message&#8221; button to trigger a test notification to your endpoint. Please note that this is just a test, and it will not initiate the retry logic if it fails. Also, for the test post to be sent, you need at least 1 feed with posts added to your account.<\/li>\n<\/ol>\n\n\n\n<h3 class=\"wp-block-heading\">Security: Verifying webhook signatures<\/h3>\n\n\n\n<p>To ensure that incoming webhook requests are genuinely from Feeder and haven&#8217;t been tampered with, you can verify the webhook secret that is generated for each webhook. Every webhook request will include an <code>X-Feeder-Signature<\/code> header containing an HMAC-SHA256 signature of the request body.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">How it works<\/h3>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"715\" src=\"https:\/\/feeder.co\/help\/wp-content\/uploads\/sites\/2\/2023\/07\/2026-02-07-at-10.35.15-1024x715.png\" alt=\"\" class=\"wp-image-1534\" srcset=\"https:\/\/feeder.co\/help\/wp-content\/uploads\/sites\/2\/2023\/07\/2026-02-07-at-10.35.15-1024x715.png 1024w, https:\/\/feeder.co\/help\/wp-content\/uploads\/sites\/2\/2023\/07\/2026-02-07-at-10.35.15-300x210.png 300w, https:\/\/feeder.co\/help\/wp-content\/uploads\/sites\/2\/2023\/07\/2026-02-07-at-10.35.15-768x537.png 768w, https:\/\/feeder.co\/help\/wp-content\/uploads\/sites\/2\/2023\/07\/2026-02-07-at-10.35.15-1536x1073.png 1536w, https:\/\/feeder.co\/help\/wp-content\/uploads\/sites\/2\/2023\/07\/2026-02-07-at-10.35.15.png 1872w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<ol class=\"wp-block-list\">\n<li>In your Rule settings, toggle the &#8220;Advanced&#8221; option. You will see a string in the &#8220;Webhook Secret&#8221; field. <\/li>\n\n\n\n<li>When Feeder sends a webhook to your endpoint, it computes an HMAC-SHA256 hash of the JSON request body using your secret as the key.<\/li>\n\n\n\n<li>The resulting signature is sent in the <code>X-Feeder-Signature<\/code> header, prefixed with <code>sha256=<\/code>. For example:<\/li>\n<\/ol>\n\n\n\n<pre class=\"wp-block-code\"><code>   X-Feeder-Signature: sha256=a1b2c3d4e5f6...<\/code><\/pre>\n\n\n\n<ol start=\"4\" class=\"wp-block-list\">\n<li>On your server, you recompute the same HMAC-SHA256 hash using the raw request body and your copy of the secret, then compare it to the value in the header.<\/li>\n<\/ol>\n\n\n\n<h3 class=\"wp-block-heading\">Why use this?<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Authenticity<\/strong>: Confirms the request was sent by Feeder, not a third party.<\/li>\n\n\n\n<li><strong>Integrity<\/strong>: Guarantees the payload has not been modified in transit.<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">Verifying the signature<\/h3>\n\n\n\n<p>To verify:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Read the raw request body as a string (do not parse it first).<\/li>\n\n\n\n<li>Compute the HMAC-SHA256 of that string using your secret.<\/li>\n\n\n\n<li>Compare your computed signature with the <code>X-Feeder-Signature<\/code> header value using a <strong>timing-safe comparison<\/strong> to prevent timing attacks.<\/li>\n<\/ol>\n\n\n\n<h3 class=\"wp-block-heading\">Example: Node.js (Express)<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code>const crypto = require(\"crypto\");\n\nconst WEBHOOK_SECRET = process.env.FEEDER_WEBHOOK_SECRET;\n\nfunction verifyFeederSignature(req, res, next) {\n  const signature = req.headers&#91;\"x-feeder-signature\"];\n  if (!signature) {\n    return res.status(401).send(\"Missing signature\");\n  }\n\n  const expectedSignature =\n    \"sha256=\" +\n    crypto.createHmac(\"sha256\", WEBHOOK_SECRET).update(req.body).digest(\"hex\");\n\n  const isValid = crypto.timingSafeEqual(\n    Buffer.from(signature),\n    Buffer.from(expectedSignature)\n  );\n\n  if (!isValid) {\n    return res.status(401).send(\"Invalid signature\");\n  }\n\n  next();\n}\n\n\/\/ Important: use express.raw() so req.body is the raw string, not parsed JSON\napp.post(\n  \"\/webhook\",\n  express.raw({ type: \"application\/json\" }),\n  verifyFeederSignature,\n  (req, res) =&gt; {\n    const payload = JSON.parse(req.body);\n    \/\/ Handle the webhook payload\n    console.log(\"Received verified webhook:\", payload);\n    res.sendStatus(200);\n  }\n);<\/code><\/pre>\n\n\n\n<p><strong>Important:<\/strong> You must access the raw request body for signature verification. If your framework parses the JSON body before you compute the HMAC, the re-serialized string may differ from the original and the signature will not match. In Express, use <code>express.raw({ type: \"application\/json\" })<\/code> on the webhook route as shown above.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Anything else?<\/h2>\n\n\n\n<p>If you have further queries, please feel free to reach out to our support team.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>The &#8220;Post to Webhook&#8221; rule enables you to automate the process of sending new RSS feed posts to your specified webhook endpoint, as soon as they become available. You can also fine-tune what posts are being sent by setting up keywords to filter on. When a new post matches your criteria, it will be sent [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2}},"categories":[206],"tags":[],"yst_prominent_words":[],"class_list":["post-1214","post","type-post","status-publish","format-standard","hentry","category-automation"],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"jetpack_shortlink":"https:\/\/wp.me\/p893aM-jA","_links":{"self":[{"href":"https:\/\/feeder.co\/help\/wp-json\/wp\/v2\/posts\/1214","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/feeder.co\/help\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/feeder.co\/help\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/feeder.co\/help\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/feeder.co\/help\/wp-json\/wp\/v2\/comments?post=1214"}],"version-history":[{"count":11,"href":"https:\/\/feeder.co\/help\/wp-json\/wp\/v2\/posts\/1214\/revisions"}],"predecessor-version":[{"id":1535,"href":"https:\/\/feeder.co\/help\/wp-json\/wp\/v2\/posts\/1214\/revisions\/1535"}],"wp:attachment":[{"href":"https:\/\/feeder.co\/help\/wp-json\/wp\/v2\/media?parent=1214"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/feeder.co\/help\/wp-json\/wp\/v2\/categories?post=1214"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/feeder.co\/help\/wp-json\/wp\/v2\/tags?post=1214"},{"taxonomy":"yst_prominent_words","embeddable":true,"href":"https:\/\/feeder.co\/help\/wp-json\/wp\/v2\/yst_prominent_words?post=1214"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}