Przejdź do głównej zawartości

PRO REST API

REST API w namespace polski-pro/v1 do zarządzania fakturami, ustawieniami i dokumentami prawnymi. Wymaga uwierzytelnienia i uprawnienia manage_woocommerce.

API wymaga dwóch elementów autoryzacji:

  1. Nonce WordPress - nagłówek X-WP-Nonce z wartością wygenerowaną przez wp_create_nonce('wp_rest')
  2. Uprawnienie - zalogowany użytkownik musi posiadać capability manage_woocommerce
const response = await fetch('/wp-json/polski-pro/v1/invoices', {
headers: {
'X-WP-Nonce': wpApiSettings.nonce,
'Content-Type': 'application/json',
},
});
$nonce = wp_create_nonce('wp_rest');
$response = wp_remote_get(
rest_url('polski-pro/v1/invoices'),
[
'headers' => [
'X-WP-Nonce' => $nonce,
],
]
);

Brakujący lub nieprawidłowy nonce odrzuca WordPress z kodem rest_cookie_invalid_nonce i statusem 403. Zalogowany użytkownik bez uprawnienia manage_woocommerce dostaje 403 z kodem polski_pro_forbidden, i tak samo kończy się wywołanie bez zalogowania: kontroler faktur ustawia status 403 na sztywno, więc 401 tu nie występuje.

GET /wp-json/polski-pro/v1/invoices

Parametry zapytania:

Parametr Typ Domyślna Opis
order_id int brak Filtr po ID zamówienia WooCommerce
type string brak Filtr typu: faktura_vat, proforma, korygujaca, paragon, packing_slip
status string brak Filtr statusu: draft, issued, sent, paid, cancelled
page int 1 Numer strony
per_page int 20 Liczba wyników na stronę, przycinana do zakresu 1-100

To jest cała lista zarejestrowanych parametrów. Endpoint nie przyjmuje zakresu dat ani wyszukiwania pełnotekstowego: filtrowanie po dacie i szukanie po numerze faktury lub nazwie kontrahenta trzeba zrobić po stronie klienta.

Odpowiedź (200 OK):

Ciałem odpowiedzi jest zwykła tablica obiektów faktur. Liczniki wracają w nagłówkach X-WP-Total i X-WP-TotalPages, a nie w ciele odpowiedzi. Wpisy listy nie zawierają pozycji: items wypełnia wyłącznie endpoint pojedynczej faktury.

[
{
"id": 1,
"order_id": 567,
"original_invoice_id": null,
"source_refund_id": null,
"type": "faktura_vat",
"type_label": "Faktura VAT",
"number": "FV/2026/04/001",
"status": "issued",
"status_label": "Issued",
"nip_seller": "9876543210",
"nip_buyer": "1234567890",
"buyer_name": "Firma Testowa Sp. z o.o.",
"buyer_address": "ul. Testowa 1",
"buyer_city": "Warszawa",
"buyer_postcode": "00-001",
"correction_reason": null,
"net_total": 1000.00,
"vat_total": 230.00,
"gross_total": 1230.00,
"currency": "PLN",
"pdf_path": "/wp-content/uploads/polski-pro/invoices/FV-2026-04-001.pdf",
"ksef_reference": null,
"ksef_status": null,
"issued_at": "2026-04-01T10:30:00+02:00",
"created_at": "2026-04-01T10:30:00+02:00",
"items": []
}
]
POST /wp-json/polski-pro/v1/invoices

Parametry body (JSON):

Parametr Typ Wymagany Opis
order_id int Tak ID zamówienia WooCommerce
type string Nie Typ: faktura_vat (domyślnie), proforma, korygujaca, paragon, packing_slip

Żądanie:

{
"order_id": 567,
"type": "faktura_vat"
}

Odpowiedź (201 Created):

Utworzona faktura, w tym samym kształcie co wpisy listy powyżej. Nieznany type, brak zamówienia albo nieudane utworzenie zwracają 400 z polem message.

