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

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

Оновлено:

Ви пишете обробник вебхуків на http://localhost:3000, а Stripe, GitHub чи Telegram вимагають публічну HTTPS-адресу. Розберімо, чому так, які є способи це обійти, і як працювати у два кроки: спершу зловити й роздивитися справжній запит, а тоді переслати його на локальний сервер.

Чому сервіс не може достукатися до localhost

localhost означає «ця сама машина». Коли сервер провайдера надсилає запит на http://localhost:3000/webhook, він стукає сам до себе, а не до вас. До того ж ваш ноутбук зазвичай сидить за NAT і файрволом, тож публічної адреси в нього немає. А більшість провайдерів ще й приймають лише HTTPS з валідним сертифікатом.

Отже, потрібні три речі:

  1. Публічне доменне ім’я.
  2. HTTPS із довіреним сертифікатом.
  3. Спосіб доставити кожен запит із цієї адреси на ваш локальний порт.

Які є варіанти

Підхід Як працює Коли зручно
Тунель (ngrok, cloudflared тощо) Клієнт на вашій машині тримає з’єднання з публічним сервером, який проксіює трафік на ваш порт Коли локальний застосунок має бути доступний довго
CLI провайдера (наприклад, stripe listen) Провайдер сам стрімить події на локальний слухач Якщо працюєте з одним сервісом і в нього такий CLI є
Webhook Inspector Публічна адреса, що зберігає кожен запит, плюс пересилання на localhost через вкладку браузера або CLI-агент Коли хочеться спершу побачити сирий запит, а потім повторити чи переслати його

Тунель шле трафік одразу в застосунок: якщо обробник упав або повернув не той статус, запит пропав, хіба що провайдер повторить його сам. Адреса-перехоплювач зберігає кожен запит, тож його можна роздивитися, виправити код і надіслати ще раз.

Крок 1: зловіть справжній запит

  1. Відкрийте онлайн-інспектор вебхуків. Реєстрація не потрібна. Ви отримаєте унікальну адресу на кшталт https://webhook.voronyuk.com/abcd23efgh/stripe, де abcd23efgh — випадковий хеш із 10 символів, а stripe — назва, яку ви обираєте самі (або випадкова).
  2. Вставте цю адресу в налаштування вебхуків провайдера. Будь-який підшлях і query-параметри після неї теж ловляться, тобто https://webhook.voronyuk.com/abcd23efgh/stripe/orders?x=1 теж працює.
  3. Згенеруйте подію в сервісі або надішліть запит самі:
curl -X POST https://webhook.voronyuk.com/abcd23efgh/stripe/orders?x=1 \
  -H "Content-Type: application/json" \
  -d '{"event":"order.created","id":42}'

Запит з’являється одразу, без оновлення сторінки: метод, шлях, query, заголовки, тіло (JSON красиво відформатований, form data розкодовані, бінарні дані показано в base64), розмір і IP клієнта. За замовчуванням адреса відповідає 200 з тілом {"ok":true,"request_id":N}.

Саме тут видно, що провайдер насправді надсилає: точні заголовки, формат підпису, JSON у тілі чи form-urlencoded. Можна шукати за шляхом, заголовками й тілом, фільтрувати за методом, копіювати будь-який запит як curl або експортувати все в JSON чи HAR.

Крок 2: перешліть запит на localhost

Коли вже зрозуміло, що приходить, віддайте запит своєму коду. У панелі Пересилання є три режими.

Relay через браузер

Поки вкладка інструмента відкрита, вона пересилає кожен запит на ціль на кшталт http://localhost:3000. Запит іде з браузера, тому локальний сервер має дозволяти CORS. Встановлювати нічого не треба.

CLI-агент

CLI-агент працює без браузера, сам перепідключається і доганяє запити, які пропустив, поки був офлайн. Готову команду з токеном скопіюйте з панелі Пересилання:

WI_TOKEN='<токен>' inspector listen https://webhook.voronyuk.com/abcd23efgh/stripe --to localhost:3000

Пересилання з сервера

Якщо ціль публічна, скажімо staging-сервер, запити може пересилати сам сервер. Приватні адреси й localhost заблоковано з міркувань безпеки. Обмеження: до 60 пересилань на хвилину для однієї адреси, тайм-аут 5 секунд, редиректи не виконуються.

