# nipdata.pl — Dokumentacja REST API

**Wersja:** 0.2.0 (Faza 1 MVP)  
**Data:** maj 2026  
**Środowisko:** produkcyjne, https://api.nipdata.pl  
**Kontakt techniczny:** _<uzupełnij — np. tech@2secure.pl>_

---

## Spis treści

1. [Wprowadzenie](#1-wprowadzenie)
2. [Quick Start](#2-quick-start)
3. [Środowiska i base URL](#3-środowiska-i-base-url)
4. [Autoryzacja](#4-autoryzacja)
5. [Endpointy](#5-endpointy)
   - [GET /v1/company/{nip}](#51-get-v1companynip)
   - [GET /v1/health](#52-get-v1health)
   - [GET /v1/ready](#53-get-v1ready)
   - [GET /v1/version](#54-get-v1version)
6. [Schemat odpowiedzi: `CompanyData`](#6-schemat-odpowiedzi-companydata)
7. [Kody błędów](#7-kody-błędów)
8. [Walidacja NIP](#8-walidacja-nip)
9. [Wydajność i limity](#9-wydajność-i-limity)
10. [Logowanie zgodności (compliance)](#10-logowanie-zgodności-compliance)
11. [Roadmap](#11-roadmap)
12. [Przykłady kodu](#12-przykłady-kodu)
13. [FAQ](#13-faq)

---

## 1. Wprowadzenie

**nipdata.pl** to REST API do weryfikacji polskich firm po numerze NIP. Łączy dane z dwóch źródeł:

- **GUS BIR1.1** — rejestr REGON (nazwa firmy, REGON, adres siedziby, forma prawna, status działalności)
- **Biała Lista podatników VAT (Ministerstwo Finansów)** — status VAT, rachunki bankowe zgłoszone do KAS, `requestId` jako urzędowy dowód weryfikacji

Jedno wywołanie `GET /v1/company/{nip}` zwraca znormalizowaną, połączoną odpowiedź z obu źródeł. API wywołuje GUS i Białą Listę **równolegle**, łącząc wyniki przed odesłaniem klientowi.

**Zastosowania:**
- Weryfikacja kontrahenta przy rejestracji w aplikacji
- Auto-uzupełnianie danych do faktury (nazwa, adres, REGON)
- Weryfikacja statusu VAT i rachunku bankowego (split payment, należyta staranność)
- Rejestracja dowodu weryfikacji w logach zgodności (KAS `requestId`)

---

## 2. Quick Start

### Krok 1: Uzyskaj token

Token bearer otrzymuje się od administratora nipdata.pl. To jeden statyczny ciąg, np. `-vxBMNkwNozPx-2uTR8XI0soD-tgTHXqK0hbNHfYYfA` (43 znaki, base64-url-safe).

Przechowuj token jako **secret** (zmienna środowiskowa, secret manager — nigdy w repozytorium kodu).

### Krok 2: Pierwszy request

```bash
curl -H "Authorization: Bearer <TWOJ_TOKEN>" \
     https://api.nipdata.pl/v1/company/5252344078
```

Powinieneś otrzymać HTTP 200 z danymi firmy Google Poland.

### Krok 3: Parsuj odpowiedź

Odpowiedź to JSON zgodny ze schematem [`CompanyData`](#6-schemat-odpowiedzi-companydata). Najważniejsze pola:

```javascript
data.name                  // nazwa firmy
data.regon                 // REGON
data.address.city          // miasto
data.vat.status            // "czynny" | "zwolniony" | "niezarejestrowany"
data.vat.bank_accounts     // ["IBAN1", "IBAN2", ...]
data.vat.request_id        // dowód weryfikacji MF — zachowaj w logu compliance
```

---

## 3. Środowiska i base URL

| Środowisko | Base URL | Status |
|---|---|---|
| **Produkcja** | `https://api.nipdata.pl` | live |
| Sandbox | _w opracowaniu_ | — |

Wszystkie endpointy dostępne są **wyłącznie po HTTPS** (TLS 1.2+, certyfikat Let's Encrypt). Próby połączenia po HTTP są przekierowywane na HTTPS (HTTP 301).

API obsługuje wyłącznie **JSON** (request body — n/d, response — `Content-Type: application/json; charset=utf-8`).

Schemat URL endpointu danych firmowych:
```
https://api.nipdata.pl/v1/company/{nip}
└────────────────────┘ └┘ └─────┘ └─┘
        host           v1   res    id
```

---

## 4. Autoryzacja

API używa schematu **HTTP Bearer Authentication** (RFC 6750).

**W każdym chronionym żądaniu** dodaj nagłówek:

```http
Authorization: Bearer <TWOJ_TOKEN>
```

### Endpointy publiczne (bez tokenu)

Trzy endpointy są celowo publiczne — używają ich systemy monitoringu i load balancery:

- `GET /v1/health` — liveness probe
- `GET /v1/ready` — readiness probe (status DB i adapterów)
- `GET /v1/version` — wersja API
- `GET /docs` — interaktywna dokumentacja Swagger UI
- `GET /openapi.json` — schemat OpenAPI 3.0

### Błędy autoryzacji

| Sytuacja | HTTP | `error.code` |
|---|---|---|
| Brak nagłówka `Authorization` | **401** | `missing_bearer_token` |
| Nagłówek obecny ale token nie pasuje | **401** | `invalid_token` |

Każda odpowiedź 401 zawiera nagłówek `WWW-Authenticate: Bearer realm="nipdata.pl"`.

### Bezpieczeństwo

- Token jest **statyczny** — nie ma TTL, nie wymaga odświeżania.
- Wycieki: skontaktuj się z administratorem; rotacja zajmuje ~30 sekund (zmiana w `.env` + restart kontenera).
- W planie (Faza 2): per-organizacja klucze z bazy + audit log per call + rate limiting per-key.

---

## 5. Endpointy

### 5.1 GET /v1/company/{nip}

Pobiera znormalizowane dane firmy łącząc równolegle GUS i Białą Listę.

**Auth:** wymagana (Bearer)

**Path params:**

| Parametr | Typ | Opis |
|---|---|---|
| `nip` | string, 10 cyfr | NIP polski. Spacje, myślniki i prefix `PL` są ignorowane (np. `525-234-40-78`, `PL5252344078` i `5252344078` są równoważne). |

**Query params:** brak.

**Headers:**
```http
Authorization: Bearer <TWOJ_TOKEN>
Accept: application/json
```

**Przykład request:**
```bash
curl -H "Authorization: Bearer <TWOJ_TOKEN>" \
     https://api.nipdata.pl/v1/company/5252344078
```

**Przykład odpowiedzi (HTTP 200):**
```json
{
  "nip": "5252344078",
  "regon": "140182840",
  "krs": "0000240611",
  "name": "GOOGLE POLAND SPÓŁKA Z OGRANICZONĄ ODPOWIEDZIALNOŚCIĄ",
  "legal_form": "Osoba prawna",
  "legal_form_code": "OSP",
  "address": {
    "street": "Rondo Ignacego Daszyńskiego",
    "building_no": "2C",
    "apartment_no": null,
    "postal_code": "00-843",
    "city": "Warszawa",
    "voivodeship": "MAZOWIECKIE",
    "country": "PL"
  },
  "pkd": [],
  "registration_date": "2005-10-06",
  "status": "aktywna",
  "vat": {
    "status": "czynny",
    "bank_accounts": [
      "93103015080000000504162006",
      "37103015080000000504162044",
      "34103015080000000504162001"
    ],
    "request_id": "bZMVJ-976hcnb",
    "checked_for_date": "2026-05-04"
  },
  "sources": ["gus", "biala_lista"],
  "fetched_at": "2026-05-04T12:38:12.035845Z",
  "cache_hit": false
}
```

**Możliwe odpowiedzi:**

| HTTP | Sytuacja | `error.code` |
|---|---|---|
| 200 | OK — firma znaleziona w przynajmniej jednym źródle | — |
| 401 | brak/niepoprawny token | `missing_bearer_token` / `invalid_token` |
| 404 | NIP poprawny ale firma nie istnieje w GUS i Białej Liście | `not_found` |
| 422 | NIP nie ma poprawnej sumy kontrolnej | `invalid_nip` |
| 502 | wszystkie źródła zewnętrzne niedostępne | `all_sources_unavailable` |
| 504 | timeout (GUS lub BL przekroczyły 30 s) | `gateway_timeout` |

**Pola w odpowiedzi:** zob. sekcję [`CompanyData`](#6-schemat-odpowiedzi-companydata).

**Uwagi:**
- Pola `null` lub puste tablice (`[]`) są pomijane w odpowiedzi (`response_model_exclude_none=True`).
- Każde wywołanie zapisuje immutable **snapshot** danych w bazie nipdata (do historii i audytu — pole `request_id` z BL jest dowodem KAS).
- `sources` mówi które źródło faktycznie odpowiedziało. Możliwe wartości: `["gus","biala_lista"]`, `["gus"]` (BL padło), `["biala_lista"]` (GUS padło). Jedno źródło wystarczy do HTTP 200 — brak obu daje HTTP 404 lub 502.

---

### 5.2 GET /v1/health

Liveness probe. Zawsze HTTP 200 jeśli proces FastAPI żyje. Nie sprawdza zależności.

**Auth:** brak.

**Request:**
```bash
curl https://api.nipdata.pl/v1/health
```

**Response (HTTP 200):**
```json
{ "status": "ok" }
```

Używaj jako kontrola "czy serwer w ogóle odpowiada" (np. uptime monitoring).

---

### 5.3 GET /v1/ready

Readiness probe. Sprawdza dostępność bazy PostgreSQL i wszystkich adapterów (GUS, Biała Lista, VIES, KRS, CEIDG).

**Auth:** brak.

**Request:**
```bash
curl https://api.nipdata.pl/v1/ready
```

**Response (HTTP 200):**
```json
{
  "status": "ok",
  "db": true,
  "adapters": {
    "gus": true,
    "biala_lista": true,
    "vies": false,
    "krs": false,
    "ceidg": false
  },
  "environment": "production",
  "gus_environment": "production"
}
```

**Pola:**

| Pole | Typ | Opis |
|---|---|---|
| `status` | string | `ok` jeśli DB i kluczowe adaptery działają, `degraded` w przeciwnym razie |
| `db` | boolean | czy połączenie z PostgreSQL działa |
| `adapters.gus` | boolean | czy klucz GUS jest skonfigurowany (sprawdzenie statyczne) |
| `adapters.biala_lista` | boolean | aktywny probe API MF (timeout 5 s) |
| `adapters.vies` / `krs` / `ceidg` | boolean | `false` w MVP — adaptery w roadmapie |
| `environment` | string | `production` lub `staging` |
| `gus_environment` | string | `production` lub `test` |

`status: "degraded"` może oznaczać częściową niedostępność, ale endpoint główny dalej może odpowiadać (np. tylko jedno źródło padło).

---

### 5.4 GET /v1/version

Zwraca wersję API. Używana do debugowania.

**Auth:** brak.

**Response (HTTP 200):**
```json
{ "version": "0.2.0", "api_version": "v1" }
```

`api_version` to prefix URL (zawsze `v1` w ramach tej dokumentacji). `version` to wersja kodu — bumpowana przy każdym deployu.

---

## 6. Schemat odpowiedzi: `CompanyData`

Główny model zwracany przez `/v1/company/{nip}`. Wszystkie pola są opcjonalne (`null` / brak), z wyjątkiem oznaczonych jako **wymagane**.

```typescript
{
  nip:                string                  // wymagane, 10 cyfr
  regon:              string | null           // 9 lub 14 cyfr
  krs:                string | null           // 10 cyfr (z wiodącymi zerami)
  name:               string | null           // pełna nazwa firmy (z GUS lub BL)
  short_name:         string | null           // krótka nazwa — puste w MVP
  legal_form:         string | null           // np. "Osoba prawna"
  legal_form_code:    string | null           // "OSP" | "JDG" | "JL_P" | "JL_F"
  
  address: {
    street:           string | null
    building_no:      string | null
    apartment_no:     string | null
    postal_code:      string | null           // format "00-843"
    city:             string | null
    voivodeship:      string | null           // np. "MAZOWIECKIE"
    country:          string                   // domyślnie "PL"
  } | null
  
  pkd: [                                       // puste w MVP, dorzucone w kolejnej iteracji
    {
      code:           string                   // np. "73.11.Z"
      description:    string
      is_main:        boolean
    }
  ]
  
  registration_date:  string | null            // format ISO "YYYY-MM-DD"
  suspension_date:    string | null
  dissolution_date:   string | null
  status:             string | null            // "aktywna" | "zakończona"
  
  vat: {
    status:           "czynny" | "zwolniony" | "niezarejestrowany"   // wymagane
    bank_accounts:    string[]                 // lista IBAN-ów (26 cyfr)
    request_id:       string | null            // dowód weryfikacji MF (KLUCZOWE — zapisz!)
    checked_for_date: string                   // wymagane, format "YYYY-MM-DD"
  } | null
  
  vies_valid:         boolean | null           // Faza 1+ (VAT-UE)
  vies_checked_at:    string | null            // ISO timestamp
  
  krs_info: {                                  // Faza 1+ (KRS API)
    krs:              string
    legal_form:       string | null
    capital_grosze:   number | null
    board:            BoardMember[]
    partners:         Partner[]
    representation_rules: string | null
  } | null
  
  ceidg_active:       boolean | null           // Faza 1+
  
  sources:            string[]                 // wymagane, np. ["gus", "biala_lista"]
  fetched_at:         string                   // wymagane, ISO timestamp UTC
  cache_hit:          boolean                  // wymagane, czy dane z cache
}
```

### Typy zagnieżdżone

**`BoardMember`** (członek zarządu — KRS, Faza 1+):
```typescript
{ name: string, surname: string, function: string, appointed_at: string | null, revoked_at: string | null }
```

**`Partner`** (wspólnik — KRS, Faza 1+):
```typescript
{ name: string | null, surname: string | null, company_name: string | null, shares: string | null }
```

### Kodowanie formy prawnej (`legal_form_code`)

| Kod | Pełna nazwa (`legal_form`) | Pochodzenie |
|---|---|---|
| `OSP` | Osoba prawna | sp. z o.o., S.A., spółdzielnia, fundacja, etc. |
| `JDG` | Jednoosobowa działalność gospodarcza | osoba fizyczna prowadząca DG |
| `JL_P` | Jednostka lokalna osoby prawnej | oddział, filia spółki |
| `JL_F` | Jednostka lokalna osoby fizycznej | oddział JDG |

Bardziej szczegółowa forma prawna (np. "SPÓŁKA Z OGRANICZONĄ ODPOWIEDZIALNOŚCIĄ") będzie dostępna po rozszerzeniu adaptera GUS o pełny raport (kolejna iteracja).

---

## 7. Kody błędów

Wszystkie błędy zwracają jednolity format:

```json
{
  "detail": {
    "error": {
      "code": "<machine_readable_code>",
      "message": "<human_readable_message_pl>"
    }
  }
}
```

### Pełna lista kodów

| HTTP | `code` | Komunikat | Kiedy |
|---|---|---|---|
| **400** | (FastAPI default) | Validation error | NIP w URL nie pasuje do regex `^[0-9-]{10,13}$` |
| **401** | `missing_bearer_token` | Brak nagłówka Authorization: Bearer <token> | brak nagłówka `Authorization` |
| **401** | `invalid_token` | Nieprawidłowy bearer token | token obecny ale nie pasuje |
| **404** | `not_found` | Firma o NIP X nie istnieje w GUS ani Białej Liście | NIP poprawny syntactic + checksum, ale nie znaleziono |
| **422** | `invalid_nip` | NIP X ma nieprawidłową sumę kontrolną | NIP nie przechodzi walidacji checksum |
| **502** | `all_sources_unavailable` | GUS i Biała Lista niedostępne | oba zewnętrzne API padły lub timeout |
| **504** | `gateway_timeout` | Timeout — GUS lub Biała Lista przekroczyły 30 s | rzadkie, zwykle awaria po stronie MF/GUS |

### Strategia retry

| HTTP | Retry? | Backoff |
|---|---|---|
| 401, 422, 404 | **NIE** | błąd po stronie klienta |
| 502, 504 | **TAK** | exponential, max 3 próby (np. 1s → 3s → 9s) |
| 5xx inne | **TAK** | jak wyżej |

---

## 8. Walidacja NIP

NIP jest walidowany dwustopniowo:

1. **Format**: regex `^[0-9-]{10,13}$` (10 cyfr ± do 3 myślników, np. `525-234-40-78`).
2. **Checksum**: standardowy polski algorytm sumy kontrolnej:

```
weights = [6, 5, 7, 2, 3, 4, 5, 6, 7]
checksum = sum(NIP[i] * weights[i] for i in 0..8) mod 11
NIP jest poprawny ⟺ checksum != 10 AND checksum == NIP[9]
```

Niepoprawny NIP daje **HTTP 422** zanim API w ogóle odpyta GUS lub Białą Listę (chroni przed marnowaniem zewnętrznych quot).

API akceptuje też prefix `PL` (`PL5252344078`) — jest automatycznie usuwany.

---

## 9. Wydajność i limity

### Latencja

| Scenariusz | Typowa latencja | Komentarz |
|---|---|---|
| Pierwsze wywołanie po starcie procesu | ~700 ms | login GUS + równoległy fetch BL |
| Kolejne wywołania (sesja GUS aktywna) | **~600-700 ms** | równoległy fetch GUS+BL |
| Cache HIT (Faza 1+) | _<50 ms_ | po wdrożeniu cache PostgreSQL |
| Niepoprawny NIP (HTTP 422) | <50 ms | bez wywołań zewnętrznych |
| Firma nieznana (HTTP 404) | ~600 ms | pełen fetch wykonany, brak danych |

### Limity zewnętrzne (warto znać)

- **GUS BIR1.1** — bezpłatny, bez ograniczeń ilościowych (wymagana sesja, sesja wygasa po 60 min bezczynności — zarządzane automatycznie przez nipdata).
- **Biała Lista MF** — 10 req/s **per IP**. Powyżej tej granicy MF zwraca HTTP 429; nipdata przekazuje to jako 502 z `error.code=all_sources_unavailable` (ale GUS może wciąż odpowiedzieć).

### Limity nipdata.pl (Faza 1)

W tej fazie **brak rate limitingu po stronie nipdata** (zaufanie do bearer token + monitoring). W Fazie 2 zostaną wprowadzone limity per-token.

### Timeouts

- httpx → GUS: 30 s
- httpx → Biała Lista: 15 s
- Klient powinien ustawić timeout **≥ 35 s** żeby nie ucinać requestów które nipdata jeszcze obsługuje.

---

## 10. Logowanie zgodności (compliance)

`vat.request_id` to **unikalny identyfikator zapytania nadany przez Białą Listę MF**. Zachowanie go w bazie 2SECURE jest dowodem że weryfikacja kontrahenta miała miejsce — może być przedstawiony przy ewentualnej kontroli KAS jako element należytej staranności.

**Zalecany schemat zapisu w bazie kontrahenta:**

```sql
CREATE TABLE contractor_verifications (
  id              SERIAL PRIMARY KEY,
  contractor_nip  VARCHAR(10) NOT NULL,
  vat_status      VARCHAR(32) NOT NULL,         -- "czynny" / "zwolniony" / "niezarejestrowany"
  vat_request_id  VARCHAR(32),                  -- ← klucz: dowód MF
  bank_accounts   JSONB,                        -- snapshot rachunków na moment weryfikacji
  checked_for_date DATE NOT NULL,
  verified_at     TIMESTAMPTZ DEFAULT NOW(),
  source          VARCHAR(32) DEFAULT 'nipdata.pl'
);
```

Zapisuj rekord **przy każdym wywołaniu** które kończy się 200 OK, niezależnie od tego czy używasz danych do faktury, czy do procesu wewnętrznego. To minimalny narzut a zapewnia ślad audytowy.

---

## 11. Roadmap

| Faza | Zakres | Termin |
|---|---|---|
| **MVP / Faza 1** | GUS basic + Biała Lista, bearer auth | **gotowe (maj 2026)** |
| Faza 1+ | PKD + pełne pola GUS (`DanePobierzPelnyRaport`) | kolejna iteracja |
| Faza 1+ | Cache PostgreSQL UNLOGGED (~50 ms dla powtórek) | kolejna iteracja |
| Faza 1+ | Endpoint `/v1/iban/check?nip=&iban=&date=` (weryfikacja konkretnego rachunku) | na żądanie |
| Faza 1+ | VIES (VAT-UE) — `vies.valid`, `vies.trader_name` | po cache |
| Faza 2 | Per-organizacja klucze API + audit log + rate limit per-key | Q3 2026 |
| Faza 2 | Webhooks (zmiana statusu VAT, wykreślenie z BL) | Q3 2026 |
| Faza 2 | KRS API — zarząd, wspólnicy, kapitał | Q3 2026 |
| Faza 3 | History point-in-time (`/v1/company/{nip}/history?at=`) | Q4 2026 |
| Faza 3 | Raport PDF z pieczęcią PAdES (z archiwumpodpisu.pl) | Q4 2026 |

---

## 12. Przykłady kodu

### 12.1 PHP

```php
<?php
$nip = '5252344078';
$token = getenv('NIPDATA_TOKEN');

$ch = curl_init("https://api.nipdata.pl/v1/company/{$nip}");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER     => ["Authorization: Bearer {$token}"],
    CURLOPT_TIMEOUT        => 35,
    CURLOPT_CONNECTTIMEOUT => 10,
]);
$body   = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

if ($status === 200) {
    $d = json_decode($body, true);
    echo "Firma: {$d['name']}\n";
    echo "REGON: {$d['regon']}\n";
    echo "VAT: {$d['vat']['status']}\n";
    echo "Konta na BL: " . count($d['vat']['bank_accounts']) . "\n";
    echo "request_id (zapisz!): {$d['vat']['request_id']}\n";
} elseif ($status === 404) {
    echo "Brak firmy o tym NIP w GUS/BL\n";
} elseif ($status === 422) {
    echo "Niepoprawny NIP (suma kontrolna)\n";
} else {
    $err = json_decode($body, true);
    echo "Błąd HTTP {$status}: {$err['detail']['error']['message']}\n";
}
```

### 12.2 Python (httpx)

```python
import httpx
import os
from typing import Optional

NIPDATA_TOKEN = os.environ["NIPDATA_TOKEN"]


def get_company(nip: str) -> Optional[dict]:
    """Zwraca dane firmy lub None gdy NIP poprawny ale firma nieznana."""
    response = httpx.get(
        f"https://api.nipdata.pl/v1/company/{nip}",
        headers={"Authorization": f"Bearer {NIPDATA_TOKEN}"},
        timeout=35.0,
    )
    if response.status_code == 422:
        raise ValueError(f"Niepoprawny NIP: {nip}")
    if response.status_code == 404:
        return None
    response.raise_for_status()
    return response.json()


# Użycie
data = get_company("5252344078")
if data:
    print(f"Firma: {data['name']}")
    print(f"VAT status: {data['vat']['status']}")
    print(f"Rachunki: {data['vat']['bank_accounts']}")
    print(f"Dowód weryfikacji (request_id): {data['vat']['request_id']}")
```

### 12.3 Python (requests)

```python
import requests, os

resp = requests.get(
    "https://api.nipdata.pl/v1/company/5252344078",
    headers={"Authorization": f"Bearer {os.environ['NIPDATA_TOKEN']}"},
    timeout=35,
)
resp.raise_for_status()
data = resp.json()
```

### 12.4 JavaScript (Node.js, fetch)

```javascript
const NIPDATA_TOKEN = process.env.NIPDATA_TOKEN;

async function getCompany(nip) {
    const response = await fetch(
        `https://api.nipdata.pl/v1/company/${nip}`,
        {
            headers: { 'Authorization': `Bearer ${NIPDATA_TOKEN}` },
            signal: AbortSignal.timeout(35_000),
        }
    );
    if (response.status === 404) return null;
    if (response.status === 422) throw new Error('Niepoprawny NIP');
    if (!response.ok) throw new Error(`HTTP ${response.status}`);
    return await response.json();
}

const data = await getCompany('5252344078');
console.log(data.name, data.vat.status);
```

### 12.5 cURL — szybki sanity check

```bash
# GET dane firmy
curl -H "Authorization: Bearer $NIPDATA_TOKEN" \
     https://api.nipdata.pl/v1/company/5252344078 | jq

# Health (publiczne)
curl https://api.nipdata.pl/v1/ready | jq

# Test 422 — niepoprawny NIP
curl -i -H "Authorization: Bearer $NIPDATA_TOKEN" \
     https://api.nipdata.pl/v1/company/1234567890

# Test 401 — brak tokenu
curl -i https://api.nipdata.pl/v1/company/5252344078
```

---

## 13. FAQ

**Q: Czy mogę odpytywać API z przeglądarki (frontend)?**  
A: Nie zalecane. CORS jest zamknięty, plus token byłby w kodzie klienta = wyciek. Wywołuj zawsze z backendu.

**Q: Co jeśli oba źródła (GUS i BL) padną jednocześnie?**  
A: HTTP 502 z `error.code=all_sources_unavailable`. To rzadkie — w praktyce GUS i BL nie padają w tym samym czasie. Zaleca się retry z exponential backoff.

**Q: Czy `vat.bank_accounts` są zawsze aktualne?**  
A: Tak — pochodzą z aktualnego stanu Białej Listy MF na dzień `vat.checked_for_date` (= dzisiaj UTC). API odpytuje BL przy każdym wywołaniu (do czasu wdrożenia cache).

**Q: Co jeśli firma została wykreślona z REGON, ale GUS jeszcze ją zwraca?**  
A: Pole `dissolution_date` będzie ustawione, a `status: "zakończona"`. Nie filtruj zakończonych po stronie API — niech klient zdecyduje (czasem trzeba pokazać historyczne dane do faktury z przeszłości).

**Q: Czy API działa dla NIP-ów osób fizycznych (JDG)?**  
A: Tak. Pole `legal_form_code` będzie wówczas `JDG`, a niektóre pola zarządu/wspólników (które nie dotyczą JDG) będą puste. Adres siedziby = adres działalności gospodarczej.

**Q: Czy mogę testować bez tokenu?**  
A: Endpointy publiczne (`/v1/health`, `/v1/ready`, `/v1/version`, `/docs`) — tak. Główny endpoint `/v1/company/{nip}` — wymaga tokenu.

**Q: Jak otrzymać Swagger UI?**  
A: https://api.nipdata.pl/docs — interaktywna dokumentacja. Wpisz tam token w "Authorize" raz i możesz testować endpointy z przeglądarki.

**Q: Jakie polskie podmioty obsługujecie?**  
A: Wszystkie zarejestrowane w REGON (firmy, JDG, fundacje, stowarzyszenia, urzędy, kościoły) — to ~6 mln podmiotów.

---

**Wersja dokumentacji:** 1.0  
**Wygenerowana:** 2026-05-04  
**Zwróć uwagę:** dokument dotyczy API v0.2.0. Sprawdź `GET /v1/version` dla aktualnej wersji deploya.
