Uwierzytelnianie
API Fakturnia korzysta z uwierzytelniania w modelu OAuth 2.0 client credentials. Aplikacja wymienia parę client_id / client_secret na krótko żyjący token Bearer (JWT), a następnie dołącza ten token do każdego żądania.
REST API wymaga planu MAX. Konta API, wszystkie endpointy
/external/v1i webhooki są modułem planu MAX. Bez aktywnego planu endpoint tokenu odpowiada403zerror: "access_denied"ierror_code: "SUBSCRIPTION_REQUIRED", a wywołanie z tokenem wydanym wcześniej kończy się403 SUBSCRIPTION_REQUIRED. Po wygaśnięciu planu integracja przestaje działać do czasu jego przedłużenia; webhooki nie są wtedy wysyłane. Konta pracownicze i uprawnienia w aplikacji nie mają na to wpływu: token działa zawsze jako właściciel konta.
Uzyskiwanie poświadczeń
Utwórz aplikację API w sekcji Inne → Integracje → REST API. Każda aplikacja posiada:
client_id(publiczny identyfikator, np.client_5c62e069…),client_secret(sekret, przechowuj go wyłącznie po stronie serwera),- zestaw uprawnień scope, które ograniczają zakres działań aplikacji.
Możesz prowadzić wiele aplikacji (np. po jednej na każdą integrację) i niezależnie unieważniać dowolną z nich. Unieważnienie działa natychmiast: tokeny wydane wcześniej dostają 401 UNAUTHORIZED przy kolejnym wywołaniu, nie dopiero po wygaśnięciu. Dla aplikacji możesz też ustawić listę dozwolonych adresów IP; wywołanie z innego adresu kończy się 403 FORBIDDEN.
Dane API są przypisane do środowiska. Poświadczenia z środowiska testowego (
https://sandbox.app.fakturnia.pl) działają wyłącznie wobechttps://sandbox.api.fakturnia.pl, a poświadczenia produkcyjne wyłącznie wobechttps://prod.api.fakturnia.pl. Zacznij od sandboxa, a na produkcję przełącz się dopiero po przetestowaniu integracji.
Żądanie tokenu
curl -s https://prod.api.fakturnia.pl/v1/oauth/token \
-H "Content-Type: application/json" \
-d '{ "grant_type": "client_credentials", "client_id": "...", "client_secret": "..." }'
{ "access_token": "eyJ…", "token_type": "Bearer", "expires_in": 3600, "scope": "documents:create documents:read" }
Tokeny są ważne przez expires_in sekund. Buforuj i ponownie wykorzystuj token aż do momentu zbliżającego się wygaśnięcia, zamiast żądać nowego przy każdym wywołaniu. Po wygaśnięciu API odpowiada 401 TOKEN_EXPIRED: pobierz nowy token i ponów żądanie.
Endpoint tokenu odpowiada zgodnie z OAuth 2.0: 400 invalid_request / unsupported_grant_type przy błędnym żądaniu, 401 invalid_client przy błędnych danych (bez rozróżniania, czy client_id istnieje), 403 access_denied z error_code: "SUBSCRIPTION_REQUIRED" bez planu MAX oraz 403 access_denied bez error_code, gdy żądanie przychodzi z adresu IP spoza listy dozwolonych dla aplikacji.
let cached: { token: string; exp: number } | null = null;
async function getToken(): Promise<string> {
const now = Date.now();
if (cached && cached.exp - now > 60_000) return cached.token;
const res = await fetch('https://prod.api.fakturnia.pl/v1/oauth/token', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
grant_type: 'client_credentials',
client_id: process.env.FAKTURNIA_CLIENT_ID,
client_secret: process.env.FAKTURNIA_CLIENT_SECRET,
}),
});
const json = await res.json();
cached = { token: json.access_token, exp: now + json.expires_in * 1000 };
return cached.token;
}
Używanie tokenu
Authorization: Bearer <access_token>
Brakujący lub nieprawidłowy token zwraca 401 z kodem UNAUTHORIZED, wygasły 401 TOKEN_EXPIRED. Prawidłowy token bez wymaganego zakresu uprawnień scope zwraca 403 z kodem NO_PERMISSIONS, a errors[0] mówi, którego scope brakuje. Kolejność sprawdzeń: token, stan konta API, adres IP (lista dozwolonych), plan MAX, dopiero potem scope.
Zakresy uprawnień (scope)
Każdy punkt końcowy deklaruje wymagany przez siebie scope. Żądaj wyłącznie tych zakresów uprawnień, których potrzebuje Twoja integracja.
| Zasób | Zakresy (scope) |
|---|---|
| Dokumenty | documents:browse · documents:read · documents:create · documents:update · documents:delete · documents:download · documents:send-to-ksef · documents:update-payment-status · documents:update-external-reference |
| Klienci | clients:browse · clients:read · clients:create · clients:update · clients:delete |
| Produkty | products:browse · products:read · products:create · products:update · products:delete |
| Magazyn | warehouse:browse · warehouse:create · warehouse:update · warehouse:delete · warehouse:stock:read · warehouse:adjust · warehouse:wz:create · warehouse:documents:create |
| Pracownicy | employees:browse · employees:create · employees:update · employees:delete |
| Dokumenty cykliczne | recurring:browse · recurring:read · recurring:toggle |
| KSeF | ksef:read · ksef:configure · ksef:test |
| Ustawienia | settings:read · settings:update |
| Webhooki | webhooks:read · webhooks:create · webhooks:update · webhooks:delete |
| Konta pocztowe | email-accounts:browse · email-accounts:read |
| Aktywność | activity:read |
| Firma | gus:company:read |
Dokładny scope dla każdego punktu końcowego jest podany w dokumentacji API.
Lista kontrolna bezpieczeństwa
- Przechowuj
client_secretpo stronie serwera. Nigdy nie umieszczaj go w przeglądarkach, aplikacjach mobilnych ani publicznych repozytoriach. - Przechowuj tokeny w pamięci lub krótko żyjącym buforze. Wygasają one, więc ich długotrwałe utrwalanie zwiększa ryzyko bez żadnej korzyści.
- Używaj wyłącznie protokołu HTTPS. API odrzuca połączenia nieszyfrowane.
- Natychmiast rotuj sekret w przypadku jego wycieku (unieważnij aplikację i utwórz nową); unieważnienie odcina także tokeny już wydane.
- Ogranicz źródłowe adresy IP aplikacji, jeśli integracja działa z serwera o stałym adresie.
- Ograniczaj uprawnienia: integracja, która jedynie odczytuje dane, nie powinna posiadać
documents:create.
Sprawdzenie tokenu
GET /auth/me zwraca tożsamość oraz przyznane zakresy uprawnień powiązane z bieżącym tokenem. Użyj go po wdrożeniu integracji, żeby potwierdzić, że token działa i ma właściwe uprawnienia, albo przy debugowaniu, do której aplikacji należy dany token. Endpoint wymaga jedynie ważnego tokenu, bez dodatkowego scope'a.
curl -s https://prod.api.fakturnia.pl/external/v1/auth/me \
-H "Authorization: Bearer $TOKEN"
{
"success": true,
"data": {
"clientId": "507f1f77bcf86cd799439011",
"name": "Integracja z e-Sklepem",
"scopes": ["documents:read", "clients:browse"],
"userId": "507f1f77bcf86cd799439012"
}
}