Що бачить відправник

Пересилання одностороннє. Застосунок отримує кожен запит, але сервіс-відправник завжди бачить відповідь самого інспектора — стандартну 200 або налаштовану вами, — а не відповідь застосунку. Для сервісів, яким досить 2xx (Stripe, GitHub, Shopify), цього вистачає. Якщо ж сервіс чекає відповідь застосунку в HTTP-відповіді (як-от challenge у url_verification від Slack), дайте йому публічну адресу самого застосунку.

Як зіставляються шляхи

Підшлях і query перехопленого запиту дописуються до цілі. Якщо ціль http://localhost:3000:

https://webhook.voronyuk.com/abcd23efgh/stripe/orders?x=1
→ http://localhost:3000/orders?x=1

Тож якщо обробник висить на /webhook, реєструйте в провайдера https://webhook.voronyuk.com/abcd23efgh/stripe/webhook.

Крок 3: виправте й повторіть

Коли обробник падає, нову подію генерувати не обов’язково. У інструменті для перехоплення вебхуків будь-який запит можна повторити з браузера (працює й для localhost) або з сервера (лише для публічних адрес). Виправили код, повторили запит, і так по колу.

Кілька практичних порад:

  • Для перевірки підпису потрібне сире тіло. Більшість провайдерів підписують саме ті байти, які надсилають. Перевіряйте підпис на сирому тілі, а не на JSON, який ви вже розпарсили й серіалізували назад.
  • Відповідайте швидко. Провайдери довго не чекають, деякі лише кілька секунд. Спершу поверніть 2xx, важку роботу робіть потім.
  • Підставляйте власні відповіді. Для кожної адреси можна задати статус (200–599), заголовки, тіло до 64 КБ і затримку до 30 секунд. Так зручно перевіряти, як провайдер реагує на помилки й тайм-аути.

Обмеження

  • До 10 адрес на сесію і до 1000 збережених запитів на адресу (найстаріші видаляються).
  • Тіло зберігається до 1 МБ. Одна адреса приймає до 500 запитів на хвилину.
  • Запити зберігаються 72 години.
  • Звичайний http:// перенаправляється на HTTPS (GET — 301, інші методи — 308).
  • Сесія — це cookie, а не акаунт. Кнопка Session link відкриває ті самі адреси в іншому браузері. Перехоплені запити бачить лише власник сесії.

Покрокові інструкції для конкретних сервісів: вебхуки Stripe, вебхуки GitHub і вебхук Telegram-бота.

Часті питання

Як отримувати вебхуки на localhost без ngrok?

Підійде будь-яка схема, що дає публічну HTTPS-адресу і шлях до вашої машини. У Webhook Inspector запити ловляться на публічній адресі й пересилаються на localhost через relay у браузері або CLI-агент, без налаштування тунелю.

Чому мій локальний ендпоінт нічого не отримує?

Провайдер просто не бачить localhost на вашому комп’ютері. Зареєструйте публічну адресу, переконайтеся, що запит туди доходить, і вже потім пересилайте його локально.

Чи потрібен CORS для relay через браузер?

Так. Relay надсилає запити з вкладки браузера на локальний сервер, тож той має дозволяти cross-origin запити. Якщо не хочеться чіпати CORS, скористайтеся CLI-агентом.

Що буде із запитами, які прийшли, поки ноутбук був вимкнений?

Вони все одно перехоплюються і зберігаються 72 години. CLI-агент після перепідключення доганяє пропущені запити, а будь-який запит можна повторити вручну.

Чи приватна адреса для перехоплення?

Перехоплені запити бачить лише ваша сесія. Але надсилати запити на адресу може будь-хто, хто її знає, тож не світіть її і завжди перевіряйте підпис провайдера в обробнику.

Спробуйте зараз

Отримайте безкоштовний URL для вебхуків і дивіться, як приходять запити, — без реєстрації.

Отримати URL для вебхуків

Інші гайди

GitHub

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

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

MCP

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

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

Shopify

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

Створюємо вебхук магазину або підписку застосунку, розбираємо заголовки X-Shopify, перевіряємо X-Shopify-Hmac-Sha256 і враховуємо тайм-аути та повтори Shopify.

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 через офіційні бібліотеки.