Integracje

REST API (WebApi) - integracje custom z panelem

REST API do integracji panelu z własnym systemem: wystawianie dokumentów, kontrahenci, towary, wysyłka do KSeF. Autoryzacja kluczem WebApi, przykłady w PHP, Pythonie i JavaScripcie.

REST API (WebApi) — przegląd

REST API pozwala połączyć Mobilną Fakturę z dowolnym zewnętrznym systemem: własnym sklepem, programem magazynowym, systemem ERP albo aplikacją mobilną. Dane wymieniane są w formacie JSON przez zwykłe zapytania HTTP.

Jeśli zamiast odpytywania wolisz otrzymywać powiadomienia o zdarzeniach, zajrzyj do artykułu o webhookach.

Dostępność: pakiet STANDARD i MAX.


Zastosowania

  • Automatyczne fakturowanie ze sklepu napisanego od podstaw (bez WooCommerce czy PrestaShop)
  • Integracja z systemem ERP albo programem magazynowym
  • Synchronizacja z CRM — kontrahenci w jednym miejscu
  • Aplikacja mobilna dla handlowców — wystawianie dokumentów w terenie
  • Własne raporty i zestawienia na podstawie danych z panelu
  • Wysyłka do KSeF bezpośrednio z zewnętrznego systemu

Włączenie REST API i klucz WebApi

REST API jest domyślnie wyłączone — trzeba je włączyć w panelu:

  1. Ustawienia → Integracje → WebAPI
  2. Przełącz protokół na REST (domyślnie ustawiony jest SOAP)
  3. Kliknij Generuj klucz — otrzymasz klucz WebApi

⚠️ Ważne: konto ma jeden klucz WebApi. Ponowne wygenerowanie unieważnia poprzedni, więc wszystkie integracje korzystające ze starego klucza przestaną działać — zaktualizuj je od razu.

Jeśli nie przełączysz protokołu na REST, każde zapytanie zwróci 403 z komunikatem „REST API nie jest włączone dla tego konta”.


Autoryzacja

API jest bezstanowe — dane uwierzytelniające dołączasz do każdego zapytania:

PoleOpis
loginlogin do panelu
password albo password_md5hasło jawne albo jego skrót MD5
webkeyklucz WebApi z ustawień
profile_idopcjonalnie — identyfikator profilu firmy
POST https://mobilna-faktura.pl/panel/api/v1/documents
Content-Type: application/json

{
  "login": "jan@firma.pl",
  "password_md5": "5f4dcc3b5aa765d61d8327deb882cf99",
  "webkey": "a4c4dcf4c0280f1d2e6f3ac1fe43f8e9"
}

Przy zapytaniach GET te same pola możesz przekazać w adresie:

curl "https://mobilna-faktura.pl/panel/api/v1/clients?login=jan@firma.pl&password_md5=<md5>&webkey=<klucz>"

⚠️ Ważne: w zapytaniach przesyłasz hasło do konta panelu. Używaj wyłącznie HTTPS, trzymaj dane w zmiennych środowiskowych i nigdy nie umieszczaj ich w repozytorium kodu.

Pierwszy krok — sprawdzenie konfiguracji

Endpoint POST /api/v1/auth/check działa nawet gdy REST jest jeszcze wyłączony. Zwraca informację, czy dane logowania są poprawne i czy protokół jest przełączony:

curl -X POST https://mobilna-faktura.pl/panel/api/v1/auth/check \
  -H "Content-Type: application/json" \
  -d '{"login":"jan@firma.pl","password":"tajne","webkey":"a4c4dcf4..."}'

Dostępne endpointy

Adres bazowy: https://mobilna-faktura.pl/panel/api/v1

Konto i profile

MetodaEndpointCo robi
POST/auth/checkSprawdzenie danych logowania i konfiguracji
GET/profilesLista profili firm na koncie
GET/meDane zalogowanego konta

Dokumenty

MetodaEndpointCo robi
GET/documentsLista dokumentów (filtry w parametrach)
GET/documents/{id}Szczegóły dokumentu wraz z pozycjami
POST/documentsWystawienie nowego dokumentu
DELETE/documentsUsunięcie — identyfikatory w polu ids
GET/documents/{id}/pdfPobranie PDF
POST/documents/{id}/sendWysyłka mailem do kontrahenta

Kontrahenci

MetodaEndpointCo robi
GET/clientsLista kontrahentów
GET/clients/{id}Szczegóły kontrahenta
POST/clientsDodanie nowego
DELETE/clientsUsunięcie — identyfikatory w polu ids

Kontrahent zwraca i przyjmuje pole default_price_level — poziom cenowy stosowany przy wystawianiu dokumentu (detaliczna, hurtowa, specjalna, podstawowa). null oznacza dziedziczenie poziomu z kartoteki towaru. To ten sam mechanizm co w panelu, więc integracja wystawiająca faktury dla klienta hurtowego dostanie właściwe ceny bez przeliczania ich po swojej stronie.

Towary i słowniki