{
"id": 43,
"order_id": 567,
"original_invoice_id": null,
"source_refund_id": null,
"type": "faktura_vat",
"type_label": "Faktura VAT",
"number": "FV/2026/04/002",
"status": "issued",
"status_label": "Issued",
"nip_seller": "9876543210",
"nip_buyer": "1234567890",
"buyer_name": "Firma Testowa Sp. z o.o.",
"buyer_address": "ul. Testowa 1",
"buyer_city": "Warszawa",
"buyer_postcode": "00-001",
"correction_reason": null,
"net_total": 500.00,
"vat_total": 115.00,
"gross_total": 615.00,
"currency": "PLN",
"pdf_path": null,
"ksef_reference": null,
"ksef_status": null,
"issued_at": "2026-04-05T14:00:00+02:00",
"created_at": "2026-04-05T14:00:00+02:00",
"items": []
}
GET /wp-json/polski-pro/v1/invoices/{id}

Zwraca kompletne dane faktury wraz z pozycjami (items).

Odpowiedź (200 OK):

{
"id": 43,
"order_id": 567,
"original_invoice_id": null,
"source_refund_id": null,
"type": "faktura_vat",
"type_label": "Faktura VAT",
"number": "FV/2026/04/002",
"status": "issued",
"status_label": "Issued",
"nip_seller": "9876543210",
"nip_buyer": "1234567890",
"buyer_name": "Firma Testowa Sp. z o.o.",
"buyer_address": "ul. Testowa 1",
"buyer_city": "Warszawa",
"buyer_postcode": "00-001",
"correction_reason": null,
"net_total": 212.20,
"vat_total": 48.80,
"gross_total": 261.00,
"currency": "PLN",
"pdf_path": "/wp-content/uploads/polski-pro/invoices/FV-2026-04-002.pdf",
"ksef_reference": null,
"ksef_status": null,
"issued_at": "2026-04-05T14:00:00+02:00",
"created_at": "2026-04-05T14:00:00+02:00",
"items": [
{
"id": 91,
"product_id": 120,
"name": "Produkt testowy",
"quantity": 2,
"unit": "szt.",
"net_price": 100.00,
"vat_rate": 23,
"vat_amount": 46.00,
"gross_price": 246.00
},
{
"id": 92,
"product_id": null,
"name": "Dostawa - InPost Paczkomat",
"quantity": 1,
"unit": "szt.",
"net_price": 12.20,
"vat_rate": 23,
"vat_amount": 2.80,
"gross_price": 15.00
}
]
}

Nazwa i adres sprzedawcy nie należą do tego payloadu. Pochodzą z danych sprzedawcy w ustawieniach faktur, a na samej fakturze zapisywany jest tylko nip_seller.

Odpowiedź (404 Not Found):

{
"message": "Invoice not found."
}
POST /wp-json/polski-pro/v1/invoices/{id}/pdf

Regeneruje plik PDF faktury. Endpoint nie przyjmuje żadnych parametrów body: szablon i język pochodzą z ustawień faktur.

Odpowiedź (200 OK):

Odświeżony obiekt faktury, z polem pdf_path wskazującym nowy plik. Brak faktury zwraca 404, brak zamówienia 400, a nieudane wygenerowanie pliku 500, każde z polem message.

POST /wp-json/polski-pro/v1/invoices/{id}/ksef

Kolejkuje fakturę do wysyłki do Krajowego Systemu e-Faktur (KSeF) przez Action Scheduler. Endpoint nie przyjmuje parametrów body i nic w kokpicie WordPressa go nie wywołuje: jedyną drogą jest klient REST.

Wywołanie kończy się w chwili zakolejkowania zadania. Nigdy nie zwraca w odpowiedzi numeru referencyjnego KSeF, statusu KSeF ani linku do UPO, bo w tym momencie żadna z tych wartości jeszcze nie istnieje. Odczytaj je później z pól ksef_reference i ksef_status faktury.

Zanim się na tym oprzesz, przeczytaj Integracja z KSeF: klient API jest przypięty do środowiska testowego KSeF, a jego uwierzytelnianie nie zostało potwierdzone od początku do końca.

Odpowiedź (202 Accepted):

{
"invoice": {
"id": 43,
"number": "FV/2026/04/002",
"status": "issued",
"ksef_reference": null,
"ksef_status": null
},
"message": "Invoice queued for KSeF submission."
}

