Перейти до вмісту

Надійне приймання вебхуків Stripe

Цей гайд ставить Railhook між Stripe і вашим застосунком. Stripe надсилає вебхуки на джерело Railhook, яке перевіряє підпис, зберігає кожну подію в тому вигляді, в якому вона надійшла, і пересилає її на ваш сервіс. Коли ваш сервіс недоступний, нічого не губиться: пересилання повторюються, а те, що все одно не вдалося, можна відтворити пізніше.

Чому самих повторів Stripe недостатньо

Section titled “Чому самих повторів Stripe недостатньо”

Stripe повторює спроби. У live-режимі він пробує доставити невдалу подію до трьох днів з експоненційною затримкою; у пісочниці — тричі за кілька годин. Після цього Dashboard може повторно надіслати подію протягом 15 днів, а Stripe CLI — протягом 30. Stripe також зазначає, що події можуть надходити не по порядку і що ендпоінт може отримати ту саму подію більше одного разу. (Stripe: Receive Stripe events in your webhook endpoint)

Що це залишає на вас:

  • Ваш обробник має відповідати швидко. Stripe просить повернути 2xx до будь-якої складної логіки, інакше доставка сплине за таймаутом і вважатиметься невдалою. Railhook відповідає Stripe, щойно подію збережено, а ваш сервіс може працювати стільки, скільки дозволяє таймаут призначення.
  • Відновлення — по одній події. Після довшого збою повторне надсилання з Dashboard означає клацати подію за подією. Railhook відтворює всі збережені події за проміжок часу одним викликом.
  • Дублікати доходять до вашого коду. Railhook розпізнає ідентифікатор evt_…: на повторну доставку тієї самої події він відповідає 202 зі збереженою копією й не пересилає її вдруге.

Знадобляться проєкт Railhook і API-ключ. Усе нижче також можна зробити в розділі Вхідні панелі керування.

Terminal window
export RAILHOOK_URL=https://railhook.io # or your own instance
export RAILHOOK_API_KEY=...
export PROJECT_ID=...
  1. Створіть джерело. Stripe показує секрет підпису лише після реєстрації адреси, тож спершу створіть джерело без секрету. З verificationMode зі значенням PROVIDER і без секрету воно відхиляє кожен запит із 401, доки ви його не додасте, тож тим часом нічого неперевіреного не зберігається.

    Terminal window
    curl -X POST "$RAILHOOK_URL/api/v1/projects/$PROJECT_ID/incoming-sources" \
    -H "X-API-Key: $RAILHOOK_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{"name":"Stripe","providerType":"STRIPE","verificationMode":"PROVIDER"}'

    Збережіть id і ingressUrl із відповіді.

  2. Зареєструйте адресу в Stripe. У Workbench відкрийте Webhooks і натисніть Create an event destination. Оберіть Your account, позначте типи подій, які обробляєте, оберіть Webhook endpoint і вставте ingressUrl як Endpoint URL.

  3. Передайте Railhook секрет підпису. На сторінці ендпоінта в Stripe натисніть Reveal secret і скопіюйте значення, що починається з whsec_. Задайте його джерелу:

    Terminal window
    curl -X PUT "$RAILHOOK_URL/api/v1/projects/$PROJECT_ID/incoming-sources/$SOURCE_ID" \
    -H "X-API-Key: $RAILHOOK_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{"name":"Stripe","hmacSecret":"whsec_..."}'

    Змінюються лише надіслані поля; секрет лише для запису, API його ніколи не повертає.

  4. Додайте призначення. Це адреса вашого сервісу, який має отримувати події:

    Terminal window
    curl -X POST "$RAILHOOK_URL/api/v1/projects/$PROJECT_ID/incoming-sources/$SOURCE_ID/destinations" \
    -H "X-API-Key: $RAILHOOK_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{"url":"https://api.example.com/webhooks/stripe","authType":"BEARER","authConfig":"{\"token\":\"...\"}","enabled":true}'
  5. Надішліть тестову подію зі Stripe або виконайте stripe trigger payment_intent.succeeded. Вона з’явиться в розділі Вхідні → Отримані, з одним пересиланням на кожне призначення.

Як перевіряється підпис

Section titled “Як перевіряється підпис”

Railhook читає Stripe-Signature, обчислює шістнадцятковий HMAC-SHA256 від <t>.<raw body> із секретом whsec_ і порівнює його з кожним значенням v1. t має бути в межах 300 секунд від годинника Railhook. Поки ви змінюєте секрет у Stripe, він надсилає по одному v1 на кожен активний секрет; запит проходить перевірку, якщо збігається будь-який із них, тож задайте джерелу новий секрет одразу після зміни. Запит, що не пройшов перевірку, отримує 401 і не зберігається, а Stripe його повторює.

Тіло точно таке, яким його надіслав Stripe, байт у байт, з його Content-Type. Stripe-Signature не пересилається: ваш сервіс автентифікує Railhook за обліковими даними призначення, тож секрет Stripe йому взагалі не потрібен. Кожен запит містить Idempotency-Key, незмінний між спробами, і X-Forward-Attempt. Див. Призначення.

Пересилання повторюється на 408, 429, будь-який 5xx, таймаут чи помилку з’єднання — до 5 спроб. Будь-який інший 4xx одразу переносить його в «Невдалі пересилання», звідки його можна повторити, виправивши сервіс.

Спрямуйте призначення на свою машину через тунель, і тестові події Stripe дійдуть до коду у вашому редакторі вже після перевірки в Railhook.

  1. Встановіть CLI й увійдіть, як описано в CLI, а потім відкрийте тунель до порту вашого застосунку:

    Terminal window
    railhook listen 3000
  2. Додайте джерелу друге призначення з виведеною публічною адресою й вашим маршрутом у кінці, наприклад https://<host>/tunnel/<slug>/webhooks/stripe. Шлях після адреси тунелю зберігається, тож запит потрапить на http://localhost:3000/webhooks/stripe.

  3. Згенеруйте подію в пісочниці Stripe. Коли закриєте тунель, вимкніть або видаліть це призначення, щоб його пересилання не накопичувалися в «Невдалих пересиланнях».

Повтор подій після збою

Section titled “Повтор подій після збою”

Якщо ваш сервіс лежав довше, ніж тривали повтори, відтворіть те, що надійшло за цей час. Це створює нові пересилання на кожне призначення джерела, знову зі спроби 1:

Terminal window
curl -X POST "$RAILHOOK_URL/api/v1/projects/$PROJECT_ID/incoming-events/bulk-replay" \
-H "X-API-Key: $RAILHOOK_API_KEY" \
-H "Content-Type: application/json" \
-d '{"sourceId":"'"$SOURCE_ID"'","from":"2026-09-18T10:00:00Z","to":"2026-09-18T14:00:00Z","verified":true}'

Обробник усе одно має бути ідемпотентним за ідентифікатором події Stripe, бо повтор надсилає й ті події, які ваш сервіс, можливо, вже обробив. Повтор сягає так далеко, як довго зберігаються події: 7 днів у Railhook Cloud і скільки налаштуєте на власному сервері. Див. Повтор.