MetodaEndpointCo robi
GET/itemsLista towarów i usług
GET/items/{id}Szczegóły pozycji
POST/itemsDodanie towaru
PUT/items/{id}Edycja towaru (ceny, opis, poziomy cen)
PUT/items/{id}/stockZmiana stanu magazynowego
GET/dictionariesLista dostępnych słowników
GET/dictionaries/{nazwa}Zawartość słownika (np. stawki VAT, jednostki)

Endpointy PUT przyjmują także POST, gdy biblioteka HTTP nie obsługuje metody PUT.

Poziomy cen w odpowiedzi

Każdy towar zwraca obok ceny podstawowej trzy poziomy cenowe:

{
    "id": 29130,
    "name": "Kabel HDMI 2m",
    "price_net": "39.00",
    "price_gross": "47.97",
    "default_price_level": "podstawowa",
    "price_retail":    {"net": "45.00", "gross": "55.35", "fallback": false},
    "price_wholesale": {"net": "29.00", "gross": "35.67", "fallback": false},
    "price_special":   {"net": "39.00", "gross": "47.97", "fallback": true}
}
  • price_net / price_gross to cena podstawowa — pola niezmienione, więc dotychczasowe integracje działają bez zmian.
  • fallback: true oznacza, że poziom nie ma własnej ceny i dziedziczy podstawową (brutto liczone ze stawki VAT towaru).
  • default_price_level to domyślny poziom towaru. Poziom ustawiony na kartotece kontrahenta (default_price_level w /clients) ma nad nim pierwszeństwo — dokładnie tak, jak przy wystawianiu faktury w panelu.

Przy zapisie ceny poziomów podaje się jako price_retail, price_wholesale, price_special (netto) oraz warianty _gross. Wartość null lub "" czyści poziom, czyli przywraca dziedziczenie ceny podstawowej.

Zmiana stanu magazynowego

Stan zmienia się wyłącznie przez dokument magazynowy: PZ przy zwiększeniu, WZ przy zmniejszeniu — tak samo jak w panelu. Dzięki temu każda zmiana z API jest widoczna w dokumentach, schodzi z partii FIFO i trafia do synchronizacji stanów ze sklepem.

Podaj dokładnie jedno z pól:

PoleZnaczeniePrzykład zastosowania
quantitystan docelowy (wartość absolutna)inwentaryzacja, pełna synchronizacja ze sklepem
changezmiana względna-3 po sprzedaży, +10 po dostawie
{
    "login": "...", "password": "...", "webkey": "...",
    "change": -3,
    "description": "Sprzedaż w sklepie"
}

Odpowiedź zawiera stan przed i po zmianie oraz identyfikator utworzonego dokumentu:

{
    "success": true,
    "item_id": 29130,
    "quantity": 12,
    "previous_quantity": 15,
    "changed": true,
    "document_type": "WZ",
    "warehouse_document_id": 8412
}

⚠️ Wymaga pakietu Max oraz włączonej opcji Ustawienia → WZ/PZ → aktualizacja stanów wraz z drukami. Bez tej opcji dokument powstanie, ale odpowiedź zwróci changed: false z wyjaśnieniem. Gdy stan już się zgadza, żaden dokument nie powstaje. Przy włączonej blokadzie stanów ujemnych zejście poniżej zera kończy się kodem 409.

KSeF

MetodaEndpointCo robi
POST/ksef/sendWysyłka dokumentu do KSeF
GET/ksef/statusSprawdzenie statusu wysyłki

⚠️ Ważne: usuwanie działa na kolekcji, nie na pojedynczym adresie — wyślij DELETE /documents z listą identyfikatorów w polu ids, a nie DELETE /documents/12.

Dokumentów i kontrahentów nie edytuje się przez API — dokument można wystawić, pobrać i usunąć, ale nie zmienić. Edycja PUT działa dla towarów.


Format odpowiedzi (JSON)

Każda odpowiedź zawiera pole success.

Powodzenie

{
  "success": true,
  "document_id": 998877,
  "already_exists": false,
  "positions": 3,
  "message": "Dokument zostal dodany"
}

Błąd

{
  "success": false,
  "message": "Brak wymaganych danych logowania (login, webkey, password lub password_md5)"
}

Kody HTTP

  • 200 OK — zapytanie wykonane (sprawdź pole success)
  • 400 Bad Request — brak wymaganego pola albo błędne dane
  • 401 Unauthorized — błędny login, hasło lub klucz WebApi
  • 402 Payment Required — wykorzystany limit dokumentów z abonamentu
  • 403 Forbidden — REST API nie jest włączone dla konta (przełącz protokół w ustawieniach)
  • 404 Not Found — zasób nie istnieje
  • 500 — błąd po stronie serwera

⚠️ Ważne: przy duplikacie numeru dokumentu API zwraca success: true wraz z polem already_exists: true i identyfikatorem istniejącego dokumentu — nie traktuj tego jako błędu.


Przykłady kodu

PHP

$auth = [
    'login'        => 'jan@firma.pl',
    'password_md5' => md5('twoje-haslo'),
    'webkey'       => 'a4c4dcf4c0280f1d2e6f3ac1fe43f8e9',
];