Wartość invoice to pełny obiekt faktury pokazany wyżej, tutaj przycięty do pól istotnych dla tego wywołania.

Pozostałe odpowiedzi:

Kod Kiedy
404 Nie ma faktury o tym ID
422 Dokument nie jest dokumentem księgowym. Kwalifikują się tylko faktura_vat i korygujaca, więc paragon, proforma i WZ są tu odrzucane
409 Faktura ma już referencję KSeF, a wysłaną fakturę można wyłącznie skorygować, nigdy wysłać ponownie
503 Action Scheduler jest niedostępny, więc nie da się nic zakolejkować
{
"message": "Paragon documents are not eligible for KSeF submission."
}
POST /wp-json/polski-pro/v1/invoices/{id}/correction

Tworzy fakturę korygującą powiązaną z fakturą źródłową. Skorygowane kwoty wyliczane są z zamówienia oraz, jeśli został podany, ze zwrotu WooCommerce. Tym endpointem nie da się wpisać skorygowanych pozycji ręcznie.

Parametry body (JSON):

Parametr Typ Wymagany Opis
refund_id int Nie Zwrot WooCommerce, na którym opiera się korekta

Żądanie:

{
"refund_id": 981
}

Odpowiedź (201 Created):

Faktura korygująca, w tym samym kształcie co każdy inny obiekt faktury. type to korygujaca, original_invoice_id wskazuje fakturę źródłową, a sumy są ujemne.

{
"id": 44,
"order_id": 567,
"original_invoice_id": 43,
"source_refund_id": 981,
"type": "korygujaca",
"type_label": "Faktura korygujaca",
"number": "FK/2026/04/001",
"status": "issued",
"status_label": "Issued",
"correction_reason": "Zwrot 1 sztuki produktu",
"net_total": -100.00,
"vat_total": -23.00,
"gross_total": -123.00,
"currency": "PLN",
"pdf_path": null,
"ksef_reference": null,
"ksef_status": null,
"issued_at": "2026-04-05T15:00:00+02:00",
"created_at": "2026-04-05T15:00:00+02:00",
"items": []
}

Brak faktury źródłowej zwraca 404, a korekta, której serwis nie potrafi zbudować, 400.

GET /wp-json/polski-pro/v1/invoices/stats

Parametry zapytania:

Parametr Typ Domyślna Opis
days int 30 Liczba dni wstecz, przycinana do zakresu 1-365

To jedyny parametr tego endpointu. Nie ma grupowania po dniach, tygodniach ani miesiącach.

Odpowiedź (200 OK):

Liczniki obejmują faktury utworzone w oknie days. total_revenue sumuje gross_total z pominięciem faktur anulowanych, natomiast kwoty w by_type sumują wszystko, więc gdy w oknie są faktury anulowane, suma przychodów z by_type jest wyższa niż total_revenue. ksef_sent liczy faktury, które mają zapisaną referencję KSeF.

{
"period_days": 30,
"total": 156,
"total_revenue": 150588.9,
"ksef_sent": 12,
"by_type": [
{ "type": "faktura_vat", "count": 148, "revenue": 152430.4 },
{ "type": "korygujaca", "count": 3, "revenue": -1230.0 },
{ "type": "proforma", "count": 5, "revenue": 3078.5 }
],
"by_status": [
{ "status": "issued", "count": 120 },
{ "status": "sent", "count": 25 },
{ "status": "paid", "count": 8 },
{ "status": "cancelled", "count": 3 }
]
}

Odpowiedź zawiera wyłącznie pola wymienione wyżej, bez dodatkowych podsumowań, rozbić po stawkach VAT czy osi czasu. Rozbicia by_type i by_status są listami, nie obiektami z kluczami. W tym przykładzie trzy anulowane faktury o łącznej wartości brutto 3690,00 nie wchodzą do total_revenue, ale wchodzą do przychodu w by_type.

GET /wp-json/polski-pro/v1/settings
PUT /wp-json/polski-pro/v1/settings

