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

Як надійно отримувати вебхуки Stripe

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

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

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

У live-режимі Stripe до трьох днів повторює невдалу подію з експоненційною затримкою; у пісочниці тричі за кілька годин. З Dashboard подію можна надіслати повторно протягом 15 днів, через Stripe CLI протягом 30. Події можуть надходити не по порядку і більше одного разу. (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 показує секрет підпису лише після того, як ви зареєструєте URL, тож спершу створіть джерело без секрету. Із 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. Зареєструйте URL у 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. Додайте призначення, URL вашого сервісу:

    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> у hex із секретом whsec_ і порівнює результат із кожним значенням v1. t має відрізнятися від часу на годиннику Railhook не більш ніж на 300 секунд. Поки ви ротуєте секрет у Stripe, той надсилає по одному v1 на кожен активний секрет; запит проходить перевірку, якщо збігається будь-який із них, тож оновіть секрет у джерелі одразу після ротації. На запит, що не пройшов перевірку, Railhook відповідає 401 і не зберігає його, а Stripe повторює спробу.

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

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

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

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

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

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

Відтворення після збою

Section titled “Відтворення після збою”

Якщо ваш сервіс лежав довше, ніж тривали повторні спроби, відтворіть те, що надійшло за цей час. Railhook створить нові пересилання на кожне призначення джерела, кожне зі спроби 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 і скільки налаштуєте на власному сервері. Див. Відтворення.