$dokument = [
    'numer_dokumentu'  => 'FV/2026/08/0042',
    'typ_dokumentu'    => 1,
    'data_wystawienia' => '16-08-2026',
    'data_sprzedazy'   => '16-08-2026',
    'termin_zaplaty'   => '30-08-2026',
    'na_nazwa'         => 'ACME Sp. z o.o.',
    'na_nip'           => '1234563218',
    'waluta'           => 'PLN',
    'products'         => [
        ['nazwa' => 'Usluga konsultingowa', 'amount' => 1,
         'cena' => 1000, 'cena2' => 1230, 'stawka_vat' => '23', 'jednostki' => 'szt.'],
    ],
];

$ch = curl_init('https://mobilna-faktura.pl/panel/api/v1/documents');
curl_setopt_array($ch, [
    CURLOPT_POST           => true,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER     => ['Content-Type: application/json'],
    CURLOPT_POSTFIELDS     => json_encode($auth + ['document' => $dokument]),
]);

$wynik = json_decode(curl_exec($ch), true);
curl_close($ch);

if (!empty($wynik['success'])) {
    echo 'Dokument zapisany, id: ' . $wynik['document_id'];
} else {
    echo 'Blad: ' . $wynik['message'];
}

Python

import hashlib, requests

BASE = 'https://mobilna-faktura.pl/panel/api/v1'
auth = {
    'login': 'jan@firma.pl',
    'password_md5': hashlib.md5('twoje-haslo'.encode()).hexdigest(),
    'webkey': 'a4c4dcf4c0280f1d2e6f3ac1fe43f8e9',
}

odp = requests.post(f'{BASE}/documents', json={**auth, 'document': {
    'numer_dokumentu': 'FV/2026/08/0042',
    'typ_dokumentu': 1,
    'data_wystawienia': '16-08-2026',
    'na_nazwa': 'ACME Sp. z o.o.',
    'na_nip': '1234563218',
    'products': [
        {'nazwa': 'Usluga', 'amount': 1, 'cena': 1000,
         'cena2': 1230, 'stawka_vat': '23', 'jednostki': 'szt.'},
    ],
}}).json()

print(odp['document_id'] if odp.get('success') else odp['message'])

JavaScript

const auth = {
  login: 'jan@firma.pl',
  password: 'twoje-haslo',
  webkey: 'a4c4dcf4c0280f1d2e6f3ac1fe43f8e9',
};

const odp = await fetch('https://mobilna-faktura.pl/panel/api/v1/documents', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    ...auth,
    document: {
      numer_dokumentu: 'FV/2026/08/0042',
      typ_dokumentu: 1,
      data_wystawienia: '16-08-2026',
      na_nazwa: 'ACME Sp. z o.o.',
      na_nip: '1234563218',
      products: [
        { nazwa: 'Usluga', amount: 1, cena: 1000,
          cena2: 1230, stawka_vat: '23', jednostki: 'szt.' },
      ],
    },
  }),
}).then(r => r.json());

console.log(odp.success ? odp.document_id : odp.message);

cURL — pobranie listy kontrahentów

curl "https://mobilna-faktura.pl/panel/api/v1/clients?login=jan@firma.pl&password_md5=<md5>&webkey=<klucz>"

⚠️ Ważne: daty przekazuj w formacie dd-mm-rrrr. Pola pozycji akceptują też warianty z przedrostkiem product_ (product_nazwa, product_cena) — dla zgodności z API SOAP.


Dokumentacja szczegółowa w panelu

Po zalogowaniu, w Ustawienia → Integracje → Dokumentacja API (REST) znajdziesz opis każdego endpointu wraz z listą parametrów, przykładowymi odpowiedziami i gotową klasą pomocniczą w PHP.


Webhooki (powiadomienia w drugą stronę)

REST API działa na zasadzie odpytywania — to Twój system pyta, czy coś się zmieniło. Odwrotny kierunek zapewniają webhooki: Mobilna Faktura sama powiadamia Twój endpoint, gdy wystawisz fakturę, klient ją opłaci albo dodasz kontrahenta.

Powiadomienia są podpisane (HMAC-SHA256), ponawiane przy błędach i rejestrowane w dzienniku dostaw. Konfiguracja: Ustawienia → Integracje → Zdarzenia biznesowe (webhooki).

Pełny opis: Webhooki — powiadomienia o zdarzeniach w czasie rzeczywistym

Webhooki wymagają pakietu MAX.


Wersjonowanie

Adresy zawierają numer wersji (/api/v1/...). Zmiany łamiące zgodność trafią do kolejnej wersji (v2) — wersja v1 pozostanie dostępna, więc istniejące integracje nie przestaną działać z dnia na dzień.


Korzyści

  • Pełna kontrola integracji custom (zamiast ograniczeń wtyczek)
  • Standard REST + JSON — łatwe dla każdego dewelopera
  • Webhooki — powiadomienia push zamiast odpytywania
  • Dokumentacja w panelu z przykładami dla każdego endpointu
  • Wsparcie profili firm — jedno konto, wiele podmiotów