Trasa rejestruje metody odczytu i edycji, więc zapis przyjmuje PUT, PATCH albo POST. Obie metody wymagają uprawnienia manage_woocommerce.

Parametry body (JSON):

Nie ma parametrów section ani settings. Body to same grupy ustawień na najwyższym poziomie. Grupy, które rozpoznaje handler:

Grupa Zapisywana opcja
invoices polski_pro_invoices
ksef polski_pro_ksef
nip polski_pro_nip
shipping polski_pro_shipping
delivery_date polski_delivery_date
checkout polski_pro_checkout
abandoned_carts polski_abandoned_carts
conditional_payments polski_pro_conditional_payments
product_feed polski_pro_product_feed
loyalty polski_pro_loyalty
sms polski_pro_sms
accounting polski_pro_accounting

Każda podana grupa nadpisuje zapisaną opcję w całości, więc wysyłaj pełną zawartość grupy, a nie pojedyncze pola. Klucze spoza listy dozwolonych pól danej grupy są odrzucane. Grupy pominięte w body zostają bez zmian, a wszystko wysłane pod nazwą spoza powyższej tabeli jest ignorowane.

Żądanie:

{
"invoices": {
"auto_generate": true,
"numbering_format": "FV/{YYYY}/{MM}/{NR}",
"seller_nip": "9876543210",
"payment_deadline_days": 14
},
"ksef": {
"enabled": false,
"environment": "test",
"auto_send": false
}
}

Odpowiedź (200 OK):

Zapis zwraca kompletny zestaw ustawień PRO, dokładnie taki sam jak GET, a nie tylko zmienioną grupę. W odpowiedzi nie ma pól section ani updated_at.

{
"invoices": {
"auto_generate": true,
"numbering_format": "FV/{YYYY}/{MM}/{NR}",
"seller_nip": "9876543210",
"payment_deadline_days": 14
},
"ksef": {
"enabled": false,
"environment": "test",
"auto_send": false
},
"nip": {
"checkout_field": true,
"required": false,
"validate_gus": true
}
}
GET /wp-json/polski-pro/v1/legal/variables

Zwraca nazwy zmiennych obsługiwanych przez szablony, wartości domyślne wzięte z ustawień WooCommerce oraz etykiety trzech dostępnych typów dokumentów.

Odpowiedź (200 OK):

{
"required": {
"company_name": "Full company name",
"company_address": "Company address",
"company_nip": "NIP (tax ID)",
"company_regon": "REGON number",
"company_email": "Contact email",
"company_phone": "Contact phone",
"shop_url": "Shop URL",
"shop_name": "Shop name",
"bank_name": "Bank name",
"bank_account": "Bank account number"
},
"defaults": {
"company_name": "Mój Sklep",
"company_address": "ul. Sklepowa 5, 02-222 Warszawa",
"company_nip": "9876543210",
"company_regon": "",
"company_email": "[email protected]",
"company_phone": "",
"shop_url": "https://mojsklep.pl",
"shop_name": "Mój Sklep",
"bank_name": "",
"bank_account": ""
},
"types": {
"regulamin": "Regulamin sklepu",
"polityka-prywatnosci": "Polityka prywatnosci",
"polityka-zwrotow": "Prawo odstapienia / Polityka zwrotow"
}
}
POST /wp-json/polski-pro/v1/legal/generate

Renderuje szablon dokumentu i zwraca go do podglądu. Nic nie zapisuje.

Parametry body (JSON):

Parametr Typ Wymagany Opis
type string Tak Typ dokumentu: regulamin, polityka-prywatnosci, polityka-zwrotow
variables object Nie Nadpisania zmiennych szablonu, domyślnie pusty obiekt. Wartości niepodane biorą się z ustawień sklepu

Endpoint nie zna parametrów company_data, format ani language. Dane firmy przekazuje się jako zmienne, a wynik zawsze wraca jako treść szablonu, bez wariantu Markdown czy PDF.

Żądanie:

{
"type": "regulamin",
"variables": {
"company_name": "Mój Sklep Sp. z o.o.",
"company_nip": "9876543210",
"company_address": "ul. Sklepowa 5, 02-222 Warszawa",
"company_email": "[email protected]",
"company_phone": "+48 123 456 789"
}
}

