SaaS · FakturaXL · 2026 · tydzień

FakturaXL - integracja API: eksport CSV i faktury UBL 2.1

API wpuszcza jedno zapytanie na dziesięć sekund, a produkty i stany magazynowe siedzą w osobnych endpointach - narzędzie przechodzi przez wszystkie strony, czeka tam, gdzie musi, i zwraca jeden plik z produktem i ilością w jednym wierszu.

  • PHP
  • XML API
  • Vanilla JS
  • CSV
  • UBL 2.1
  • Peppol BIS Billing 3.0
FakturaXL - integracja API: eksport CSV i faktury UBL 2.1

Wyzwanie

Program do fakturowania trzyma faktury, katalog produktów i stany magazynowe, ale ich wyciągnięcie na zewnątrz to osobna sprawa. API zwraca produkty i stany magazynowe z dwóch różnych endpointów, każdy stronicowany, a limit przepuszcza jedno zapytanie na dziesięć sekund. Katalog na kilkaset pozycji oznacza kilkanaście minut odpytywania, w trakcie których nie można po prostu poczekać w milczeniu, bo nie wiadomo, czy coś jeszcze działa.

Nasze rozwiązanie

Powstała jednoplikowa aplikacja PHP z własnym interfejsem w przeglądarce: przegląd faktur z filtrami, szczegóły dokumentu, pobieranie PDF-a, klienci, magazyny i działy. Do tego eksport, który przechodzi przez wszystkie strony produktów i stanów, respektuje limit zapytań, ponawia po odbiciu i skleja obie listy w jeden CSV z produktem i ilością w wierszu. Zero zależności zewnętrznych - odpala się przez wbudowany serwer PHP.

1

Plików aplikacji

0

Zależności zewnętrznych

CSV i UBL 2.1

Formaty eksportu

Co zbudowaliśmy

  • 01 Podgląd faktur z filtrami po dacie, typie i statusie płatności
  • 02 Szczegóły dokumentu z pozycjami i pobieraniem PDF-a
  • 03 Produkty, stany magazynowe, klienci, magazyny i działy
  • 04 Eksport CSV produktów sklejonych ze stanem magazynowym
  • 05 Obsługa limitu API: odstępy między zapytaniami, ponowienie po odbiciu
  • 06 Pasek postępu przy eksporcie idącym przez kilkanaście stron
  • 07 Mapa kodów odpowiedzi API zamiast surowych numerów błędów
  • 08 Motyw ciemny i jasny, układ zjeżdżający do jednej kolumny na telefonie
  • 09 Jeden plik PHP, zero zależności, uruchamianie przez wbudowany serwer
Spis treści +

Punkt wyjścia

Dane w programie do fakturowania są, tylko nie da się ich stamtąd wyjąć w formie, której potrzebuje ktoś z zewnątrz - arkusz z produktami i aktualnym stanem magazynowym. Program pokazuje jedno i drugie, ale w osobnych widokach.

API stawia dwie przeszkody naraz. Produkty i stany magazynowe to dwa endpointy, każdy zwracający dane po stronie, a limit przepuszcza jedno zapytanie na dziesięć sekund. Zebranie pełnego katalogu to więc kilkanaście minut cierpliwego odpytywania, a nie jedno wywołanie.

Decyzje, które ukształtowały projekt

Jeden plik zamiast projektu

Backend, style i cały interfejs siedzą w jednym index.php. Bez frameworka, bez instalacji, bez katalogu z zależnościami - uruchamia się wbudowanym serwerem PHP i działa. Narzędzie, którego używa się kilka razy w miesiącu, nie może wymagać przypominania sobie, jak je postawić. To ten sam typ zadania, co inne nasze aplikacje webowe robione pod jedną konkretną robotę, a nie pod portfolio technologii.

Limit zapytań jako część projektu, nie jako awaria

Dziesięć sekund między zapytaniami to nie błąd do obejścia, tylko warunek brzegowy. Eksport odczekuje między stronami, rozpoznaje odpowiedź „przekroczono limit” i ponawia zapytanie po dodatkowej przerwie zamiast przerywać z błędem. Przez cały czas pokazuje, przy której stronie jest.

