openapi: 3.0.3
info:
  title: Bazy.biz API
  version: "1.0"
  description: |
    Publiczne API serwisu Bazy.biz — monitoring nowych firm z CEIDG i KRS,
    szablony wyszukiwań. Autoryzacja kluczem Bearer (Sanctum) generowanym
    w panelu użytkownika (/panel/api). Pełna dokumentacja: https://bazy.biz/integracje-api
  contact:
    email: biuro@bazy.biz
servers:
  - url: https://bazy.biz/api/v1
security:
  - bearerAuth: []
paths:
  /me:
    get:
      summary: Weryfikacja klucza API
      description: Zwraca dane konta i informację o dostępie do monitoringu.
      responses:
        "200":
          description: OK
          content:
            application/json:
              schema:
                type: object
                properties:
                  id: { type: integer }
                  email: { type: string }
                  name: { type: string }
                  monitoring_access: { type: boolean }
        "401": { $ref: "#/components/responses/Unauthenticated" }
  /monitoring/search:
    post:
      summary: Wyszukiwanie nowych firm (CEIDG/KRS)
      description: >
        Wyszukuje firmy według filtrów. Wszystkie parametry opcjonalne —
        bez filtrów zwraca najnowsze wpisy. Limit 60 zapytań/min.
      requestBody:
        content:
          application/x-www-form-urlencoded:
            schema:
              $ref: "#/components/schemas/SearchFilters"
          application/json:
            schema:
              $ref: "#/components/schemas/SearchFilters"
      responses:
        "200":
          description: OK
          content:
            application/json:
              schema:
                type: object
                properties:
                  success: { type: boolean }
                  total: { type: integer }
                  page: { type: integer }
                  data:
                    type: array
                    items: { $ref: "#/components/schemas/Firm" }
        "401": { $ref: "#/components/responses/Unauthenticated" }
        "429": { description: Przekroczony limit zapytań }
  /monitoring/found:
    get:
      summary: Lista znalezionych firm
      description: Liczba i 10 ostatnich firm oznaczonych jako znalezione (deduplikacja).
      responses:
        "200": { description: OK }
  /monitoring/found/clear:
    post:
      summary: Czyści listę znalezionych firm
      responses:
        "200": { description: OK }
  /monitoring/found/{nip}:
    delete:
      summary: Usuwa firmę z listy znalezionych
      parameters:
        - name: nip
          in: path
          required: true
          schema: { type: string, pattern: "^[0-9]+$" }
      responses:
        "200": { description: OK }
  /monitoring/templates:
    get:
      summary: Lista szablonów wyszukiwań
      responses:
        "200": { description: OK }
    post:
      summary: Tworzy szablon wyszukiwania
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [name]
              properties:
                name: { type: string, maxLength: 120 }
                filters: { $ref: "#/components/schemas/SearchFilters" }
                is_alert_enabled: { type: boolean }
      responses:
        "201": { description: Utworzono }
  /monitoring/templates/{id}:
    patch:
      summary: Aktualizuje szablon
      parameters:
        - { name: id, in: path, required: true, schema: { type: integer } }
      responses:
        "200": { description: OK }
    delete:
      summary: Usuwa szablon
      parameters:
        - { name: id, in: path, required: true, schema: { type: integer } }
      responses:
        "200": { description: OK }
components:
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      description: Klucz API z panelu użytkownika (/panel/api).
  responses:
    Unauthenticated:
      description: Brak lub nieprawidłowy klucz API
  schemas:
    SearchFilters:
      type: object
      properties:
        imie: { type: string, description: "Imię właściciela (dopasowanie częściowe)" }
        nazwisko: { type: string }
        nip: { type: string, description: "NIP — zawsze string (zera wiodące)" }
        regon: { type: string }
        krs: { type: string }
        rejestr: { type: array, items: { type: string, enum: [CEIDG, KRS] } }
        status: { type: array, items: { type: string } }
        wojewodztwo: { type: array, items: { type: string } }
        powiat: { type: array, items: { type: string } }
        gmina: { type: string }
        miasto: { type: string, description: "Miasto lub lista po przecinku" }
        wyklucz_miasta: { type: string }
        kod: { type: string, description: "Kod pocztowy (prefiks)" }
        pkd_include: { type: array, items: { type: string }, description: "Kody PKD 2025 bez kropek, np. 4100A" }
        pkd_search_type: { type: string, enum: [glowny, all], default: glowny }
        contact_filter: { type: string, enum: [has_email, has_phone, has_both, has_any, no_email, no_phone] }
        start_date_from: { type: string, format: date }
        start_date_to: { type: string, format: date }
        reg_date_from: { type: string, format: date }
        reg_date_to: { type: string, format: date }
        only_new_firms: { type: boolean }
        exclude_previously_found: { type: boolean }
        page: { type: integer, minimum: 1, default: 1 }
        limit: { type: integer, minimum: 1, maximum: 2000, default: 20 }
        sort_by: { type: string }
        sort_dir: { type: string, enum: [asc, desc] }
    Firm:
      type: object
      properties:
        nazwa: { type: string }
        wlasciciel_nip: { type: string }
        wlasciciel_regon: { type: string }
        wlasciciel_imie: { type: string }
        wlasciciel_nazwisko: { type: string }
        status: { type: string }
        dataRozpoczecia: { type: string, format: date }
        adresDzialalnosci_miasto: { type: string }
        adresDzialalnosci_wojewodztwo: { type: string }
        telefon: { type: string }
        email: { type: string }
        pkdGlowny: { type: string }
        pkdGlownyNazwa: { type: string }
