Przejdź do treści

Dla programistów

Integracja SaaS z księgowością: klienci, szkice faktur, webhooki

Ostatnia weryfikacja SUPPORTED WITH LIMITATIONS

Tłumaczenie wersji angielskiej, która jest aktualizowana jako pierwsza. Stwierdzenia regulacyjne odnoszą się do wymienionych źródeł i daty ich odczytu.

Połączenie produktu SaaS z księgowością w KRONENWERK oznacza cztery rzeczy: utworzenie jednego klienta na każde płacące konto, otwarcie transakcji i szkicu faktury dla każdego zdarzenia rozliczeniowego z nagłówkiem Idempotency-Key wyprowadzonym z własnego rekordu, odbieranie zdarzeń invoice.issued, invoice.paid i payment.recorded na punkcie końcowym webhooków oraz uzgadnianie stanu za pomocą GET /reports/outstanding. API nie wystawia faktur ani nie rejestruje płatności; robi to osoba w produkcie, a zdarzenia informują Państwa system o tym, co się wydarzyło. Taki jest uczciwy kształt tej integracji i ta strona pokazuje go krok po kroku.

Co integracja może, a czego nie może zautomatyzować

API KRONENWERK tworzy rekordy odwracalne i odczytuje księgi. Nie wykonuje czynności nieodwracalnych — wystawienia faktury, zarejestrowania płatności, anulowania — ponieważ każda z nich zużywa coś, czego nie da się cofnąć, albo przesuwa pieniądze w księdze. Dla back-endu SaaS jest to ograniczenie, które warto znać, zanim zaprojektują Państwo integrację.

Państwa zdarzenieCo robi Państwa aplikacjaCo dzieje się w produkcieCo wraca
Konto rejestruje się lub przechodzi na plan płatnyPOST /customersKlient pojawia się w danych podstawowych z numerem partnera201 z id i number klienta
Uzgodniono umowę lub zamówieniePOST /transactionsTransakcja (zlecenie z etapem i terminem) pojawia się na tablicy firmy201 z number, np. V2026-0481
Nadchodzi okres rozliczeniowy konta B2BPOST /invoices/draftsSzkic czeka na pozycje i wystawienie przez osobę201 ze szkicem; później invoice.issued
Klient płaci (karta, przelew)Nic w APIPłatność jest rejestrowana w produkcie: ręcznie albo dopasowana z podłączonego rachunku bankowegopayment.recorded oraz, gdy należność zostanie rozliczona, invoice.paid
Zwrot lub spór odwraca fakturęNic w APIOsoba wystawia pełną korektęinvoice.cancelled ze wskazaniem faktury korygującej
Kontrola na koniec miesiącaGET /reports/outstanding, GET /invoices?status=OPENOtwarte na dziś należności i zobowiązania; otwarte faktury

API jest częścią planu Enterprise; cała jego powierzchnia jest opisana na stronie API księgowego. Biznesowa strona prowadzenia ksiąg w firmie subskrypcyjnej — przychody rozliczane w czasie, VAT od usług cyfrowych, wiele walut — jest omówiona w artykułach księgowość dla SaaS i łączenie aplikacji z księgowością.

Wzorzec 1: jeden klient na płacące konto, tworzony idempotentnie

Klienta w KRONENWERK proszę tworzyć w chwili, gdy konto staje się klientem płacącym, a nie przy rejestracji, i używać własnego identyfikatora konta w nagłówku Idempotency-Key. Ponowienie po utraconej odpowiedzi zwróci wtedy klienta, który został utworzony, a nie duplikat — a zduplikowany klient to błąd, którego nikt nie zauważa, dopóki faktura nie trafi do niewłaściwego rekordu.

curl -X POST https://kronenwerk.org/api/extern/v1/customers \
  -H "Authorization: Bearer greif_live_…" \
  -H "Idempotency-Key: account-88213" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Beispiel GmbH",
    "email": "billing@example.de",
    "street": "Musterstraße 1",
    "postalCode": "10115",
    "city": "Berlin",
    "country": "DE",
    "vatId": "DE123456789",
    "currency": "EUR"
  }'

Nazwa, ulica, kod pocztowy i miejscowość są wymagane — EN 16931 przenosi adres w częściach, a klient bez ulicy to taki, do którego nie da się zaadresować żadnej faktury. Kraj, numer VAT i waluta są opcjonalne; brakujący kraj przyjmuje domyślnie kraj własnej firmy. Zwrócone id proszę zapisać przy swoim koncie. Numer VAT znaczy więcej, niż się wydaje: przy wystawianiu KRONENWERK sprawdza go w VIES i na jego podstawie wyprowadza rozstrzygnięcie podatkowe (np. odwrotne obciążenie dla klienta biznesowego z innego kraju UE). Proszę zbierać go przy zakupie.

