{
  "openapi": "3.1.0",
  "info": {
    "title": "Generator danych testowych — API",
    "version": "1.0.0",
    "summary": "Fikcyjne polskie dane testowe (PESEL, NIP, REGON, IBAN, karta, VIN) i walidator.",
    "description": "Dane fikcyjne, wyłącznie do testów oprogramowania. Wszystkie liczby kontrolne są poprawne, a rekordy nie pochodzą z żadnej bazy osób (are not taken from any real-person database; a single random number may coincide with a real one). Numer telefonu jest losowy i może należeć do prawdziwej osoby — nie wysyłaj na niego SMS-ów i nie dzwoń (the phone number is random and may belong to a real person; never message or call it). Bez klucza API, limit 60 zapytań na minutę na adres IP. Instrukcja dla agentów AI: https://kmagdziarz.pl/narzedzia/generator/llms.txt"
  },
  "servers": [
    {
      "url": "https://kmagdziarz.pl"
    }
  ],
  "paths": {
    "/narzedzia/generator/api": {
      "get": {
        "operationId": "generateTestData",
        "summary": "Generuje fikcyjne rekordy danych testowych",
        "parameters": [
          {
            "name": "type",
            "in": "query",
            "description": "Rodzaj rekordu. Aliasy polskie: zbiorcze, osobowe, firmowe, bankowe, pojazdy.",
            "schema": {
              "type": "string",
              "enum": [
                "record",
                "person",
                "company",
                "bank",
                "vehicle"
              ],
              "default": "record"
            },
            "example": "person"
          },
          {
            "name": "count",
            "in": "query",
            "description": "Liczba rekordów (liczba całkowita 1–100).",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 1
            },
            "example": 10
          },
          {
            "name": "gender",
            "in": "query",
            "description": "Płeć osoby. Aliasy: K (female), M (male).",
            "schema": {
              "type": "string",
              "enum": [
                "any",
                "female",
                "male"
              ],
              "default": "any"
            }
          },
          {
            "name": "age",
            "in": "query",
            "description": "Przedział wieku osoby. Nie łącz z min_age/max_age.",
            "schema": {
              "type": "string",
              "enum": [
                "0-99",
                "0-17",
                "18-24",
                "25-65",
                "66-99"
              ],
              "default": "0-99"
            },
            "example": "25-65"
          },
          {
            "name": "min_age",
            "in": "query",
            "description": "Minimalny wiek (0–120). Nie łącz z age.",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "maximum": 120
            }
          },
          {
            "name": "max_age",
            "in": "query",
            "description": "Maksymalny wiek (0–120), nie mniejszy niż min_age. Nie łącz z age.",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "maximum": 120
            }
          },
          {
            "name": "regon",
            "in": "query",
            "description": "Długość numeru REGON firmy.",
            "schema": {
              "type": "string",
              "enum": [
                "9",
                "14"
              ],
              "default": "9"
            },
            "example": "14"
          },
          {
            "name": "card",
            "in": "query",
            "description": "Typ karty płatniczej.",
            "schema": {
              "type": "string",
              "enum": [
                "any",
                "visa",
                "mastercard"
              ],
              "default": "any"
            }
          },
          {
            "name": "seed",
            "in": "query",
            "description": "Ziarno losowania (0–2147483647). Ten sam seed w tym samym dniu UTC daje te same dane. Bez seeda wynik jest losowy, a użyty seed wraca w odpowiedzi.",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "maximum": 2147483647
            },
            "example": 1
          },
          {
            "name": "fields",
            "in": "query",
            "description": "Lista kluczy pól po przecinku (np. pesel,birthDate). Zwraca tylko te pola, w podanej kolejności. Nieznany klucz daje błąd 400 z listą dozwolonych.",
            "schema": {
              "type": "string"
            },
            "example": "pesel,birthDate"
          },
          {
            "name": "format",
            "in": "query",
            "description": "Format odpowiedzi. CSV ma BOM UTF-8, separator `;` i nagłówki z polskimi etykietami.",
            "schema": {
              "type": "string",
              "enum": [
                "json",
                "csv"
              ],
              "default": "json"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Rekordy danych testowych.",
            "headers": {
              "RateLimit-Limit": {
                "description": "Request limit per window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Reset": {
                "description": "Seconds until the oldest request leaves the window.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GenerateResponse"
                },
                "example": {
                  "type": "person",
                  "count": 1,
                  "seed": 1,
                  "generated_at": "2026-10-07T12:00:00.000Z",
                  "notice": "Dane fikcyjne, wyłącznie do testów oprogramowania.",
                  "items": [
                    {
                      "pesel": "90010112345",
                      "birthDate": "1990-01-01"
                    }
                  ]
                }
              },
              "text/csv": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "description": "Nieprawidłowy lub nieznany parametr.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Przekroczony limit zapytań; patrz nagłówek Retry-After.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/narzedzia/generator/api/validate": {
      "get": {
        "operationId": "validateIdentifier",
        "summary": "Sprawdza sumę kontrolną identyfikatora (GET, tylko do szybkich ręcznych prób)",
        "description": "Zalecany jest POST: wartość w adresie URL trafia do logów serwerów i proxy. Nie wysyłaj prawdziwych danych osobowych. Endpoint sprawdza tylko poprawność formalną (sumę kontrolną), nie istnienie numeru w rejestrze.",
        "parameters": [
          {
            "name": "type",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "enum": [
                "pesel",
                "nip",
                "regon",
                "iban",
                "card",
                "vin",
                "id_card",
                "passport"
              ]
            },
            "example": "nip"
          },
          {
            "name": "value",
            "in": "query",
            "required": true,
            "description": "Wartość do sprawdzenia (maks. 64 znaków).",
            "schema": {
              "type": "string",
              "maxLength": 64
            },
            "example": "1234563218"
          }
        ],
        "responses": {
          "200": {
            "description": "Wynik walidacji.",
            "headers": {
              "RateLimit-Limit": {
                "description": "Request limit per window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Reset": {
                "description": "Seconds until the oldest request leaves the window.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidateResponse"
                },
                "example": {
                  "type": "nip",
                  "valid": true,
                  "normalized": "1234563218"
                }
              }
            }
          },
          "400": {
            "description": "Brak lub nieprawidłowy parametr.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Przekroczony limit zapytań; patrz nagłówek Retry-After.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "validateIdentifierPost",
        "summary": "Sprawdza sumę kontrolną identyfikatora (zalecane)",
        "description": "Wartość jest w treści żądania, a nie w adresie URL, więc nie trafia do logów serwerów. Nie wysyłaj prawdziwych danych osobowych. Treść do 1 KB, Content-Type: application/json.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "type",
                  "value"
                ],
                "additionalProperties": false,
                "properties": {
                  "type": {
                    "type": "string",
                    "enum": [
                      "pesel",
                      "nip",
                      "regon",
                      "iban",
                      "card",
                      "vin",
                      "id_card",
                      "passport"
                    ]
                  },
                  "value": {
                    "type": "string",
                    "maxLength": 64
                  }
                }
              },
              "example": {
                "type": "nip",
                "value": "1234563218"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Wynik walidacji.",
            "headers": {
              "RateLimit-Limit": {
                "description": "Request limit per window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Reset": {
                "description": "Seconds until the oldest request leaves the window.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidateResponse"
                },
                "example": {
                  "type": "nip",
                  "valid": true,
                  "normalized": "1234563218"
                }
              }
            }
          },
          "400": {
            "description": "Zła treść, zły Content-Type, za duże żądanie lub nieprawidłowe pole.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Przekroczony limit zapytań; patrz nagłówek Retry-After.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "GenerateResponse": {
        "type": "object",
        "required": [
          "type",
          "count",
          "seed",
          "generated_at",
          "notice",
          "items"
        ],
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "record",
              "person",
              "company",
              "bank",
              "vehicle"
            ]
          },
          "count": {
            "type": "integer"
          },
          "seed": {
            "type": "integer"
          },
          "generated_at": {
            "type": "string",
            "format": "date-time"
          },
          "notice": {
            "type": "string"
          },
          "items": {
            "type": "array",
            "items": {
              "type": "object",
              "description": "Klucze pól (camelCase, ASCII) zależą od type i parametru fields.",
              "properties": {
                "phone": {
                  "type": "string",
                  "description": "Losowy numer telefonu; może należeć do prawdziwej osoby — nie wysyłaj SMS-ów i nie dzwoń. Random phone number that may belong to a real person; never message or call it."
                }
              },
              "additionalProperties": {
                "type": "string"
              }
            }
          }
        }
      },
      "ValidateResponse": {
        "type": "object",
        "required": [
          "type",
          "valid",
          "normalized"
        ],
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "pesel",
              "nip",
              "regon",
              "iban",
              "card",
              "vin",
              "id_card",
              "passport"
            ]
          },
          "valid": {
            "type": "boolean"
          },
          "normalized": {
            "type": "string"
          },
          "birth_date": {
            "type": "string",
            "format": "date",
            "description": "Tylko dla poprawnego PESEL."
          },
          "gender": {
            "type": "string",
            "enum": [
              "female",
              "male"
            ],
            "description": "Tylko dla poprawnego PESEL."
          }
        }
      },
      "Error": {
        "type": "object",
        "required": [
          "error",
          "message"
        ],
        "properties": {
          "error": {
            "type": "string"
          },
          "message": {
            "type": "string"
          },
          "allowed": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        }
      }
    }
  }
}