Feedspace Home Dashboard

How Do I Verify Feedspace Webhook Signatures?

Last updated on June 15, 2026

Overview

Feedspace signs every webhook payload with a secret key using HMAC-SHA256. This signature is included in the X-Feedspace-Signature header of each request. By verifying this signature on your server before processing the payload, you can confirm the request genuinely came from Feedspace and reject any spoofed or tampered requests.

Why Signature Verification Matters

Without signature verification, any party that knows your webhook endpoint URL could send a forged payload to your server. Verifying the signature ensures:

  • The payload was sent by Feedspace and has not been altered in transit.
  • Your server ignores requests from unauthorized sources.
  • Your downstream workflows and data remain trustworthy.

Always validate the signature before reading or acting on the payload.

Steps to Verify a Webhook Signature

Step 1: Get Your Webhook Secret

  1. In your Feedspace dashboard, go to Automation in the left sidebar.
  2. Click the Webhook tab.
  3. Find the webhook you want to verify and click Edit.
  4. Copy the Webhook Secret shown in the edit panel. This is the key you will use to compute the expected signature.

Store this secret securely as an environment variable on your server. Never hard-code it in your source code or commit it to version control.

Step 2: Read the Signature Header

When Feedspace sends a webhook request to your endpoint, it includes a header named X-Feedspace-Signature. This header contains the HMAC-SHA256 hash of the raw request body, encoded as a hex string. Read this value before you parse or modify the request body.

Step 3: Compute the Expected Signature

Using your webhook secret as the key, compute an HMAC-SHA256 hash of the raw request body (the exact bytes received, before any JSON parsing). Encode the result as a lowercase hex string.

Step 4: Compare the Signatures

Compare the computed hash against the value in the X-Feedspace-Signature header using a constant-time comparison. If they match, the request is authentic. If they do not match, reject the request with a 401 Unauthorized response and do not process the payload.

Use a constant-time comparison (such as crypto.timingSafeEqual in Node.js or hmac.compare_digest in Python) to prevent timing attacks.

Code Examples

Node.js Example

const crypto = require('crypto');

function verifyFeedspaceSignature(req, secret) {
  const signatureHeader = req.headers['x-feedspace-signature'];

  if (!signatureHeader) {
    return false;
  }

  // req.rawBody must be the raw Buffer or string received before JSON parsing
  const computedSignature = crypto
    .createHmac('sha256', secret)
    .update(req.rawBody)
    .digest('hex');

  const headerBuffer = Buffer.from(signatureHeader, 'hex');
  const computedBuffer = Buffer.from(computedSignature, 'hex');

  if (headerBuffer.length !== computedBuffer.length) {
    return false;
  }

  // Use constant-time comparison to prevent timing attacks
  return crypto.timingSafeEqual(headerBuffer, computedBuffer);
}

// Example Express.js handler
app.post('/webhook', express.raw({ type: 'application/json' }), (req, res) => {
  const secret = process.env.FEEDSPACE_WEBHOOK_SECRET;
  req.rawBody = req.body;

  if (!verifyFeedspaceSignature(req, secret)) {
    return res.status(401).json({ error: 'Invalid signature' });
  }

  const payload = JSON.parse(req.rawBody);
  // Process payload here
  res.status(200).json({ received: true });
});

Python Example

import hmac
import hashlib
import os
from flask import Flask, request, abort

app = Flask(__name__)

def verify_feedspace_signature(raw_body: bytes, signature_header: str, secret: str) -> bool:
    if not signature_header:
        return False

    computed_signature = hmac.new(
        secret.encode('utf-8'),
        raw_body,
        hashlib.sha256
    ).hexdigest()

    # Use constant-time comparison to prevent timing attacks
    return hmac.compare_digest(computed_signature, signature_header)

@app.route('/webhook', methods=['POST'])
def webhook():
    secret = os.environ.get('FEEDSPACE_WEBHOOK_SECRET', '')
    signature_header = request.headers.get('X-Feedspace-Signature', '')
    raw_body = request.get_data()

    if not verify_feedspace_signature(raw_body, signature_header, secret):
        abort(401)

    payload = request.get_json(force=True)
    # Process payload here
    return {'received': True}, 200

Important Notes

  • Use the raw request body: Compute the HMAC over the exact bytes received. Parsing the JSON first and re-serialising it can change byte ordering or whitespace and cause a mismatch.
  • Use constant-time comparison: Standard string equality checks are vulnerable to timing attacks. Always use crypto.timingSafeEqual (Node.js) or hmac.compare_digest (Python).
  • Store the secret securely: Keep your webhook secret in an environment variable or a secrets manager. Rotate it if you suspect it has been exposed.
  • Reject early: Return a 401 response immediately if the signature is missing or invalid. Do not process any part of the payload before verification passes.

Troubleshooting

Signature always fails even with the correct secret

The most common cause is that your framework has already parsed the request body before your handler runs. Make sure you are computing the HMAC over the raw bytes, not over a re-serialised JSON object. In Express.js, use express.raw() middleware instead of express.json() for the webhook route. In Flask, call request.get_data() before request.get_json().

The header is missing

If the X-Feedspace-Signature header is absent, the request was not sent by Feedspace or was stripped by a proxy. Reject it with a 401 response.

I rotated the secret but signatures still fail

After saving a new secret in Feedspace, redeploy or restart your server so it picks up the updated environment variable. If your server cached the old secret value, it will continue to reject valid requests until the cache is cleared.

You might also find helpful

How to Use Webhooks in Feedspace

Overview Feedspace provides webhooks to notify your application about important events in real-time. With webhooks, you can automatically trigger workflows in your system whenever reviews are collected on Feedspace. Reference: Feedspace Webhook Documentation Step 1 – Access Automation Webhook Step 2 – Add Your Endpoint URL Step 3 – Select...

How Do I Test My Feedspace Webhook Integration?

Overview Before connecting your production server, you can test your Feedspace webhook integration using a free temporary URL service. This lets you inspect the exact JSON payload Feedspace sends, confirm your event selection is correct, and validate your signature verification code, all without writing a single line of server code...

What Is the Feedspace REST API?

Overview The Feedspace REST API is a JSON-based HTTP API that gives developers direct, programmatic access to their Feedspace workspace. Using the API, you can submit reviews from your own application, retrieve reviews to display in a custom UI, automate review pipelines, and sync Feedspace data with external systems, all...