Wzorzec 2: transakcja na każde zamówienie, z Państwa identyfikatorami

Transakcja w KRONENWERK to jednostka pracy z tytułem, klientem, etapem z własnego przepływu pracy firmy i terminem — zamówienie, projekt, okres subskrypcji. Nie niesie żadnych pieniędzy i właśnie dlatego jest właściwym rekordem dla „wydarzyło się coś do zafakturowania”, zanim ktokolwiek zdecydował, co będzie na fakturze. Identyfikatory dostawcy proszę umieścić w opisie, aby osoba, która później wystawi fakturę, znalazła subskrypcję Stripe lub zamówienie jednym wyszukaniem.

curl -X POST https://kronenwerk.org/api/extern/v1/transactions \
  -H "Authorization: Bearer greif_live_…" \
  -H "Idempotency-Key: sub_1Q…-2026-09" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Team plan, September 2026 — Beispiel GmbH",
    "customerId": "3f2b…",
    "description": "Stripe subscription sub_1Q…, invoice in_1Q…, 12 seats",
    "dueOn": "2026-09-30"
  }'

Wymagany jest tylko title. stage może wskazywać klucz etapu z przepływu pracy firmy; pominięty sprawia, że transakcja zaczyna tam, gdzie zaczyna się przepływ. Odpowiedź zawiera id, number, title, stage, customer, dueOn, archived i createdAt. GET /transactions?search=sub_1Q… odnajduje ją ponownie. Proszę pamiętać, że nie jest to zapis księgowy: nic nie zostaje zaksięgowane, dopóki w produkcie nie zostanie wystawiona faktura lub zarejestrowana płatność.

Wzorzec 3: szkic faktury na każde zdarzenie rozliczeniowe B2B

Dla klientów biznesowych, którzy potrzebują prawidłowej faktury — XRechnung dla niemieckiego nabywcy publicznego, dokumentu Peppol dla belgijskiego, Factur-X dla francuskiego — proszę rozpocząć szkic, gdy nadchodzi okres rozliczeniowy. Szkic niesie propozycję numeracji sprzedawcy i warunki płatności klienta; osoba dodaje pozycje i wystawia go, a plik ustrukturyzowany jest generowany i walidowany w tym momencie. Dlaczego granica przebiega właśnie na szkicu, wyjaśnia strona API fakturowania.

curl -X POST https://kronenwerk.org/api/extern/v1/invoices/drafts \
  -H "Authorization: Bearer greif_live_…" \
  -H "Idempotency-Key: in_1Q…" \
  -H "Content-Type: application/json" \
  -d '{ "customerId": "3f2b…" }'

Jako klucza proszę użyć identyfikatora faktury dostawcy: jedna faktura Stripe, jeden szkic KRONENWERK, niezależnie od tego, ile razy dostarczony zostanie webhook, który go wywołał. Jeśli Państwa produkt rozlicza konsumentów, a nie firmy, szkic na każdą płatność może w ogóle nie być potrzebny; okresowe zestawienie obsługiwane w produkcie często pasuje lepiej, a to, czy sprzedaż konsumencka w danym kraju wymaga indywidualnej faktury, wymaga potwierdzenia przez specjalistę.

Wzorzec 4: nasłuchiwanie webhooków, weryfikacja, deduplikacja, szybka odpowiedź

Proszę zarejestrować w produkcie punkt końcowy HTTPS na porcie 443 i zasubskrybować invoice.issued, invoice.paid, invoice.cancelled oraz payment.recorded. Każda dostawa niesie KRONENWERK-Signature: t=<seconds>,v1=<hex> — HMAC-SHA256 obliczony ze znacznika czasu, kropki i surowej treści — oraz stabilny identyfikator zdarzenia w KRONENWERK-Event-Id i Idempotency-Key. Treść to płaski obiekt JSON, którego wartości są łańcuchami, klucze posortowane, a event i id zawsze obecne.

POST /hooks/kronenwerk HTTP/1.1
Content-Type: application/json; charset=utf-8
KRONENWERK-Event: invoice.paid
KRONENWERK-Event-Id: 0d3c…
KRONENWERK-Delivery: 61af…
KRONENWERK-Attempt: 1
Idempotency-Key: 0d3c…
KRONENWERK-Signature: t=1788768000,v1=9f2c…
User-Agent: KRONENWERK-Webhooks/1

{"amountDueMinor":"0","buyerName":"Beispiel GmbH","currency":"EUR","documentType":"INVOICE","dueDate":"2026-09-17","event":"invoice.paid","grossMinor":"105910","id":"0d3c…","invoiceId":"7a90…","issueDate":"2026-09-03","netMinor":"89000","number":"2026-0042","paidOn":"2026-09-10","paymentState":"PAID","taxMinor":"16910"}

