Czym są webhooks w Stripe
Webhook to żądanie HTTP POST, które Stripe wysyła na podany przez Ciebie URL za każdym razem, gdy w Twoim koncie wydarzy się coś istotnego: płatność, zwrot, nowa subskrypcja, spór.
Webhook = „hej, właśnie coś się stało w Twoim koncie Stripe, oto dane tego zdarzenia w formacie JSON".
Zamiast co minutę odpytywać API Stripe „czy już ktoś zapłacił?" (polling), Stripe sam Cię powiadomi w momencie, gdy płatność się zakończy. To efektywniejsze, szybsze i bardziej niezawodne.
Jak wygląda webhook od Stripe
Każdy webhook zawiera obiekt Event z typem zdarzenia i pełnymi danymi. Przykładowa struktura:
{
"id": "evt_1PqR2sA0B3cD4eF5gH6iJ7k",
"type": "checkout.session.completed",
"data": {
"object": {
"id": "cs_live_...",
"amount_total": 9900,
"currency": "pln",
"customer_details": {
"name": "Jan Kowalski",
"email": "jan@firma.pl",
"tax_ids": [{ "type": "pl_vat", "value": "PL1234567890" }]
},
"metadata": { ... }
}
}
}Twój endpoint odbiera ten JSON, parsuje dane i wykonuje akcję, na przykład wystawia fakturę w programie księgowym.
Które zdarzenia Stripe nasłuchiwać do fakturowania
Stripe obsługuje ponad 200 typów zdarzeń. Do automatycznego fakturowania potrzebujesz dwóch:
checkout.session.completedOdpala się po udanej płatności jednorazowej przez Stripe Checkout. Zawiera pełne dane sesji: kwotę, walutę, dane kupującego (imię, e-mail, adres, NIP), opis produktu z line_items. To najczęściej używane zdarzenie do fakturowania.
Kiedy używać: płatności jednorazowe, Payment Links, Stripe Checkout w Twoim sklepie.
invoice.paidOdpala się, gdy Stripe pobierze płatność za subskrypcję (fakturę Stripe). Zawiera dane z obiektu Invoice: kwotę, walutę, dane klienta, pozycje subskrypcji. Odpala się cyklicznie, co miesiąc, kwartał lub rok, zależnie od interwału subskrypcji.
Kiedy używać: subskrypcje, płatności cykliczne, SaaS.
Zdarzenia, których NIE używać do fakturowania
charge.succeededzawiera mniej danych (brak line_items, ograniczone dane kupującego). Nie rekomendowany do fakturowaniapayment_intent.succeededinformuje o udanej płatności, ale nie zawiera kontekstu z Checkout Session (brak danych produktu, adresu)checkout.session.async_payment_succeededdotyczy opóźnionych metod płatności (np. SEPA). Ważne, ale bardziej niszowe
DIY, czyli własna integracja webhook → faktura
Jeśli chcesz samodzielnie zbudować integrację Stripe webhook → faktura w Fakturowni lub inFakt, oto co musisz zaimplementować:
- 1
Endpoint HTTP na Twoim serwerze
Serwer (Node.js, Python, PHP, Go) z endpointem POST, który przyjmuje webhooks od Stripe. Musi być publicznie dostępny przez HTTPS.
- 2
Weryfikacja podpisu Stripe-Signature
Każdy webhook od Stripe zawiera nagłówek
Stripe-Signaturez podpisem HMAC-SHA256. Musisz go weryfikować, żeby upewnić się, że żądanie naprawdę pochodzi od Stripe. Bez tego ktoś może wysłać fałszywy webhook na Twój endpoint. - 3
Idempotencja, czyli ochrona przed duplikatami
Stripe może wysłać ten sam webhook wielokrotnie (np. przy timeout). Musisz przechowywać ID zdarzeń i sprawdzać, czy faktura dla danego zdarzenia nie została już wystawiona. Bez tego dostaniesz podwójne faktury.
- 4
Mapowanie danych Stripe → program księgowy
Zamiana danych ze Stripe (amount w groszach, currency, customer_details, tax_ids, line_items) na format API Fakturowni lub inFakt (buyer_name, buyer_tax_no, positions, price_net, tax). To najtrudniejsza część, bo trzeba obsłużyć różne waluty, stawki VAT, brakujące pola i edge cases.
- 5
Wywołanie API programu księgowego
Wysłanie żądania POST do API Fakturowni (/invoices.json) lub inFakt (/invoices) z danymi faktury. Obsługa kodów błędów, walidacji i retry przy tymczasowych problemach.
- 6
Obsługa błędów i monitoring
Logowanie błędów, alerty przy nieudanych fakturach, retry z exponential backoff dla tymczasowych awarii API, dashboard do śledzenia statusów. Bez tego nie wiesz, czy faktura się wystawiła, dopóki klient nie zapyta.
Przykład kodu: webhook Stripe + faktura (Node.js)
Poniżej uproszczony przykład endpointu webhook w Node.js (Express), który odbiera zdarzenie checkout.session.completed i tworzy fakturę w Fakturowni. To MVP, a w produkcji potrzebujesz jeszcze idempotencji, retry, obsługi wielu walut i pełnego mapowania pól.
const express = require('express');
const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY);
const app = express();
// Webhook endpoint: raw body wymagany do weryfikacji podpisu
app.post('/webhook', express.raw({ type: 'application/json' }), async (req, res) => {
const sig = req.headers['stripe-signature'];
let event;
try {
event = stripe.webhooks.constructEvent(
req.body,
sig,
process.env.STRIPE_WEBHOOK_SECRET // whsec_...
);
} catch (err) {
console.error('Webhook signature verification failed:', err.message);
return res.status(400).send('Invalid signature');
}
if (event.type === 'checkout.session.completed') {
const session = event.data.object;
// Pobierz line_items (nie są domyślnie w webhooku)
const lineItems = await stripe.checkout.sessions.listLineItems(session.id);
// Mapowanie danych na format Fakturowni
const invoiceData = {
api_token: process.env.FAKTUROWNIA_API_TOKEN,
invoice: {
kind: 'vat',
number: null, // Fakturownia nada numer
sell_date: new Date().toISOString().split('T')[0],
issue_date: new Date().toISOString().split('T')[0],
payment_type: 'card',
buyer_name: session.customer_details?.name || 'Osoba prywatna',
buyer_email: session.customer_details?.email,
buyer_tax_no: session.customer_details?.tax_ids?.[0]?.value || '',
positions: lineItems.data.map(item => ({
name: item.description,
quantity: item.quantity,
total_price_gross: item.amount_total / 100,
tax: 23, // ⚠️ hardcoded, w produkcji mapuj z konfiguracji
})),
// ... adres kupującego, waluta, metadane...
},
};
// Wyślij do API Fakturowni
const response = await fetch(
`https://${process.env.FAKTUROWNIA_DOMAIN}/invoices.json`,
{
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(invoiceData),
}
);
if (!response.ok) {
console.error('Fakturownia error:', await response.text());
// ⚠️ W produkcji: retry, alert, zapis do kolejki
}
}
res.json({ received: true });
});
app.listen(3000);Co brakuje w tym przykładzie (a jest w produkcji)
- Idempotencja: sprawdzenie, czy faktura dla tego zdarzenia już istnieje (Stripe może wysłać webhook wielokrotnie)
- Obsługa walut: przeliczanie kwot dla różnych walut, formatowanie zgodne z oczekiwaniami programu księgowego
- Mapowanie stawek VAT: różne stawki (23%, 8%, 5%, 0%, zw., np.) zależnie od rodzaju produktu i konfiguracji użytkownika
- Obsługa invoice.paid: osobna ścieżka dla subskrypcji z innymi polami danych
- Retry z exponential backoff: ponowne próby przy tymczasowych błędach API (timeout, 5xx)
- Monitoring i alerty: powiadomienia o nieudanych fakturach, dashboard z historią
- Obsługa adresu kupującego: mapowanie pól adresowych ze Stripe na pola Fakturowni/inFakt
- Obsługa inFakt: osobna integracja z innym formatem API
Ten kod to punkt startowy. W rzeczywistości produkcyjna integracja to 40–80 godzin pracy programisty. Więcej o aspektach technicznych integracji z KSeF znajdziesz w poradniku KSeF dla programistów.
DIY vs Stripto: porównanie wysiłku
Samodzielna budowa integracji daje pełną kontrolę, ale kosztuje czas i wymaga utrzymania. Stripto robi to samo bez pisania kodu. Porównanie:
| Aspekt | DIY (własny kod) | Stripto |
|---|---|---|
| Czas wdrożenia | 40–80 godzin (1–2 tygodnie) | 1 minuta |
| Koszt początkowy | 8 000–16 000 zł (praca developera) | 0 zł (5 faktur za darmo) |
| Koszt miesięczny | Serwer + utrzymanie + monitoring | 29 zł/mies. lub 290 zł/rok |
| Konfiguracja webhooków | Ręczna (panel Stripe + kod) | Automatyczna |
| Weryfikacja podpisów | Musisz zaimplementować | Wbudowana |
| Idempotencja | Musisz zaimplementować | Wbudowana |
| Obsługa Fakturowni + inFakt | Dwie osobne integracje | Oba wbudowane |
| Obsługa błędów i retry | Musisz zaimplementować | Automatyczna |
| Panel ze statusami faktur | Musisz zbudować | Wbudowany |
| Aktualizacje API | Twoja odpowiedzialność | Automatyczne |
| Pełna kontrola nad logiką | Tak | Ograniczona (konfiguracja w UI) |
Kiedy warto budować samemu? Gdy masz niestandardową logikę fakturowania (np. selektywne fakturowanie, własne reguły VAT, integracja z ERP) i dysponujesz zespołem programistycznym, który będzie to utrzymywać. Dla standardowego przypadku, gdzie każda płatność oznacza fakturę, Stripto jest tańsze i szybsze.
Jak Stripto obsługuje webhooks Stripe
Stripto automatyzuje cały łańcuch od webhooka do faktury. Nie musisz pisać kodu, konfigurować endpointów ani zarządzać podpisami.
- 1
Podłączasz konto Stripe w panelu Stripto
Podajesz klucz API Stripe. Stripto automatycznie tworzy webhook endpoint w Twoim koncie Stripe, więc nie musisz wchodzić do panelu Stripe.
- 2
Podłączasz Fakturownię lub inFakt
Podajesz klucz API programu księgowego. Stripto testuje połączenie i konfiguruje mapowanie danych.
- 3
Klient płaci, a faktura powstaje automatycznie
Stripe wysyła webhook do Stripto. Stripto weryfikuje podpis, sprawdza idempotencję, mapuje dane na format programu księgowego i tworzy fakturę ustrukturyzowaną. Program księgowy wysyła ją do KSeF. Cały proces trwa kilka sekund.
Szczegółowy opis automatycznego fakturowania ze Stripe znajdziesz w przewodniku po automatycznych fakturach.
Nie pisz kodu, podłącz Stripto
Automatyczne faktury z webhooków Stripe w minutę. Bez serwera, bez kodu, bez utrzymania.
Najczęściej zadawane pytania
Który webhook Stripe jest najważniejszy do fakturowania?
Najważniejsze jest checkout.session.completed, czyli zdarzenie potwierdzające, że klient zapłacił. Zawiera wszystkie dane potrzebne do wystawienia faktury: kwotę, walutę, dane kupującego, NIP (jeśli podany) i opis produktu. Stripto nasłuchuje właśnie tego zdarzenia.
Czy muszę samodzielnie konfigurować webhook w Stripe?
Jeśli używasz Stripto, to nie. Stripto automatycznie tworzy webhook endpoint w Twoim koncie Stripe podczas konfiguracji. Nie musisz wchodzić do panelu Stripe ani pisać kodu. Jeśli budujesz własną integrację, to tak, musisz ręcznie skonfigurować endpoint, weryfikację podpisów i obsługę zdarzeń.
Jaka jest różnica między checkout.session.completed a invoice.paid?
checkout.session.completed odpala się po jednorazowej płatności przez Stripe Checkout. invoice.paid odpala się, gdy Stripe pobierze płatność za subskrypcję (cyklicznie). Jeśli masz oba typy płatności, musisz nasłuchiwać obu zdarzeń. Stripto obsługuje oba automatycznie.
Co się stanie, jeśli mój serwer nie odpowie na webhook?
Stripe automatycznie ponawia wysyłkę webhooka. Jeśli Twój endpoint nie zwróci kodu 200 w ciągu 20 sekund, Stripe spróbuje ponownie, nawet przez 3 dni, z rosnącymi odstępami (exponential backoff). Po wyczerpaniu prób zdarzenie jest oznaczane jako nieudane. Stripto obsługuje to automatycznie, więc nie musisz martwić się o dostępność serwera.
Czy Stripto obsługuje webhook charge.succeeded?
Stripto nasłuchuje checkout.session.completed i invoice.paid, czyli zdarzeń z najlepszymi danymi do fakturowania. charge.succeeded zawiera mniej informacji (brak danych z Checkout, brak line_items) i nie jest rekomendowany do wystawiania faktur.
Ile kosztuje zbudowanie własnej integracji webhook → faktura?
W kosztach programistycznych: 40–80 godzin pracy developera na MVP (webhook, mapowanie danych, integracja z API Fakturowni/inFakt, obsługa błędów, retry, idempotencja, testy). Przy stawce 200 zł/h to 8 000–16 000 zł. Plus utrzymanie, monitoring i aktualizacje API. Stripto kosztuje 29 zł/mies. i jest gotowe w minutę.
Czy mogę filtrować, które płatności Stripe generują faktury?
W samodzielnej integracji tak, ale musisz to zaprogramować. W Stripto każda udana płatność ze Stripe generuje fakturę automatycznie. Jeśli potrzebujesz selektywnego fakturowania (np. tylko B2B z NIP-em), własna integracja daje więcej kontroli, ale wymaga znacznie więcej pracy.
Czy Stripe webhook jest bezpieczny?
Tak, pod warunkiem że weryfikujesz podpis. Każdy webhook od Stripe zawiera nagłówek Stripe-Signature z podpisem HMAC. Musisz go sprawdzić używając webhook secret (whsec_...) z panelu Stripe. Bez weryfikacji ktoś może wysłać fałszywy webhook na Twój endpoint i spowodować wystawienie fałszywej faktury. Stripto weryfikuje podpisy automatycznie.
Połącz Stripe z Fakturownią lub inFakt
Konfiguracja w minutę. Automatyczne faktury gotowe na KSeF.