Як тестувати вебхуки Shopify
Створюємо вебхук магазину або підписку застосунку, розбираємо заголовки X-Shopify, перевіряємо X-Shopify-Hmac-Sha256 і враховуємо тайм-аути та повтори Shopify.
Оновлено:
Вебхуки Shopify повідомляють ваш застосунок про нове замовлення, зміну товару чи видалення застосунку з магазину. Щоб обробник не губив події, треба знати структуру payload, заголовки, як рахується HMAC і наскільки суворо Shopify ставиться до часу відповіді. Розберемо все це, а справжні доставки спершу ловитимемо на публічну адресу.
Два способи створити вебхук у Shopify
| Вебхук магазину | Підписка застосунку | |
|---|---|---|
| Де | Адмінка Shopify: Settings → Notifications → Webhooks | Конфіг застосунку (shopify.app.toml) або Admin API |
| Для кого | Власники магазинів і розробники, що тестують один магазин | Застосунки, встановлені в магазини |
| Ключ підпису | Ключ, показаний у розділі вебхуків в адмінці | Client secret вашого застосунку |
В обох випадках приходить однаковий запит: POST із JSON-тілом (вебхуки магазину можуть бути ще й у XML) і набором заголовків X-Shopify-*.
Крок 1: створіть адресу для перехоплення
Відкрийте Webhook Inspector і створіть адресу, наприклад:
https://webhook.voronyuk.com/abcd23efgh/shopify/webhooks
За замовчуванням вона відповідає 200 з {"ok":true,"request_id":N}, і Shopify вважає доставку успішною.
Крок 2а: вебхук магазину
- В адмінці Shopify відкрийте Settings → Notifications і перейдіть до розділу Webhooks.
- Натисніть Create webhook.
- Виберіть подію, наприклад Order creation, формат (JSON) і версію API.
- Вставте адресу перехоплювача і збережіть.
Потім оформіть тестове замовлення або змініть товар. Доставка з’явиться в інспекторі наживо.
Крок 2б: підписка застосунку
Якщо застосунок зроблено через Shopify CLI, підписки описуються в shopify.app.toml:
[webhooks]
api_version = "2026-07"
[[webhooks.subscriptions]]
topics = ["orders/create", "products/update"]
uri = "https://webhook.voronyuk.com/abcd23efgh/shopify/webhooks"
Задеплойте конфіг, згенеруйте подію в dev-магазині й дивіться, як приходить запит. Популярні топіки: orders/create, orders/paid, products/update, customers/create, app/uninstalled.
Крок 3: розберіть заголовки
| Заголовок | Що означає |
|---|---|
X-Shopify-Topic |
Топік, наприклад orders/create |
X-Shopify-Hmac-Sha256 |
HMAC-SHA256 від сирого тіла в base64 |
X-Shopify-Shop-Domain |
Домен магазину на myshopify.com |
X-Shopify-Webhook-Id |
Унікальний для кожної доставки; за ним відсіюють дублікати |
X-Shopify-Event-Id |
Спільний для доставок, спричинених однією дією продавця |
X-Shopify-API-Version |
Версія API, якою серіалізовано payload |
X-Shopify-Triggered-At |
Коли Shopify ініціював доставку |
Назви заголовків нечутливі до регістру, тож не порівнюйте їх посимвольно. В інспекторі можна шукати по всіх заголовках, і так легко знайти всі доставки з певного магазину чи топіка.
Крок 4: перевірка X-Shopify-Hmac-Sha256
Shopify рахує HMAC-SHA256 від сирого тіла запиту, використовуючи секрет як ключ, і кодує результат у base64. Порахуйте те саме і порівняйте за сталий час.
Node.js
const crypto = require('crypto');
const express = require('express');
const SECRET = process.env.SHOPIFY_WEBHOOK_SECRET; // client secret застосунку
const app = express();
function verifyShopify(rawBody, hmacHeader) {
if (!hmacHeader) return false;
const digest = crypto.createHmac('sha256', SECRET).update(rawBody).digest();
const received = Buffer.from(hmacHeader, 'base64');
return digest.length === received.length && crypto.timingSafeEqual(digest, received);
}
app.post('/webhooks', express.raw({ type: 'application/json' }), (req, res) => {
if (!verifyShopify(req.body, req.get('X-Shopify-Hmac-Sha256'))) {
return res.sendStatus(401);
}
res.sendStatus(200); // підтверджуємо одразу
const topic = req.get('X-Shopify-Topic');
const payload = JSON.parse(req.body.toString('utf8'));
console.log(topic, req.get('X-Shopify-Webhook-Id'), payload.id);
});
app.listen(3000);
Python
import base64
import hashlib
import hmac
import os
from flask import Flask, abort, request
app = Flask(__name__)
SECRET = os.environ["SHOPIFY_WEBHOOK_SECRET"].encode()
@app.post("/webhooks")
def webhooks():
digest = hmac.new(SECRET, request.get_data(), hashlib.sha256).digest()
expected = base64.b64encode(digest).decode()
if not hmac.compare_digest(expected, request.headers.get("X-Shopify-Hmac-Sha256", "")):
abort(401)
print(request.headers.get("X-Shopify-Topic"), request.headers.get("X-Shopify-Webhook-Id"))
return "", 200
if __name__ == "__main__":
app.run(port=3000)
Якщо перевірка не проходить, гляньте, який секрет ви берете: підписки застосунку підписуються client secret застосунку, а вебхуки магазину — ключем, що показаний в адмінці.
Крок 5: пересилання на localhost
У панелі Пересилання вкажіть ціль http://localhost:3000. Підшлях дописується до цілі, тож .../abcd23efgh/shopify/webhooks прийде на http://localhost:3000/webhooks. Скористайтеся relay через браузер (сервер має дозволяти CORS) або CLI-агентом:
WI_TOKEN='<токен>' inspector listen https://webhook.voronyuk.com/abcd23efgh/shopify --to localhost:3000
Точну команду з токеном скопіюйте з панелі. Інші варіанти — у гайді як тестувати вебхуки локально.
Час відповіді й повтори
- 5 секунд. Shopify чекає відповіді не довше п’яти секунд, інакше доставка вважається невдалою. Перевірте підпис, поверніть
200, а обробку винесіть у фонову задачу. - Повтори. Невдалу доставку Shopify повторює до восьми разів протягом чотирьох годин, щоразу з більшим інтервалом.
- Видалення підписки. Якщо збої не припиняються, підписку можуть видалити, і після виправлення ендпоінта її доведеться створити заново.
- Дублікати. Через повтори одна доставка може прийти кілька разів. Відсіюйте їх за
X-Shopify-Webhook-Id.
Збої можна відрепетирувати без ризику: задайте для адреси власну відповідь 500 або затримку і подивіться, що буде. А коли обробник ламається, повторіть збережену доставку з тестера вебхуків Shopify, замість того щоб оформлювати ще одне тестове замовлення.
Схожі гайди: вебхуки Stripe і вебхуки Twilio.
Часті питання
Як тестувати вебхуки Shopify без публічного сервера?
Вкажіть адресу перехоплювача як адресу вебхука, роздивіться доставки і пересилайте їх на localhost через CLI-агент або relay у браузері.
Чому не проходить перевірка HMAC у Shopify?
Найчастіше тіло розпарсили до хешування. Беріть сирі байти, порівнюйте з base64-дайджестом і використовуйте правильний секрет для свого типу вебхука.
Скільки Shopify чекає на відповідь вебхука?
П’ять секунд. Повільніші відповіді вважаються невдалою доставкою.
Скільки разів Shopify повторює вебхук?
До восьми разів протягом чотирьох годин. Якщо збої тривають, підписку можуть видалити.
Як не обробити той самий вебхук Shopify двічі?
Зберігайте X-Shopify-Webhook-Id кожної обробленої доставки і пропускайте ID, які вже бачили.
Спробуйте зараз
Отримайте безкоштовний URL для вебхуків і дивіться, як приходять запити, — без реєстрації.
Отримати URL для вебхуків