Zasady obsługi są te same, które Stripe dokumentuje dla własnych webhooków, i z tych samych powodów: weryfikacja podpisu względem surowej treści przed parsowaniem, odrzucenie znacznika czasu spoza tolerancji (własny weryfikator KRONENWERK stosuje pięć minut), zapisanie identyfikatora zdarzenia i pominięcie wszystkiego, co już widziano, niepoleganie na kolejności oraz szybkie zwrócenie 2xx i wykonanie pracy w kolejce. Dostarczanie jest typu at-least-once z ponowieniami; przekierowania są traktowane jako niepowodzenia. Pełny opis znajduje się na stronie webhooki.

Wzorzec 5: uzgadnianie z raportem należności otwartych

GET /reports/outstanding odpowiada na pytanie „ile jest dziś należne w każdą stronę” z tego samego przeglądu, który renderuje pulpit właściciela, więc Państwa liczba i jego liczba nie mogą się różnić.

{
  "asOf": "2026-09-03",
  "currency": "EUR",
  "booksOpen": true,
  "receivables": {
    "outstanding": { "minor": 4237650, "currency": "EUR" },
    "due": { "minor": 1105910, "currency": "EUR" },
    "overdue": { "minor": 318400, "currency": "EUR" },
    "count": 23
  },
  "payables": {
    "outstanding": { "minor": 812000, "currency": "EUR" },
    "due": { "minor": 0, "currency": "EUR" },
    "overdue": { "minor": 0, "currency": "EUR" },
    "count": 4
  }
}

Obie strony są raportowane osobno i nigdy nie są kompensowane: pieniądze należne firmie i pieniądze, które firma jest winna, stają się wymagalne w różnych dniach, a jedna liczba uspokajałaby dokładnie w tym momencie, w którym nie powinna. Dla widoku per faktura proszę przejść stronami przez GET /invoices?status=OPEN i porównać outstanding oraz overdue z własnym stanem rozliczeń. Rozbieżność zwykle oznacza płatność, która dotarła do banku, ale nie została jeszcze dopasowana w produkcie, albo fakturę, którą Państwa handler webhooków zgubił — dziennik identyfikatorów zdarzeń pokaże, które z nich zaszło.

Przykładowa sekwencja dla subskrypcji rozliczanej przez Stripe

  1. Stripe wysyła customer.subscription.created. Państwa handler weryfikuje je, deduplikuje po identyfikatorze zdarzenia Stripe i wywołuje POST /customers z Idempotency-Key: account-<id>, jeśli dla konta nie istnieje jeszcze klient KRONENWERK. Zwrócone id zostaje zapisane.
  2. Handler wywołuje POST /transactions z Idempotency-Key: sub_<id>-<period>, umieszczając identyfikatory subskrypcji i faktury Stripe w description, a koniec okresu w dueOn.
  3. Dla kont B2B handler wywołuje POST /invoices/drafts z Idempotency-Key: in_<id>.
  4. Osoba z działu finansów otwiera szkic, dodaje pozycję za okres na podstawie opisu transakcji i wystawia fakturę. KRONENWERK oblicza rozstrzygnięcie podatkowe, sprawdza numer VAT, waliduje plik ustrukturyzowany, zużywa numer i wysyła invoice.issued na Państwa punkt końcowy. number i invoiceId zostają zapisane przy fakturze Stripe.
  5. Stripe pobiera płatność kartą i wypłaca środki na rachunek bankowy firmy. Połączenie bankowe (Enable Banking dla banków europejskich, Plaid dla banków kanadyjskich i amerykańskich) pokazuje wypłatę; osoba dopasowuje ją do faktury albo rejestruje płatność ręcznie. payment.recorded i invoice.paid docierają na Państwa punkt końcowy.
  6. Jeśli Stripe zwraca obciążenie, osoba wystawia korektę w produkcie; przychodzi invoice.cancelled z cancelledByNumber, a Państwo dołączają numer faktury korygującej do zwrotu.
  7. Na koniec miesiąca porównują Państwo GET /reports/outstanding z własnymi otwartymi należnościami.

Pułapki

