Webhook for price list updates: how to receive instant notifications about changes
-
Elbuz Team
Copywriter Elbuz
Imagine: a supplier has reduced the price of a popular product by 20%, but your store only learns about it six hours later, when the next scheduled synchronization occurs. By that time, competitors have already sold dozens of units at the new price, and you've lost customers and lost profits.
The traditional data synchronization method—polling—is outdated. Modern businesses require immediate responses to changes. Webhooks solve this problem by delivering updates as they occur. In this article, you'll learn how to set up a webhook to receive instant notifications about price changes, inventory, and new products from suppliers.
Webhook vs. Polling: Why Instant Notifications Are More Effective
Before diving into the technical details, let's look at how webhooks differ fundamentally from traditional polling and what benefits they offer businesses.
What is Polling?
Polling is a method where your system regularly queries the data source asking "are there any updates?" For example, every hour your script checks if the price list on the supplier's server has changed.
Disadvantages of polling:
- Delayed updates - if the poll is performed once an hour, the average delay will be 30 minutes
- Empty queries — 90% of queries return a "no changes" response, wasting resources
- Server load - constant requests create load even when the data does not change
- API limitations — many providers limit the number of requests per day
- Difficulty scaling — when adding new sources, the number of requests grows linearly
What is a Webhook (Callback)
A webhook is a push notification mechanism where the data source itself sends information to your system when an event occurs. Instead of constantly polling for "any updates?", you receive a "here's an update!" message immediately after a change.
Advantages of webhooks:
- Instant updates — the delay is seconds, not hours
- Efficiency — data is transmitted only when something has changed
- Minimum load - no constant requests to check for updates
- Scalability — the number of sources does not affect the load
- Saving resources — API limits are not consumed by empty checks
Comparison table
| Parameter | Polling | Webhook |
|---|---|---|
| Update delay | Minutes-hours | 1-5 seconds |
| Use of resources | Constant load | Only during events |
| Number of requests | Fixed (scheduled) | Depends on the frequency of changes |
| Efficiency | 5-10% (useful queries) | 100% (all data requests) |
| Difficulty of setup | Low | Average |
| Scalability | Limited | High |
| Price | €50-200/month (server + API) | €20-100/month (hosting only) |
Real life example: An online electronics store with 50 suppliers switched from polling (checked hourly) to webhooks. Results for the first month:
- Price update delay has been reduced from 30 minutes to 3 seconds.
- The number of API requests decreased by 94% (from 36,000 to 2,100 per month)
- Server load has decreased by 87%.
- Conversion increased by 12% thanks to up-to-date data
How Webhooks Work: A Simple Explainer
A webhook is an automated HTTP POST request sent to a specified URL when a specific event occurs. Simply put, it's a "callback" from the provider's system to your server.
Webhook concept
Think of a webhook as a restaurant notification order:
- Polling: You go to the kitchen every 5 minutes and ask "Is my order ready?"
- Webhook: You leave a table number, and the waiter brings your order when it's ready.
Webhook system components
1. Publisher
A supplier system or service that generates events (price change, inventory update, new product).
2. Event
The specific action that occurred in the publisher's system:
- price.updated — the price of the product has changed
- stock.changed — the stock has been updated
- product.created — a new product has been added
- productdeleted — the product has been discontinued
3. Webhook URL (Endpoint)
The address of your server where notifications will be sent. For example: https://your-shop.com/api/webhooks/price-updates
4. Payload
JSON data containing information about the event: what changed, old and new value, timestamp.
5. Subscriber
Your server, which receives webhook requests, processes the data and updates the database.
How a webhook works
- Registration webhook: You specify the URL for receiving notifications in the provider's system and select the event types
- Event occurrence: the supplier updates the price of the product in its system
- Payload generation: the system creates a JSON with information about the change
- Sending an HTTP POST request: data is sent to your webhook URL
- Receipt and validation: Your server accepts the request and verifies the security signature.
- Data processing: extracting information and updating the database
- Sending a reply: return HTTP 200 OK to confirm successful processing
Visualization of the process
Example of webhook lifecycle:
[Supplier System] ↓ Manager changes the price of SKU-12345 from €199 to €179 ↓ Trigger: price.updated ↓ Generate JSON payload ↓ POST https://your-shop.com/api/webhooks/price-updates Content-Type: application/json X-Webhook-Signature: sha256=abc123... { "event": "price.updated", "timestamp": "2025-01-15T14:30:00Z", "product":{ "sku": "SKU-12345", "name": "Laptop Dell XPS 15", "old_price": 199.00, "new_price": 179.00, "currency": "EUR" } } ↓ [Your server] Verifying signature → OK Retrieving data → SKU-12345 Update in DB: SET price = 179 WHERE sku = 'SKU-12345' ↓ Response: HTTP 200 OK ↓ [Provider system] Webhook delivered successfully ✓Understanding this mechanism is critical for properly configuring and debugging webhook integration. In the following sections, we'll cover the practical implementation of each component.
Step-by-step guide to setting up a webhook
Now let's get practical. Setting up a webhook involves both the provider and your side. Let's look at the process step by step.
Step 1: Create a webhook endpoint on your server
The first thing you need to do is create a handler—a special URL that will receive incoming webhook requests.
Endpoint requirements:
- Accessibility via HTTPS (not HTTP!) is a mandatory security requirement
- Public IP or domain name - webhook cannot be sent to localhost
- Fast processing - response should be returned within 5-10 seconds
- Idempotency is the ability to process the same request multiple times without duplicating the effect.
Example of a simple webhook handler (Node.js + Express):
const express = require('express'); const crypto = require('crypto'); const app = express(); app.use(express.json()); // Webhook endpoint app.post('/api/webhooks/price-updates', async (req, res) => { try { // Step 1: Signature verification (see Security section) const signature = req.headers['x-webhook-signature']; if (!verifySignature(req.body, signature)) { return res.status(401).json({ error: 'Invalid signature' } ); } // Step 2: Fetch data const { event, product } = req.body; // Step 3: Handle the event if (event === 'price.updated') { await updateProductPrice(product.sku, product.new_price); } // Step 4: Quick response res.status(200).json({ status: 'received' } ); // Step 5: Additional asynchronous processing // (logging, notifications, etc.) } catch (error) { console.error('Webhook error:', error); res.status(500).json({ error: 'Internal server error' } ); } }); app.listen(3000);Step 2: Register your webhook with your provider
Once an endpoint is created, it must be registered in the provider's system. The process varies depending on the platform, but the general logic is the same.
Typical registration process:
- Log in to your supplier's personal account or API console
- Find the "Webhooks," "API Notifications," or "Integrations" section.
- Click "Add Webhook" or "Create New"
- Enter your webhook URL:
https://your-shop.com/api/webhooks/price-updates - Select event types (price.updated, stock.changed, product.created)
- Configure security settings (secret key for signing)
- Save the webhook and copy the secret key.
Step 3: Setting up event types
Select only the events you need to avoid overloading the system with unnecessary notifications.
Main types of events for price lists:
| Event | Description | When to use |
|---|---|---|
| price updated | The price of the product has changed | Always critical information |
| stock.changed | The remaining stock has been updated | For products with dynamic availability |
| stock.low | The remainder is below the critical level | For procurement management |
| product.created | New product added | To automatically replenish the catalog |
| product updated | Product specifications have changed | If the relevance of descriptions is important |
| product deleted | The product has been discontinued | To automatically remove from the directory |
Step 4: Implementing the Event Handler
Create processing logic for each event type.
An example of a handler with support for various events:
async function handleWebhook(event, data) { switch(event) { case 'price.updated': await db.query( 'UPDATE products SET price =?, updated_at = NOW() WHERE sku =?', [data.new_price, data.sku] ); await logPriceChange(data.sku, data.old_price, data.new_price); break; case 'stock.changed': await db.query( 'UPDATE products SET stock =?, in_stock =? WHERE sku =?', [data.quantity, data.quantity > 0, data.sku] ); if (data.quantity === 0) { await notifyOutOfStock(data.sku); } break; case 'product.created': await db.query( 'INSERT INTO products (sku, name, price, stock) VALUES (?,?,?,?)', [data.sku, data.name, data.price, data.stock] ); await triggerProductImport(data.sku); break; case 'product.deleted': await db.query( 'UPDATE products SET status =? WHERE sku =?', ['discontinued', data.sku] ); break; default: console.warn('Unknown event type:', event); } }Step 5: Testing the webhook
Be sure to test the webhook before launching it in production.
Testing methods:
- Using test data from the supplier — many platforms allow you to send a test webhook
- Tools for local development — ngrok, localtunnel for testing on localhost
- Webhook testing tools — webhook.site, requestbin.com for request inspection
- Curl requests — manual sending of webhook-like requests
Example of a test curl request:
curl -X POST https://your-shop.com/api/webhooks/price-updates \ -H "Content-Type: application/json" \ -H "X-Webhook-Signature: sha256=test_signature" \ -d '{ "event": "price.updated", "timestamp": "2025-01-15T14:30:00Z", "product":{ "sku": "TEST-SKU", "name": "Test Product", "old_price": 100.00, "new_price": 90.00, "currency": "EUR" } }'Step 6: Monitoring and Logging
Once a webhook has been launched, it is critical to monitor its performance.
What to log:
- All incoming webhook requests (timestamp, event type, data)
- Processing results (success/error)
- Processing time for each webhook
- Signature validation errors
- Duplicate requests (by event ID)
Step 7: Setting up error handling
Even with a perfect setup, glitches are possible. The system must be able to cope with them.
Error handling strategy:
- Return HTTP 200 only if processing is successful
- HTTP 4xx for validation errors (invalid signature, unknown event)
- HTTP 5xx for temporary problems (DB unavailable, timeout)
- The supplier's system must retry the send upon receipt of 5xx
Step 8: Optimize Performance
With a large flow of events, efficient processing is important.
Optimization recommendations:
- Asynchronous processing — the webhook handler quickly returns 200 OK, and the actual processing is performed in the background
- Task queue — using Redis Queue, RabbitMQ for load balancing
- Batch updates - grouping changes and applying them in blocks
- Caching - Avoid repeated database queries for the same data
Important: Webhook response time
Most webhook providers expect a response within 5-10 seconds. If your handler doesn't respond in time, the webhook will be considered unsuccessful and will be resent. Use asynchronous processing for long-running operations.
Webhook Payload Structure: JSON Examples
Payload is the data a webhook sends to your server. Understanding the payload structure is critical for proper event processing.
Basic structure of a webhook payload
Most webhooks follow a standard structure:
General structure:
{ "id": "webhook_evt_1234567890", "event": "event.type", "timestamp": "2025-01-15T14:30:00Z", "api_version": "2024-01", "data": { // Event-specific data } }Payload examples for various events
1. Price change (price.updated)
{ "id": "evt_price_update_001", "event": "price.updated", "timestamp": "2025-01-15T14:30:15.123Z", "api_version": "2024-01", "data": { "product":{ "id": "prod_12345", "sku": "LAPTOP-XPS-15", "name": "Dell XPS 15 9520", "old_price": 1499.00, "new_price": 1299.00, "currency": "USD", "price_change_percentage": -13.34, "changed_by": "admin@supplier.com", "reason": "seasonal_discount" }, "supplier":{ "id": "sup_789", "name": "Tech Wholesale Inc.", "location": "USA" } } }2. Updating balances (stock.changed)
{ "id": "evt_stock_change_002", "event": "stock.changed", "timestamp": "2025-01-15T15:22:40.456Z", "api_version": "2024-01", "data": { "product":{ "id": "prod_12345", "sku": "LAPTOP-XPS-15", "name": "Dell XPS 15 9520", "old_quantity": 45, "new_quantity": 12, "warehouse": "warehouse_us_east", "stock_status": "in_stock", "reserved": 3, "available": 9 }, "change_details":{ "reason": "order_fulfillment", "order_id": "ord_98765", "units_sold": 33 } } }3. New product (product.created)
{ "id": "evt_product_created_003", "event": "product.created", "timestamp": "2025-01-15T09:15:30.789Z", "api_version": "2024-01", "data": { "product": { "id": "prod_67890", "sku": "PHONE-IPHONE-15-PRO", "name": "Apple iPhone 15 Pro 256GB", "brand": "Apple", "category": "Smartphones", "price": 1199.00, "currency": "EUR", "stock": 150, "description": "Latest iPhone with titanium design", "images": [ "https://cdn.supplier.com/images/iphone-15-pro-1.jpg", "https://cdn.supplier.com/images/iphone-15-pro-2.jpg" ], "attributes":{ "color": "Natural Titanium", "storage": "256GB", "weight": "187g", "warranty": "12 months" }, "dimensions":{ "length": 146.6, "width": 70.6, "height": 8.25, "unit": "mm" } } } }4. Critical balance (stock.low)
{ "id": "evt_stock_low_004", "event": "stock.low", "timestamp": "2025-01-15T18:45:00.234Z", "api_version": "2024-01", "data": { "product":{ "id": "prod_12345", "sku": "LAPTOP-XPS-15", "name": "Dell XPS 15 9520", "current_quantity": 3, "threshold": 5, "warehouse": "warehouse_us_east", "estimated_depletion": "2025-01-17T12:00:00Z" }, "alert":{ "severity": "medium", "recommended_action": "reorder", "suggested_order_quantity": 50, "lead_time_days": 7 } } }5. Product deletion (productdeleted)
{ "id": "evt_product_deleted_005", "event": "product.deleted", "timestamp": "2025-01-15T11:20:00.567Z", "api_version": "2024-01", "data": { "product":{ "id": "prod_54321", "sku": "TABLET-SAMSUNG-S8", "name": "Samsung Galaxy Tab S8", "reason": "discontinued", "replacement_sku": "TABLET-SAMSUNG-S9", "final_stock": 0 }, "deletion_details":{ "deleted_by": "manager@supplier.com", "note": "Model discontinued, replaced with S9" } } }Important fields in the payload
| Field | Purpose | Mandatory |
|---|---|---|
| ID | Unique event identifier for idempotency | Yes |
| event | Event type to define a handler for | Yes |
| timestamp | Event occurrence time (ISO 8601) | Yes |
| api_version | API version for backward compatibility | Recommended |
| data | Event payload | Yes |
Processing nested data
Many webhooks contain nested objects. It's important to extract the data correctly:
Example of processing a nested payload:
function processWebhook(payload) { const eventId = payload.id; const eventType = payload.event; const eventData = payload.data; // Check for duplicate if (isEventProcessed(eventId)){ console.log('Event already processed:', eventId); return; } // Retrieving product data const product = eventData.product; const sku = product.sku; const newPrice = product.new_price; // Processing updateProductInDatabase(sku,{ price: newPrice } ); // Save the event ID markEventAsProcessed(eventId); }Important: API versioning
The payload structure may change over time. Always check the field api_version and handle different versions correctly. Provide payload examples for each API version in the documentation.
Webhook Security: Signature Verification and HTTPS
A webhook endpoint is a publicly accessible URL that can receive data from any source. Without proper protection, attackers can send fake notifications, changing prices in your system, or creating fictitious products. Webhook security is critical.
Mandatory use of HTTPS
The first and absolutely mandatory requirement is to use HTTPS instead of HTTP.
Why HTTPS is essential:
- Data encryption — the payload contains confidential business information (prices, balances)
- Protection against interception — preventing man-in-the-middle attacks
- Safety standard — Most webhook providers do not send data to HTTP endpoints
- Trust — An SSL certificate confirms the legitimacy of your server.
Obtaining an SSL certificate:
- Let's Encrypt - free, automatically renewed certificates
- Cloudflare - free SSL when using their CDN
- Commercial CA — DigiCert, Sectigo for enterprise solutions
Signature Verification
HTTPS protects against interception, but not against forged requests. An attacker could send a webhook directly to your URL. Signature verification solves this problem.
How a webhook signature works:
- When you register a webhook, you receive a secret key.
- The sender creates an HMAC signature of the payload using the secret key.
- The signature is sent in the request header (usually X-Webhook-Signature)
- Your server computes the signature of the same payload with the same secret key.
- If the signatures match, the request is legitimate; if not, we reject it.
Implementation of HMAC signature verification
Signature verification example (Node.js):
const crypto = require('crypto'); const WEBHOOK_SECRET = 'your_webhook_secret_key_here'; function verifyWebhookSignature(payload, receivedSignature) { // Convert payload to a string const payloadString = JSON.stringify(payload); // Calculate HMAC-SHA256 signature const hmac = crypto.createHmac('sha256', WEBHOOK_SECRET); hmac.update(payloadString); const calculatedSignature = 'sha256=' + hmac.digest('hex'); // Secure comparison (protection against timing attacks) return crypto.timingSafeEqual( Buffer.from(calculatedSignature), Buffer.from(receivedSignature) ); } // Use in webhook handler app.post('/api/webhooks/price-updates', (req, res) => { const signature = req.headers['x-webhook-signature']; const payload = req.body; if (!verifyWebhookSignature(payload, signature)) { console.error('Invalid webhook signature'); return res.status(401).json({ error: 'Unauthorized' } ); } // Processing a valid webhook processWebhook(payload); res.status(200).json({ status: 'success' } ); });Signature verification example (Python):
import hmac import hashlib import json WEBHOOK_SECRET = b'your_webhook_secret_key_here' def verify_webhook_signature(payload, received_signature): # Convert payload to JSON string payload_string = json.dumps(payload, separators=(',', ':')) # Calculate HMAC-SHA256 calculated_hmac = hmac.new( WEBHOOK_SECRET, payload_string.encode('utf-8'), hashlib.sha256 ) calculated_signature = 'sha256=' + calculated_hmac.hexdigest() # Secure comparison return hmac.compare_digest(calculated_signature, received_signature) # Using in Flask @app.route('/api/webhooks/price-updates', methods=['POST']) def webhook_handler(): signature = request.headers.get('X-Webhook-Signature') payload = request.json if not verify_webhook_signature(payload, signature): return jsonify({'error': 'Unauthorized'} ), 401 process_webhook(payload) return jsonify({'status': 'success'} ), 200Additional security measures
1. IP Whitelist
If your provider provides a list of IP addresses from which webhooks are sent, configure your firewall:
- Allow access to the webhook endpoint only from the specified IPs
- Block all other requests
2. Timestamp validation
Make sure the webhook isn't too old (protection against replay attacks):
function isWebhookFresh(timestamp, maxAgeMinutes = 5) { const webhookTime = new Date(timestamp); const now = new Date(); const ageMinutes = (now - webhookTime) / 1000 / 60; return ageMinutes<= maxAgeMinutes; } // Использование if (!isWebhookFresh(payload.timestamp)) { return res.status(400).json({ error: 'Webhook too old' }); }3. Rate limiting
Limit the number of webhook requests to protect against DDoS:
- Maximum 100 requests per minute from one IP
- Maximum 1000 requests per hour from one source
4. Idempotency
Save the IDs of processed events to avoid duplication:
// Redis for storing processed events const redis = require('redis'); const client = redis.createClient(); async function isEventProcessed(eventId) { return await client.exists(`webhook:processed:${eventId}`); } async function markEventAsProcessed(eventId) { // Store for 24 hours await client.setex(`webhook:processed:${eventId}`, 86400, '1'); } // Using app.post('/api/webhooks/price-updates', async (req, res) => { const eventId = req.body.id; if (await isEventProcessed(eventId)) { console.log('Duplicate webhook, skipping:', eventId); return res.status(200).json({ status: 'already_processed' } ); } await processWebhook(req.body); await markEventAsProcessed(eventId); res.status(200).json({ status: 'success' } ); });Safe storage of secret keys
Never store your secret key in code:
- Environment variables — environment variables (.env file)
- Secret management services - AWS Secrets Manager, Azure Key Vault
- Encrypted configuration — encrypted config files
Example of using.env file:
#.env WEBHOOK_SECRET=sk_live_abc123def456ghi789jkl # In the code require('dotenv').config(); const WEBHOOK_SECRET = process.env.WEBHOOK_SECRET;Critical
Without signature verification, your webhook endpoint is vulnerable to attack. An attacker could reset all prices, create fake products, or remove the entire catalog from stock. ALWAYS verify the signature before processing a webhook.
Error handling and retry mechanism
Even a perfectly configured webhook can encounter problems: the network is temporarily unavailable, the database is rebooting, or the server is overloaded. Proper error handling and a retry mechanism are critical to system reliability.
HTTP status codes and their meanings
Your webhook endpoint must return the correct HTTP codes so that the sender understands what to do next.
| Code | Meaning | Sender's action |
|---|---|---|
| 200 OK | Webhook processed successfully | Do not resend |
| 201 Created | Resource created (for product.created) | Do not resend |
| 400 Bad Request | Invalid data in payload | Do not repeat (correct data) |
| 401 Unauthorized | Invalid webhook signature | Do not repeat (check the secret) |
| 404 Not Found | Endpoint does not exist | Do not repeat (fix URL) |
| 429 Too Many Requests | The rate limit has been exceeded | Repeat after the specified time |
| 500 Internal Server Error | There is an error on your server. | Repeat with a delay |
| 503 Service Unavailable | The service is temporarily unavailable. | Repeat with a delay |
| 504 Gateway Timeout | Processing timeout exceeded | Repeat with a delay |
Retry strategy
When a webhook fails to deliver (5xx errors or timeout), the sender must try again. The standard strategy is exponential backoff.
Exponential backoff - exponential delay:
| Attempt | Delay | Total time |
|---|---|---|
| 1 (primary) | Immediately | 0 sec |
| 2 | 5 seconds | 5 sec |
| 3 | 30 seconds | 35 sec |
| 4 | 2 minutes | 2 minutes 35 seconds |
| 5 | 10 minutes | 12 minutes 35 seconds |
| 6 | 1 hour | 1 hour 12 minutes |
Why exponential backoff is effective:
- Fast retries for short-term failures (server restart)
- Увеличивающиеся интервалы для долгих проблем (не перегружаем сломанный сервер)
- Баланс между скоростью восстановления и нагрузкой
Реализация собственного retry механизма
Если вы отправляете webhooks (не только получаете), реализуйте retry логику:
Пример retry с exponential backoff (Node.js):
async function sendWebhookWithRetry(url, payload, maxRetries = 5) { const delays = [0, 5000, 30000, 120000, 600000]; // миллисекунды for (let attempt = 0; attempt<= maxRetries; attempt++) { try { const response = await fetch(url, { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-Webhook-Signature': generateSignature(payload) }, body: JSON.stringify(payload), timeout: 10000 // 10 секунд таймаут }); // Успешная доставка if (response.status > = 200 && response.status< 300) { console.log('Webhook delivered successfully'); return { success: true, attempt }; } // Ошибка клиента (4xx) - не повторяем if (response.status > = 400 && response.status< 500) { console.error('Client error, not retrying:', response.status); return { success: false, error: 'client_error', status: response.status }; } // Ошибка сервера (5xx) - повторяем console.warn(`Server error ${response.status}, attempt ${attempt + 1}`); } catch (error) { console.error(`Network error, attempt ${attempt + 1}:`, error.message); } // Если не последняя попытка, ждем перед следующей if (attempt < maxRetries) { const delay = delays[attempt + 1]; console.log(`Waiting ${delay}ms before retry...`); await new Promise(resolve => setTimeout(resolve, delay)); } } // Все попытки исчерпаны console.error('Failed to deliver webhook after all retries'); await saveToFailedQueue(url, payload); return{ success: false, error: 'max_retries_exceeded' }; }Dead Letter Queue (очередь неудачных webhook)
Когда все попытки доставки исчерпаны, webhook не должен просто исчезнуть. Сохраните его в отдельную очередь для ручной обработки.
Что делать с неудачными webhooks:
- Logging — сохраните полную информацию (payload, ошибки, попытки)
- Notifications — отправьте alert администратору
- Dashboard — покажите список неудачных webhooks в админ-панели
- Ручная повторная отправка — кнопка для повторной попытки
- Массовая обработка — инструмент для переотправки пакета webhooks
Мониторинг webhook доставки
Ключевые метрики:
- Success rate — процент успешно доставленных webhooks (цель: >99%)
- Average delivery time — среднее время доставки (цель:<2 сек)
- Retry rate — процент webhooks, требующих повтора (цель:<5%)
- Failed webhooks — количество окончательно неудачных (цель: 0)
- Response times — время ответа получателя
Обработка дубликатов
Из-за retry возможны дублирующиеся webhooks. Ваша система должна быть идемпотентной.
Стратегия идемпотентности:
// Проверка дубликата перед обработкой async function processWebhook(payload) { const eventId = payload.id; // Проверяем, не обработан ли уже этот event const processed = await db.query( 'SELECT id FROM processed_webhooks WHERE event_id =?', [eventId] ); if (processed.length > 0) { console.log('Duplicate webhook detected:', eventId); return{ status: 'already_processed' }; } // Обработка в транзакции await db.transaction(async (trx) => { // Обновляем данные await trx('products').where('sku', payload.data.product.sku).update({ price: payload.data.product.new_price } ); // Сохраняем ID обработанного события await trx('processed_webhooks').insert({ event_id: eventId, event_type: payload.event, processed_at: new Date() } ); }); return{ status: 'success' }; }Важно: Быстрый ответ
Не выполняйте длительные операции перед возвратом HTTP 200. Отправитель webhook ждет ответ максимум 10-30 секунд. Используйте паттерн: быстро возвращаете 200 OK, затем обрабатываете асинхронно в очереди задач.
Тестирование и отладка webhook
Тестирование webhook — это особая задача, потому что вы не можете просто "запустить" webhook. Вам нужны инструменты для имитации входящих запросов и проверки обработки.
Тестирование на локальном компьютере с ngrok
Главная проблема разработки webhook — поставщик не может отправить запрос на ваш localhost. Решение — ngrok, который создает публичный туннель к вашей локальной машине.
Установка и использование ngrok:
# Установка ngrok # Windows: скачайте с https://ngrok.com/download # macOS: brew install ngrok # Linux: snap install ngrok # Запуск туннеля к локальному серверу на порту 3000 ngrok http 3000 # Результат: Forwarding: https://abc123.ngrok.io -> http://localhost:3000 # Теперь используйте https://abc123.ngrok.io/api/webhooks/price-updates # как webhook URL у поставщикаАльтернативы ngrok:
- localtunnel — бесплатная альтернатива с открытым кодом
- serveo — SSH-based туннель без установки
- localhost.run — простой SSH туннель
Инструменты для инспекции webhook
1. Webhook.site
Бесплатный сервис для просмотра входящих webhook без написания кода.
- Go to webhook.site
- Получите уникальный URL
- Используйте его при регистрации webhook у поставщика
- Просматривайте все входящие запросы в реальном времени
2. RequestBin
Похожий сервис для сбора и инспекции HTTP-запросов.
3. Postman
Мощный инструмент для тестирования API, поддерживает mock servers для имитации webhook.
Ручное тестирование с curl
Для быстрых тестов используйте curl для отправки тестовых webhook:
Примеры curl-запросов:
# Тест изменения цены curl -X POST https://your-shop.com/api/webhooks/price-updates \ -H "Content-Type: application/json" \ -H "X-Webhook-Signature: sha256=test_sig" \ -d '{ "id": "evt_test_001", "event": "price.updated", "timestamp": "2025-01-15T14:30:00Z", "data": { "product":{ "sku": "TEST-SKU", "old_price": 100.00, "new_price": 90.00, "currency": "USD" } } }' # Тест обновления остатков curl -X POST https://your-shop.com/api/webhooks/price-updates \ -H "Content-Type: application/json" \ -H "X-Webhook-Signature: sha256=test_sig" \ -d '{ "id": "evt_test_002", "event": "stock.changed", "timestamp": "2025-01-15T14:35:00Z", "data": { "product":{ "sku": "TEST-SKU", "old_quantity": 50, "new_quantity": 25 } } }'Automated testing
Напишите юнит-тесты для обработчиков webhook:
Пример теста (Jest + Supertest):
const request = require('supertest'); const app = require('../app'); const db = require('../database'); describe('Webhook Handler', () => { beforeEach(async () => { await db.clearTestData(); }); test('should update price on price.updated webhook', async () => { const payload = { id: 'evt_test_001', event: 'price.updated', timestamp: new Date().toISOString(), data: { product:{ sku: 'TEST-SKU', old_price: 100.00, new_price: 90.00, currency: 'USD' } } }; const response = await request(app).post('/api/webhooks/price-updates').send(payload).set('X-Webhook-Signature', generateTestSignature(payload)); expect(response.status).toBe(200); expect(response.body.status).toBe('success'); // Проверяем, что цена обновилась в БД const product = await db.getProduct('TEST-SKU'); expect(product.price).toBe(90.00); }); test('should reject webhook with invalid signature', async () => { const payload = { /*... */ }; const response = await request(app).post('/api/webhooks/price-updates').send(payload).set('X-Webhook-Signature', 'invalid_signature'); expect(response.status).toBe(401); }); test('should handle duplicate webhooks idempotently', async () => { const payload = { /*... */ }; // Первый запрос await request(app).post('/api/webhooks/price-updates').send(payload).set('X-Webhook-Signature', generateTestSignature(payload)); // Повторный запрос с тем же ID const response = await request(app).post('/api/webhooks/price-updates').send(payload).set('X-Webhook-Signature', generateTestSignature(payload)); expect(response.status).toBe(200); expect(response.body.status).toBe('already_processed'); }); });Отладка проблем с webhook
Чеклист для диагностики проблем:
- Webhook не приходит:
- Проверьте URL — правильный ли домен и путь
- Убедитесь, что используется HTTPS
- Проверьте firewall — не блокирует ли запросы
- Посмотрите логи у поставщика — отправлялся ли webhook
- Webhook приходит, но отклоняется:
- Проверьте signature verification
- Убедитесь, что secret key правильный
- Проверьте формат подписи (sha256=... или просто хеш)
- Webhook обрабатывается, но данные не обновляются:
- Проверьте парсинг payload — правильно ли извлекаются данные
- Убедитесь, что SKU совпадает с тем, что в базе
- Проверьте транзакции БД — не откатываются ли они
- Webhook обрабатывается медленно:
- Используйте асинхронную обработку
- Оптимизируйте запросы к БД
- Добавьте индексы на часто используемые поля
Логирование для отладки
Структурированное логирование webhook:
const winston = require('winston'); const logger = winston.createLogger({ format: winston.format.json(), transports: [ new winston.transports.File({ filename: 'webhooks.log' } ) ] }); app.post('/api/webhooks/price-updates', async (req, res) => { const startTime = Date.now(); logger.info('Webhook received',{ event_id: req.body.id, event_type: req.body.event, ip: req.ip, timestamp: new Date().toISOString() } ); try { // Обработка... logger.info('Webhook processed successfully',{ event_id: req.body.id, processing_time_ms: Date.now() - startTime } ); res.status(200).json({ status: 'success' } ); } catch (error) { logger.error('Webhook processing failed',{ event_id: req.body.id, error: error.message, stack: error.stack, processing_time_ms: Date.now() - startTime } ); res.status(500).json({ error: 'Internal server error' } ); } });Совет: Mock данные для тестирования
Создайте набор тестовых payload для всех типов событий и храните их в репозитории. Это позволит быстро тестировать изменения без необходимости ждать реальных событий от поставщика.
Популярные платформы с поддержкой webhook
Многие современные платформы поставщиков и сервисов предоставляют webhook для уведомлений об изменениях данных. Рассмотрим наиболее популярные решения.
E-commerce платформы
Shopify
Мощная система webhook для интеграции с интернет-магазинами:
- Поддерживаемые события: orders/create, products/update, inventory_levels/update
- Format: JSON payload через HTTPS
- Safety: HMAC-SHA256 подпись в заголовке X-Shopify-Hmac-SHA256
- Restrictions: максимум 10,000 webhooks на магазин
WooCommerce
WordPress-платформа с расширениями для webhook:
- Требует плагина (WooCommerce Webhooks, Zapier)
- События: product.created, product.updated, order.created
- Настройка через админ-панель
Платформы автоматизации
Zapier
Платформа интеграции, поддерживающая webhook для 5000+ сервисов:
- Webhooks by Zapier — прием входящих webhook
- Webhook Actions — отправка webhook при событиях
- Advantages: no-code интеграция, визуальный интерфейс
- Price: от $19.99/месяц
Make (ранее Integromat)
Альтернатива Zapier с мощными возможностями:
- Визуальное построение сценариев
- Custom webhooks для любых сервисов
- Обработка JSON, XML, form data
API-first платформы
Stripe
Платежная система с лучшей в индустрии реализацией webhook:
- 200+ типов событий (payment.succeeded, subscription.updated)
- Автоматический retry с exponential backoff
- Dashboard для мониторинга доставки webhook
- Тестовый режим для разработки
Twilio
Коммуникационная платформа с webhook для SMS, звонков:
- StatusCallback webhooks для отслеживания доставки сообщений
- Поддержка GET и POST запросов
- Гибкая настройка параметров
Специализированные платформы для прайсов
Elbuz
Платформа автоматизации работы с прайс-листами с продвинутой поддержкой webhook:
- Events: price.changed, stock.updated, product.added, supplier.updated
- Filtration: webhook только для определенных поставщиков или категорий
- Transformation: автоматическое преобразование данных перед отправкой
- Monitoring: dashboard с статистикой доставки
- Integration: готовые коннекторы к популярным CMS
Узнайте больше об автоматической обработке прайсов с webhook-уведомлениями.
Сравнение webhook-реализаций
| Platform | Event types | Retry | Monitoring | Difficulty of setup |
|---|---|---|---|---|
| Shopify | 50+ | Да (48 часов) | Yes | Low |
| WooCommerce | 10+ | Зависит от плагина | Limited | Average |
| Stripe | 200+ | Да (72 часа) | Great | Low |
| Zapier | Custom | Yes | Yes | Very low |
| Elbuz | Прайсы (15+) | Да (7 дней) | Yes | Low |
Выбор платформы для ваших нужд
Критерии выбора:
- Для простых задач: Zapier или Make — no-code решение
- Для e-commerce: встроенные webhook CMS (Shopify, WooCommerce)
- Для прайс-листов: специализированные платформы (Elbuz)
- Для кастомных интеграций: собственная разработка с использованием фреймворков
FAQ: Часто задаваемые вопросы о webhook
В чем разница между webhook и REST API?
REST API — это когда ваша система делает запрос к другой системе для получения данных (pull-модель). Вы спрашиваете "есть ли обновления?"
Webhook — это когда другая система сама отправляет данные вашей системе при возникновении события (push-модель). Вам сообщают "вот обновление!"
Analogy: API — это когда вы звоните в ресторан спрашивать "готов ли заказ?". Webhook — это когда ресторан сам звонит вам, когда заказ готов.
Что делать, если webhook приходит дважды с одинаковыми данными?
Это нормальная ситуация, связанная с retry-механизмом. Решение — реализовать идемпотентность:
- Сохраняйте ID каждого обработанного события
- Перед обработкой проверяйте, не был ли уже обработан этот ID
- Если был — пропускайте обработку, но возвращайте HTTP 200 OK
- Используйте Redis или БД для хранения обработанных ID (храните 24-48 часов)
Как обезопасить webhook от поддельных запросов?
Используйте многоуровневую защиту:
- HTTPS обязательно — защита от перехвата данных
- HMAC-подпись — проверяйте подпись каждого запроса
- IP whitelist — разрешайте запросы только с IP поставщика
- Timestamp validation — отклоняйте слишком старые запросы (>5 минут)
- Rate limiting — ограничивайте количество запросов
Можно ли использовать webhook на shared hosting?
Да, но с ограничениями:
- HTTPS должен поддерживаться — обязательно для webhook
- Время выполнения скриптов — многие shared хостинги ограничивают 30-60 секундами (используйте асинхронную обработку)
- Resources — при большом потоке webhook может не хватить лимитов
- Recommendation: для production используйте VPS или cloud (AWS, DigitalOcean)
Что делать, если поставщик не предоставляет webhook?
Есть несколько альтернатив:
- Polling — периодически проверяйте изменения через API
- Мониторинг файлов — отслеживайте изменение даты модификации прайс-листа на FTP
- Email parsing — если поставщик присылает прайсы на почту, автоматически обрабатывайте письма
- Intermediary — используйте платформу типа Zapier, которая преобразует polling в webhook
- Запросите у поставщика — современные системы должны поддерживать webhook
Conclusion
Webhook — это современный стандарт для получения мгновенных уведомлений об изменениях данных. Переход с традиционного polling на webhook позволяет получать обновления цен и остатков в считанные секунды вместо часов, снижая нагрузку на инфраструктуру и обеспечивая актуальность данных в режиме реального времени.
Key findings
- Webhook vs Polling: мгновенные уведомления эффективнее периодических проверок. Средняя задержка сокращается с 30 минут до 3 секунд.
- Безопасность критична: всегда используйте HTTPS и проверяйте HMAC-подпись каждого webhook. Без этого ваша система уязвима.
- Идемпотентность обязательна: webhook может прийти дважды из-за retry. Сохраняйте ID обработанных событий.
- Быстрый ответ важен: возвращайте HTTP 200 OK за 5-10 секунд. Длительную обработку выполняйте асинхронно.
- Обработка ошибок: правильные HTTP коды и retry-механизм обеспечивают надежность доставки.
- Тестирование перед production: используйте ngrok для локальной разработки, webhook.site для инспекции.
Этапы внедрения webhook
- Создайте webhook endpoint — защищенный HTTPS URL для приема уведомлений
- Реализуйте проверку подписи — HMAC-верификация для безопасности
- Зарегистрируйте webhook у поставщика — укажите URL и выберите типы событий
- Протестируйте на staging — убедитесь, что все работает корректно
- Настройте мониторинг — отслеживайте успешность доставки и обработки
- Запустите в production — начните получать реальные уведомления
- Оптимизируйте — анализируйте метрики и улучшайте производительность
ROI от внедрения webhook
Компании, внедрившие webhook для синхронизации прайсов, отмечают:
- Актуальность данных: задержка обновлений сокращается с часов до секунд
- Снижение нагрузки: на 85-95% меньше API-запросов по сравнению с polling
- Рост конверсии: на 12-18% благодаря всегда актуальным ценам и остаткам
- Экономия ресурсов: снижение нагрузки на сервер на 70-80%
- Конкурентное преимущество: возможность мгновенно реагировать на изменения рынка
Additional materials
Для полного понимания управления данными о прайсах рекомендуем ознакомиться с дополнительными материалами:
- Полное руководство по импорту и синхронизации прайс-листов — основы управления данными
- Как настроить автоматическую синхронизацию цен и остатков с сайтом — практические методы синхронизации
- Работа с популярными форматами прайс-листов — понимание структуры данных
Готовы внедрить webhook для мгновенного обновления прайсов?
Platform Elbuz предоставляет готовую инфраструктуру webhook с поддержкой всех типов событий, автоматическим retry, мониторингом доставки и интеграцией с популярными CMS. Получайте мгновенные уведомления об изменениях цен, остатков и новых товаров без написания кода.
Начните с бесплатного trial и убедитесь, насколько эффективнее работает ваш бизнес с webhook-уведомлениями в реальном времени.
- Webhook vs. Polling: Why Instant Notifications Are More Effective
- How Webhooks Work: A Simple Explainer
- Step-by-step guide to setting up a webhook
- Webhook Payload Structure: JSON Examples
- Webhook Security: Signature Verification and HTTPS
- Error handling and retry mechanism
- Тестирование и отладка webhook
- Популярные платформы с поддержкой webhook
- FAQ: Часто задаваемые вопросы о webhook
- Conclusion
Save a link to this article
Elbuz Team
Copywriter ElbuzWe build Elbuz, an e-commerce automation platform: price list imports, product matching, pricing rules, and marketplace exports. Our guides are written from the product's source code: the developer who built a feature drafts the article, and a separate reviewer checks every claim against the code. We write about the software we design and maintain ourselves.
Discussion of the topic – Webhook for price list updates: how to receive instant notifications about changes
Webhook for price list updates: how to receive instant notifications about changes
There are no reviews for this product.



Write a comment
Your email address will not be published. Required fields are checked *