Як тестувати вебхуки 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а: вебхук магазину

  1. В адмінці Shopify відкрийте Settings → Notifications і перейдіть до розділу Webhooks.
  2. Натисніть Create webhook.
  3. Виберіть подію, наприклад Order creation, формат (JSON) і версію API.
  4. Вставте адресу перехоплювача і збережіть.

Потім оформіть тестове замовлення або змініть товар. Доставка з’явиться в інспекторі наживо.

Крок 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 для вебхуків

Інші гайди

Localhost

Як тестувати вебхуки локально

Чому Stripe, GitHub та інші сервіси не бачать ваш localhost і як зловити справжній вебхук на публічній адресі, а потім переслати його собі на машину.

GitHub

Як тестувати вебхуки GitHub

Налаштовуємо вебхук репозиторію, розбираємо заголовки GitHub, правильно перевіряємо X-Hub-Signature-256 і повторно доставляємо події під час налагодження.

MCP

Тестування вебхуків із Claude і ChatGPT через MCP

Підключіть Webhook Inspector як MCP-сервер, і AI-асистент сам створить URL, дочекається вебхука й розбере його разом із вами.

Slack

Як тестувати Slack Events API та interactivity

Дивимося, що Slack надсилає на Request URL, проходимо перевірку url_verification, валідуємо X-Slack-Signature і розкодовуємо form-encoded payload від interactivity.

Stripe

Як тестувати вебхуки Stripe

Налаштовуємо ендпоінт у Stripe, дивимося, що саме приходить, перевіряємо Stripe-Signature на Node.js і Python та пересилаємо події на локальний застосунок.

Telegram

Як тестувати вебхук Telegram-бота

Спрямовуємо бота на публічну адресу через setWebhook, роздивляємося сирі апдейти від Telegram і пересилаємо їх боту, що працює на вашій машині.

Twilio

Як тестувати вебхуки Twilio для SMS і дзвінків

Спрямовуємо номер Twilio на адресу-перехоплювач, читаємо form-encoded параметри, відповідаємо TwiML без власного сервера і перевіряємо X-Twilio-Signature через офіційні бібліотеки.