Wyprowadzanie kluczy idempotencji z czasu lub losowości
Klucz, który zmienia się przy ponowieniu, niczego nie chroni. Proszę wyprowadzać go z rekordu, który Państwo odwzorowują — identyfikatora konta, identyfikatora subskrypcji z okresem, identyfikatora faktury dostawcy — tak aby ponowienie oznaczało tę samą operację. Inna treść pod tym samym kluczem otrzymuje 409 IDEMPOTENZ_KONFLIKT, co jest defektem w Państwa kodzie, a nie błędem przejściowym.
Tworzenie szkiców, zanim istnieje klient
Stripe nie gwarantuje kolejności zdarzeń; invoice.paid może nadejść przed customer.subscription.created. Najpierw proszę ustalić klienta KRONENWERK, tworząc go idempotentnie, jeśli go brakuje, a dopiero potem utworzyć szkic.
Jeden klucz, jedna firma
Klucz API KRONENWERK jest przez całe swoje życie związany z dokładnie jedną firmą. SaaS z kilkoma podmiotami prawnymi (np. niemiecką GmbH i francuską SAS) potrzebuje jednego klucza na podmiot i musi kierować każde konto do właściwego; zob. wiele firm, wiele walut.
Traktowanie invoice.issued jako „wysłano”
Oznacza ono, że istnieje zwalidowany dokument i został zużyty numer. Doręczenie — e-mailem, przez Peppol za pośrednictwem podłączonego dostawcy punktu dostępowego lub przez system krajowy — jest osobnym krokiem w produkcie i nie jest raportowane w API.
Ignorowanie limitu zapytań
Budżet wynosi 240 zapytań na klucz, uzupełniany w tempie około dwóch na sekundę. Zadanie na koniec miesiąca, które w jednym rzucie tworzy tysiąc szkiców, napotka 429 z Retry-After; proszę respektować ten nagłówek i rozłożyć pracę w czasie. Szczegóły na stronie limity.
Testowanie na kluczu produkcyjnym
Podczas rozwoju proszę używać klucza greif_test_; działa on na tym samym hoście w trybie testowym dla firmy, która go utworzyła. GET /me zgłasza environment jako SANDBOX lub PRODUCTION, więc kontrola przy starcie może odmówić uruchomienia kompilacji testowej z kluczem produkcyjnym.
Przechowywanie kwot sformatowanych
Kwoty w API to całkowite jednostki mniejsze z kodem waluty, a w treściach webhooków — łańcuchy jednostek mniejszych. Proszę nigdzie nie parsować „1.059,10 €”; nie ma czego parsować.

Jak KRONENWERK to obsługuje

Obsługiwane z ograniczeniami Wszystko, co tu pokazano, działa na API w jego dzisiejszym kształcie, w planie Enterprise (cennik): idempotentne tworzenie klientów, transakcji i szkiców faktur; podpisane webhooki dla wystawienia, płatności, anulowania, zakupów i płatności; raport należności otwartych i stronicowany odczyt faktur. Ograniczenia są te, które wskazano w całym tekście: brak wystawiania, brak rejestrowania płatności, brak anulowania i brak pobierania plików przez API oraz brak automatycznego importu płatności Stripe. Jeśli Państwa integracja potrzebuje pętli rozliczeniowej bez udziału człowieka, API KRONENWERK tym nie jest. Jeśli potrzebuje, aby księgi firmy odzwierciedlały to, co sprzedał Państwa produkt, z krokami prawnymi wykonywanymi przez osobę zgodnie z zasadami danego kraju, to jest zamierzona ścieżka. Powiązane strony produktu to księgowość, faktury i automatyzacja; porównanie narzędzi księgowych z API znajduje się na stronie oprogramowanie księgowe z API.

Najczęściej zadawane pytania

Czy mogę zarejestrować płatność Stripe przez API?

Nie. API nie rejestruje płatności. Wypłaty trafiają do ksiąg przez połączenie bankowe albo osoba rejestruje płatność; następnie payment.recorded i invoice.paid docierają na Państwa punkt końcowy.

Czym jest „transakcja” w API?

Jednostką pracy z tytułem, opcjonalnym klientem, etapem z przepływu pracy firmy i terminem — zamówieniem lub okresem subskrypcji. Nie jest zapisem księgowym.

Czy potrzebuję szkicu na każdą płatność konsumencką?

Często nie. Szkice są przeznaczone dla klientów, którzy potrzebują indywidualnej, ustrukturyzowanej faktury. To, czy sprzedaż konsumencka w danym kraju jej wymaga, jest pytaniem wymagającym potwierdzenia przez specjalistę.

Jak powinienem wyprowadzać klucze idempotencji?

Z własnych stabilnych identyfikatorów: identyfikator konta dla klientów, identyfikator subskrypcji z okresem dla transakcji, identyfikator faktury dostawcy dla szkiców. Klucze mogą mieć do 200 znaków.

Jak testować bez dotykania ksiąg produkcyjnych?

Proszę utworzyć klucz greif_test_. Działa on na tym samym API w trybie testowym dla firmy, która go utworzyła, a GET /me zgłasza "environment", dzięki czemu Państwa kompilacja może to sprawdzić.

Źródła

  1. KRONENWERK developer documentation odczytano
  2. Stripe — Receive Stripe events in your webhook endpoint (duplicates, ordering, signatures) odczytano
  3. Stripe — Idempotent requests odczytano

Czytaj dalej