Stripe API i fakturowanie

Stripe Webhooks a automatyczne faktury: jak to działa?

Webhooks to mechanizm, dzięki któremu Stripe powiadamia Twój serwer o zdarzeniach, na przykład o udanej płatności. To fundament automatycznego fakturowania: klient płaci, webhook trafia na Twój endpoint, faktura powstaje w Fakturowni lub inFakt. Ten artykuł wyjaśnia jak to działa, ile kosztuje samodzielna budowa i dlaczego Stripto robi to w minutę.

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.completed

Odpala 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.paid

Odpala 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.succeeded zawiera mniej danych (brak line_items, ograniczone dane kupującego). Nie rekomendowany do fakturowania
  • payment_intent.succeeded informuje o udanej płatności, ale nie zawiera kontekstu z Checkout Session (brak danych produktu, adresu)
  • checkout.session.async_payment_succeeded dotyczy 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. 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. 2

    Weryfikacja podpisu Stripe-Signature

    Każdy webhook od Stripe zawiera nagłówek Stripe-Signature z 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. 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. 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. 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. 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:

AspektDIY (własny kod)Stripto
Czas wdrożenia40–80 godzin (1–2 tygodnie)1 minuta
Koszt początkowy8 000–16 000 zł (praca developera)0 zł (5 faktur za darmo)
Koszt miesięcznySerwer + utrzymanie + monitoring29 zł/mies. lub 290 zł/rok
Konfiguracja webhookówRęczna (panel Stripe + kod)Automatyczna
Weryfikacja podpisówMusisz zaimplementowaćWbudowana
IdempotencjaMusisz zaimplementowaćWbudowana
Obsługa Fakturowni + inFaktDwie osobne integracjeOba wbudowane
Obsługa błędów i retryMusisz zaimplementowaćAutomatyczna
Panel ze statusami fakturMusisz zbudowaćWbudowany
Aktualizacje APITwoja odpowiedzialnośćAutomatyczne
Pełna kontrola nad logikąTakOgraniczona (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. 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. 2

    Podłączasz Fakturownię lub inFakt

    Podajesz klucz API programu księgowego. Stripto testuje połączenie i konfiguruje mapowanie danych.

  3. 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.

Zacznij za darmo

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.

Wypróbuj Stripto