Odpowiedź (200 OK):

{
"type": "regulamin",
"content": "<h1>Regulamin sklepu internetowego...</h1>...",
"variables_used": {
"company_name": "Mój Sklep Sp. z o.o.",
"company_nip": "9876543210",
"company_address": "ul. Sklepowa 5, 02-222 Warszawa",
"company_email": "[email protected]",
"company_phone": "+48 123 456 789"
}
}

Nieznany type zwraca 400, a brakujący lub pusty szablon 500, oba z polem message.

POST /wp-json/polski-pro/v1/legal/publish

Renderuje ten sam dokument i zapisuje go jako stronę WordPressa o statusie draft, a następnie zapamiętuje jej ID w ustawieniach Polski. Publikację strony zostawia człowiekowi.

Parametry body (JSON):

Parametr Typ Wymagany Opis
type string Tak Typ dokumentu: regulamin, polityka-prywatnosci, polityka-zwrotow
variables object Nie Nadpisania zmiennych szablonu, domyślnie pusty obiekt
page_id int Nie Istniejąca strona do nadpisania, domyślnie 0, czyli utwórz nową

Odpowiedź (201 Created):

{
"page_id": 412,
"edit_url": "https://mojsklep.pl/wp-admin/post.php?post=412&action=edit",
"view_url": "https://mojsklep.pl/?page_id=412",
"status": "draft",
"message": "Page created as draft. Review and publish when ready."
}

Endpointy faktur nie mają własnego słownika kodów błędów. Zwracają status HTTP i gołe ciało z jednym polem:

{
"message": "Invoice not found."
}

Jedyny nazwany kod błędu w kontrolerze faktur to polski_pro_forbidden, zwracany przez sprawdzenie uprawnień.

Kod HTTP Kod błędu Kiedy
400 brak Nieznany type, brak zamówienia, nieudane utworzenie faktury albo korekty
403 polski_pro_forbidden Użytkownik nie ma uprawnienia manage_woocommerce
404 brak Nie ma faktury o tym ID
409 brak Faktura ma już referencję KSeF
422 brak Dokument nie kwalifikuje się do KSeF
500 brak Nie udało się wygenerować PDF
503 brak Action Scheduler jest niedostępny

Poza polski_pro_forbidden wtyczka nie definiuje tu żadnych nazwanych kodów błędów, więc nie ma sensu testować na inne identyfikatory: pozostałe błędy rozpoznaje się po statusie HTTP i polu message.

Endpointy dokumentów prawnych zachowują się tak samo: 400 przy nieznanym typie i 500 przy braku szablonu, oba z polem message.

Wyszukiwarka GUS to jedyne miejsce z własnymi kodami: polski_pro_invalid_nip (400), polski_pro_rate_limited (429) i polski_pro_gus_unavailable (502).

Nie ma globalnego limitu żądań. Cała warstwa REST w PRO ma dokładnie jeden licznik i dotyczy on wyłącznie wyszukiwania danych firmy w GUS:

POST /wp-json/polski-pro/v1/gus/lookup

Limit liczony jest per adres IP i domyślnie wynosi 10 zapytań na godzinę. Zalogowani użytkownicy z uprawnieniem manage_woocommerce są z niego wyłączeni, bo checkout ma z tego korzystać także dla niezalogowanych klientów. Po przekroczeniu endpoint zwraca 429 z kodem polski_pro_rate_limited.

Okno i próg da się przestawić filtrami:

Filtr Domyślnie Opis
polski-pro/gus/rate_limit_window_seconds HOUR_IN_SECONDS Długość okna w sekundach. Wartość 0 lub mniejsza wyłącza limit
polski-pro/gus/rate_limit_max_attempts 10 Liczba zapytań w oknie. Wartość 0 lub mniejsza wyłącza limit
Ta strona ma wyłącznie charakter informacyjny i nie stanowi porady prawnej. Przed wdrożeniem skonsultuj się z prawnikiem. Polski for WooCommerce jest oprogramowaniem open source (GPLv2) dostarczanym bez gwarancji.