When you configure a webhook URL in your Outscraper integration settings, our system will automatically send a POST request with the scraped results to that URL whenever a task/reuqest is finished.

For security, every webhook payload is signed using your Outscraper API key. This allows you to verify that the webhook truly comes from Outscraper and has not been altered.

Step 1. Signature Header

Every webhook request includes an additional header:

				
					X-Hub-Signature-256: sha256=<signature>
				
			
  • <signature> is an HMAC-SHA256 digest of the raw JSON payload.

  • It is generated using your Outscraper API key.

  • To verify authenticity, you need to compute the same digest locally and compare it with the header.

Step 2. Example Webhook Request

Here’s what a real webhook request looks like:

				
					POST /webhooks HTTP/1.1
Host: your-domain.com
Content-Type: application/json
X-Hub-Signature-256: sha256=7b6b9d07b1c0d7ff3b4b3fcecbf9c08a5f6c2a248ef12c7a37a7269d3a5b1b93

{
  "id": "your-request-id",
  "user_id": "your-user-id",
  "status": "SUCCESS",
  "api_task": true,
  "results_location": "https://api.outscraper.cloud/requests/your-request-id",
  "quota_usage": [
    {
      "product_name": "Google Maps Data",
      "quantity": 1
    }
  ]
}

				
			

Step 3. Verifying

To verify a webhook request, you must:

  1. Read the raw JSON payload (not the parsed object).

  2. Compute an HMAC-SHA256 digest of this payload using your API key.

  3. Prepend it with "sha256=" and compare to the value in the X-Hub-Signature-256 header.

  4. Reject the request if the signatures don’t match.

Python Example

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

app = Flask(__name__)

API_KEY = "your_api_key_here"  # your Outscraper API key

def generate_hmac_sha256(secret: str, data: str) -> str:
    return hmac.new(secret.encode("utf-8"), data.encode("utf-8"), hashlib.sha256).hexdigest()

@app.route("/webhooks", methods=["POST"])
def webhook():
    # Raw JSON payload as text
    payload = request.get_data(as_text=True)
    # Signature header from Outscraper
    signature_header = request.headers.get("X-Hub-Signature-256", "")

    # Compute expected signature
    expected_signature = "sha256=" + generate_hmac_sha256(API_KEY, payload)

    # Secure comparison
    if not hmac.compare_digest(signature_header, expected_signature):
        abort(401, "Invalid signature")

    data = json.loads(payload)
    print("Verified payload:", data)

    return "ok", 200

				
			

Node.js Example

				
					const crypto = require("crypto");
const express = require("express");
const bodyParser = require("body-parser");

const app = express();
app.use(bodyParser.json({ verify: (req, res, buf) => { req.rawBody = buf.toString() } }));

const API_KEY = "your_api_key_here"; // your Outscraper API key

function generateHmacSha256(secret, data) {
  return crypto.createHmac("sha256", secret).update(data, "utf8").digest("hex");
}

app.post("/webhooks", (req, res) => {
  const signature = req.headers["x-hub-signature-256"];
  const expected = "sha256=" + generateHmacSha256(API_KEY, req.rawBody);

  if (!crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected))) {
    return res.status(401).send("Invalid signature");
  }

  console.log("Verified payload:", req.body);
  res.send("ok");
});

app.listen(3000, () => console.log("Webhook listener running on port 3000"));

				
			

PHP Example

				
					<?php
$API_KEY = "your_api_key_here"; // your Outscraper API key

// Get raw POST body
$payload = file_get_contents("php://input");

// Get signature from headers
$signatureHeader = $_SERVER["HTTP_X_HUB_SIGNATURE_256"] ?? "";

// Compute expected signature
$expectedSignature = "sha256=" . hash_hmac("sha256", $payload, $API_KEY);

// Compare securely
if (!hash_equals($expectedSignature, $signatureHeader)) {
    http_response_code(401);
    die("Invalid signature");
}

// Decode and process verified payload
$data = json_decode($payload, true);
error_log("Verified payload: " . print_r($data, true));

http_response_code(200);
echo "ok";

				
			

Step 4. What to Do if Verification Fails

If the computed signature does not match the header:

  • Reject the request (401 Unauthorized).

  • Log the attempt for debugging/audit.

  • Do not process the payload.

Step 5. Testing

You can test your verification logic by triggering a webhook from Outscraper.
The signature will always validate correctly as long as you use your API key.

Резюме

  • All Outscraper webhooks are signed using your API key.

  • Verify requests by computing:

    sha256(HMAC(api_key, raw_payload))
  • Compare the computed digest with the X-Hub-Signature-256 header.

  • Only process verified requests to keep your system secure.

References

The method Outscraper uses is the same approach trusted by major platforms for verifying webhook authenticity:

These examples show that verifying webhook signatures with HMAC-SHA256 is the standard way to confirm authenticity and prevent tampering.

Категории: APIPyhtonУчебники

Влад

Руководитель проекта Linkedin