Back to blog

Set Up E-Commerce Webhooks for Price Drop Alerts

March 6, 2026 · 6 min read

Polling APIs every few minutes to check for price changes is wasteful and slow. Webhooks flip the model: instead of you checking for changes, ShelfRun notifies you the moment something changes. Here's how to set up real-time price drop alerts.

How ShelfRun Webhooks Work

When you add a store to ShelfRun, you provide a webhook URL. After each sync, ShelfRun compares the new data to the previous snapshot. If anything changed, it fires a POST request to your webhook URL with the diff.

You get webhooks for:

  • Price drops — any product price decreases
  • Price increases — products become more expensive
  • Stock changes — in stock ↔ out of stock transitions
  • New products — competitor launches something new
  • Removed products — competitor discontinues a product

Step 1: Set Up Your Webhook Endpoint

Create a simple endpoint to receive ShelfRun webhooks. Here's a Flask example:

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

app = Flask(__name__)
WEBHOOK_SECRET = os.environ["SHELFRUN_WEBHOOK_SECRET"]

def verify_signature(payload, signature):
    """Verify the webhook came from ShelfRun."""
    expected = hmac.new(
        WEBHOOK_SECRET.encode(),
        payload,
        hashlib.sha256
    ).hexdigest()
    return hmac.compare_digest(expected, signature)

@app.route("/shelfrun-webhook", methods=["POST"])
def handle_webhook():
    # Verify signature
    sig = request.headers.get("X-ShelfRun-Signature", "")
    if not verify_signature(request.get_data(), sig):
        return jsonify({"error": "Invalid signature"}), 401

    data = request.json

    for change in data.get("changes", []):
        if change["type"] == "price_drop":
            handle_price_drop(change)
        elif change["type"] == "out_of_stock":
            handle_stockout(change)
        elif change["type"] == "new_product":
            handle_new_product(change)

    return jsonify({"ok": True})

def handle_price_drop(change):
    pct = change["change_pct"]
    product = change["product"]
    print(f"Price drop: {product} dropped {pct}%")
    # Add your logic: email, Slack, update your own pricing, etc.

Step 2: Register the Webhook with ShelfRun

import requests

response = requests.post(
    "https://api.shelfrun.com/v1/stores",
    headers={"X-API-Key": "sr_live_your_key"},
    json={
        "url": "competitor-store.com",
        "sync_frequency": "hourly",
        "webhook_url": "https://yourapp.com/shelfrun-webhook",
        "webhook_events": [
            "price_drop",
            "price_increase",
            "out_of_stock",
            "back_in_stock",
            "new_product"
        ]
    }
)

print(response.json())

The Webhook Payload

Every webhook POST contains a changes array with structured diffs:

{
  "store": "competitor-store.com",
  "store_id": "str_abc123",
  "sync_at": "2026-03-06T15:00:00Z",
  "changes": [
    {
      "type": "price_drop",
      "product": "Premium Widget",
      "sku": "WGT-001",
      "old_price": 89.99,
      "new_price": 69.99,
      "change_pct": -22.2,
      "currency": "USD",
      "product_url": "https://competitor-store.com/products/widget",
      "in_stock": true
    },
    {
      "type": "out_of_stock",
      "product": "Basic Widget",
      "sku": "WGT-002",
      "old_stock": "in_stock",
      "new_stock": "out_of_stock"
    }
  ]
}

Forward Alerts to Slack

The most common use case is forwarding price alerts to Slack:

import requests

SLACK_WEBHOOK = "https://hooks.slack.com/services/..."

def handle_price_drop(change):
    emoji = "🔻" if change["change_pct"] < -15 else "📉"
    old_p = str(change['old_price'])
    new_p = str(change['new_price'])
    pct = str(round(change['change_pct'], 1))
    message = (
        emoji + " *Price Drop Alert*\n"
        "*Product:* " + change['product'] + "\n"
        "*Old price:* $" + old_p + "\n"
        "*New price:* $" + new_p + " (" + pct + "%)\n"
        "<" + change['product_url'] + "|View product>"
    )

    requests.post(SLACK_WEBHOOK, json={"text": message})

Set Thresholds to Reduce Noise

Not every price change matters. Filter webhooks to only act on significant drops:

SIGNIFICANT_DROP_PCT = -10  # Only alert on 10%+ drops
SIGNIFICANT_DROP_ABS = 5.00  # Or $5+ absolute drops

def is_significant(change):
    pct_significant = change["change_pct"] <= SIGNIFICANT_DROP_PCT
    abs_drop = change["old_price"] - change["new_price"]
    abs_significant = abs_drop >= SIGNIFICANT_DROP_ABS
    return pct_significant or abs_significant

@app.route("/shelfrun-webhook", methods=["POST"])
def handle_webhook():
    data = request.json
    for change in data.get("changes", []):
        if change["type"] == "price_drop" and is_significant(change):
            handle_significant_price_drop(change)

Test Your Webhook

ShelfRun lets you send a test webhook to verify your endpoint is working before relying on it in production. Use the API docs for the test endpoint details.

Related Reading

Get real-time price alerts

5 free API calls to get started. No credit card required.