Alternatywa, czyli walenie w API do skutku, kończy się blokadą tokenu i eksportem urwanym w połowie. To właśnie ten rodzaj roboty - przejście przez dziesiątki stron API zamiast ręcznego klikania w panelu - ma sens jako automatyzacja, a nie jako kolejna czynność na liście rzeczy do zrobienia co miesiąc.

Sklejanie dwóch list po właściwym kluczu

Produkt i jego stan magazynowy trzeba dopasować po identyfikatorze, a nie po nazwie czy pozycji na liście. Zero sztuk zapisuje się jako zero, nie jako puste pole - w arkuszu to różnica między „nie ma na stanie” a „nie wiadomo”. Gdy strona produktów nie ma ani jednego dopasowania do pobranej strony stanów, interfejs proponuje przeszukanie pozostałych stron zamiast pokazywać pustą tabelę.

Kody błędów przetłumaczone na zdania

API odpowiada numerami. Aplikacja trzyma mapę tych kodów i pokazuje „nieprawidłowy token” albo „przekroczono limit zapytań, poczekaj chwilę”, bo komunikat kod=3 nie mówi użytkownikowi nic o tym, co ma zrobić.

Druga część: faktura ustrukturyzowana

Osobny wątek u tego samego klienta to eksport faktury do XML w standardzie UBL 2.1, w profilu Peppol BIS Billing 3.0. Plik albo przechodzi walidację normy, albo jest bezużyteczny - nie ma wersji „prawie zgodnej”.

Robota polegała na przejściu pola po polu przez wymagania normy: identyfikatory profilu, kody schematu przy numerach podatkowych, NIP z prefiksem kraju tam, gdzie standard go wymaga, i bez prefiksu tam, gdzie nie. Sekcje identyfikacyjne i podatkowe znikają, gdy kontrahent nie ma NIP-u, zamiast trafiać do pliku wypełnione samym prefiksem kraju - puste pole zawsze jest lepsze od pola z czymś, co tylko wygląda jak dane. Doszły dane płatności z numerem rachunku, osobny adres odbiorcy przy wysyłce pod inny adres oraz stawki zwolniona, niepodlegająca i odwrotne obciążenie, które w tym standardzie nie są procentami, tylko osobnymi kategoriami podatkowymi.

Każda wersja pliku szła przez zewnętrzny walidator Peppol, a nie przez „wygląda dobrze”.

Co z tego wyszło

Tu nie mamy z czego zrobić tabeli pomiarów - FakturaXL nie ma publicznego adresu, więc pomiar strony jest niewykonalny, a dane z produkcji klienta (ile razy narzędzie odpaliło eksport, jak długo trwał na pełnym katalogu) nie są nam znane. Zostaje efekt jakościowy: eksport produktów i stanów magazynowych, który wcześniej wymagał ręcznego przechodzenia przez dwa osobne widoki API, jest teraz jednym uruchomieniem i jednym plikiem CSV. Faktura w UBL 2.1 przechodzi walidację normy Peppol zamiast wracać z listą błędów.

Uczciwie: nie wiemy, ile czasu to realnie oszczędza u klienta - nie mierzyliśmy procesu sprzed integracji i nie mamy dostępu do logów z jego produkcji.

Technicznie

PHP 8 z curl i simplexml, komunikacja z API przez POST z ciałem XML, front jako SPA w czystym JavaScripcie w tym samym pliku. Eksport CSV z separatorem średnikowym, żeby arkusz otworzył go bez zabawy w import. Generator UBL to osobny skrypt PHP po stronie programu, sprawdzany na oficjalnych przykładach standardu i na fakturach z realnymi danymi.

Zrzuty ekranu

Ekran startowy: nawigacja podzielona na dokumenty, magazyn i pozostałe dane, token wpisuje się raz w panelu bocznym.
Ten sam widok w motywie jasnym - przełącznik siedzi pod polem tokenu.

Podobny problem do rozwiązania?

Napisz krótko, o co chodzi — wycena wraca w 24 godziny.

Zapytaj o wycenę