{"openapi":"3.1.0","info":{"title":"Placenie API","version":"2026-10-03","summary":"REST API bramki płatniczej placenie.pl, wersja 1.","description":"API bramki płatniczej placenie.pl: tworzysz płatność, kierujesz klienta na `adres_platnosci`,\na wynik dostajesz webhookiem i możesz go w każdej chwili pobrać zapytaniem.\n\n## Podstawy\n- Adres bazowy: `https://placenie.pl/api`. Wszystkie ścieżki poniżej są względem niego (np. `POST https://placenie.pl/api/v1/platnosci`).\n- Uwierzytelnianie: nagłówek `Authorization: Bearer <klucz>`. Klucz testowy ma postać `plc_test_...`, produkcyjny `plc_live_...`.\n  Klucz testowy widzi wyłącznie transakcje testowe, produkcyjny wyłącznie produkcyjne. Klucze wydajesz w panelu (Integracja).\n- Kwoty zawsze w groszach (najmniejszej jednostce waluty): `12900` to 129,00 zł. Nigdy ułamki.\n- Treść zapytań: JSON (`Content-Type: application/json`). Formularz `application/x-www-form-urlencoded` też działa.\n- Odpowiedzi i błędy zawsze w JSON, także 404 na nieznanej ścieżce, 405, 429 i 500.\n- Czas w ISO 8601 ze strefą (`2026-10-03T12:34:56+00:00`).\n\n## Identyfikatory\nKażdy obiekt ma pole `obiekt` i identyfikator ze stałym prefiksem: płatność `tr_`, zwrot `zw_`, zdarzenie `evt_`, zapytanie `req_`.\n\n## Identyfikator zapytania\nKażda odpowiedź ma nagłówek `X-Request-Id` (np. `req_k3j2h1g0f9e8d7c6b5a4z3y2`). Przy błędzie ten sam identyfikator jest w ciele\njako `blad.zadanie_id`. Podaj go wsparciu, gdy coś poszło nie tak.\n\n## Wersja API\nWersja to data. Odpowiedź niesie nagłówek `Placenie-Version` z wersją, która ją obsłużyła. Możesz wskazać wersję nagłówkiem\n`Placenie-Version` w zapytaniu (dostępne: `2026-10-01`, `2026-10-03`). Nieznana wersja to błąd 400 `wersja_nieznana`.\nNowe pola dochodzą bez zmiany wersji, więc Twój kod powinien ignorować pola, których nie zna.\n\n## Idempotencja\nKażdy `POST` może nieść nagłówek `Idempotency-Key` (1 do 255 znaków, np. UUID). Powtórzone zapytanie z tym samym kluczem\ni tą samą treścią zwraca zapisaną odpowiedź (nagłówek `Idempotent-Replayed: true`, `X-Original-Request-Id` pierwszego zapytania)\ni niczego nie wykonuje drugi raz. Ten sam klucz z inną treścią albo inną ścieżką to 409 `klucz_idempotencji_uzyty`.\nKlucz jest ważny 24 godziny, w zakresie sklepu i trybu (test albo live). Dwa identyczne zapytania naraz: drugie czeka na pierwsze.\n\n## Limit zapytań\n120 zapytań na minutę na klucz. Nagłówki `X-RateLimit-Limit` i `X-RateLimit-Remaining` w każdej odpowiedzi; po przekroczeniu\n429 `limit_zapytan` z nagłówkiem `Retry-After` (sekundy).\n\n## Błędy\nJeden obiekt błędu dla całego API (schemat `Blad`): `typ` grupuje kody (`dane_nieprawidlowe`, `uwierzytelnienie`, `nie_znaleziono`,\n`plan`, `operator`, `konflikt`, `limit`, `zadanie_nieprawidlowe`, `blad_serwera`), `kod` jest konkretny i stabilny, `opis` po polsku,\n`pole` wskazuje pierwsze złe pole, `pola` zawiera komunikaty dla wszystkich pól, `dokumentacja` prowadzi do opisu kodu,\n`zadanie_id` to identyfikator zapytania. Pełna lista kodów w `x-kody-bledow`.\n\n## Listy\nListy mają `obiekt: \"lista\"`, `dane` (najnowsze pierwsze) i `ma_wiecej`. Stronicowanie kursorem: `limit` (1 do 100),\n`po=<id>` daje obiekty starsze od podanego (następna strona), `przed=<id>` nowsze (poprzednia strona). Bez kursora działa\nstronicowanie numerem `strona` (dodatkowo `strona`, `stron`, `razem`).\n\n## Piaskownica\nKlucz testowy działa od założenia konta, pieniądze nie płyną, a ekran płatności prowadzi do banku testowego.\nDane testowe są w `x-piaskownica`: kod BLIK `777777` zatwierdza płatność, `111111` kończy się odmową banku; dla karty i przelewu\nklient wybiera „Zatwierdź płatność” albo „Odrzuć w banku”. Do testów automatycznych służy `POST /v1/platnosci/{id}/symulacja`,\nktóre ustawia wynik bez ekranu i wysyła ten sam webhook co prawdziwa płatność.\n","contact":{"name":"Placenie, wsparcie dla programistów","url":"https://placenie.pl/kontakt"},"termsOfService":"https://placenie.pl/regulamin"},"servers":[{"url":"https://placenie.pl/api","description":"Produkcja i piaskownica (tryb wybiera klucz)."}],"security":[{"kluczApi":[]}],"tags":[{"name":"Płatności","description":"Obiekt `platnosc`: utworzenie, status, zmiana opisu i metadanych, zwrot, lista, symulacja w piaskownicy."},{"name":"Płatności cykliczne","description":"Obiekt `platnosc_cykliczna` (plan Sklep i wyższe): zgoda klienta, obciążenia z harmonogramu, ponowienia po odmowie, rezygnacja."},{"name":"Zdarzenia","description":"Obiekt `zdarzenie`: to samo, co idzie w webhooku, dostępne zapytaniem; ponowna dostawa webhooka."},{"name":"Specyfikacja","description":"Ta specyfikacja w JSON, bez klucza."}],"paths":{"/v1/platnosci":{"post":{"tags":["Płatności"],"operationId":"utworzPlatnosc","summary":"Utwórz płatność","description":"Tworzy płatność i zwraca `adres_platnosci`, na który kierujesz klienta. Po zapłacie klient wraca na `adres_powrotu`\nz parametrem `placenie_id=<id>`, a Ty dostajesz webhook `platnosc.oplacona`. Status zawsze sprawdzaj po swojej stronie\n(webhook albo `GET /v1/platnosci/{id}`), nie po samym powrocie klienta.\n\nTen sam `numer_zamowienia` z tą samą kwotą i walutą zwraca istniejącą płatność (200 zamiast 201).\nTen sam numer z inną kwotą to 409 `numer_zamowienia_zajety`. Do ponawiania zapytań użyj nagłówka `Idempotency-Key`.\n","parameters":[{"$ref":"#/components/parameters/IdempotencyKey"},{"$ref":"#/components/parameters/PlacenieVersion"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/NowaPlatnosc"},"examples":{"podstawowa":{"summary":"Zamówienie w sklepie","value":{"kwota":12900,"waluta":"PLN","numer_zamowienia":"ZAM-2026-001","opis":"Zamówienie ZAM-2026-001","email_klienta":"klient@przyklad.pl","adres_powrotu":"https://twojsklep.pl/zamowienie/ZAM-2026-001/dziekujemy","metadane":{"koszyk":"c_8812","klient_crm":"4471"}}}}}}},"responses":{"201":{"description":"Płatność utworzona.","headers":{"X-Request-Id":{"$ref":"#/components/headers/XRequestId"},"Placenie-Version":{"$ref":"#/components/headers/PlacenieVersion"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Platnosc"},"examples":{"nowa":{"$ref":"#/components/examples/PlatnoscNowa"}}}}},"200":{"description":"Istniejąca płatność o tym samym `numer_zamowienia`, kwocie i walucie (albo powtórka z `Idempotency-Key`).","headers":{"Idempotent-Replayed":{"$ref":"#/components/headers/IdempotentReplayed"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Platnosc"}}}},"400":{"$ref":"#/components/responses/Blad400"},"401":{"$ref":"#/components/responses/Blad401"},"402":{"$ref":"#/components/responses/Blad402"},"409":{"$ref":"#/components/responses/Blad409"},"422":{"$ref":"#/components/responses/Blad422"},"429":{"$ref":"#/components/responses/Blad429"}}},"get":{"tags":["Płatności"],"operationId":"listaPlatnosci","summary":"Lista płatności","description":"Płatności klucza (tylko jego tryb), najnowsze pierwsze. Filtry łączą się ze sobą i z kursorami.","parameters":[{"name":"status","in":"query","description":"Tylko płatności w tym statusie.","schema":{"$ref":"#/components/schemas/StatusPlatnosci"}},{"name":"metoda","in":"query","description":"Tylko płatności tą metodą.","schema":{"$ref":"#/components/schemas/Metoda"}},{"name":"numer_zamowienia","in":"query","description":"Dokładny numer zamówienia.","schema":{"type":"string","maxLength":120}},{"name":"od","in":"query","description":"Utworzone od tego dnia włącznie (RRRR-MM-DD).","schema":{"type":"string","format":"date","examples":["2026-10-01"]}},{"name":"do","in":"query","description":"Utworzone do tego dnia włącznie (RRRR-MM-DD).","schema":{"type":"string","format":"date","examples":["2026-10-31"]}},{"$ref":"#/components/parameters/Limit"},{"$ref":"#/components/parameters/Po"},{"$ref":"#/components/parameters/Przed"},{"$ref":"#/components/parameters/Strona"}],"responses":{"200":{"description":"Lista płatności.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Lista"},{"type":"object","properties":{"dane":{"type":"array","items":{"$ref":"#/components/schemas/Platnosc"}}}}]},"examples":{"kursorem":{"summary":"Strona po kursorze","value":{"obiekt":"lista","adres":"/v1/platnosci","dane":[{"obiekt":"platnosc","id":"tr_8h2k1j0f9e8d7c6b5a4z","tryb":"test","status":"oplacona","kwota":12900,"waluta":"PLN","zwrocono":0,"do_zwrotu":12900,"numer_zamowienia":"ZAM-2026-001","opis":"Zamówienie ZAM-2026-001","email_klienta":"klient@przyklad.pl","adres_powrotu":"https://twojsklep.pl/dziekujemy","metoda":"blik","metadane":{"koszyk":"c_8812"},"adres_platnosci":"https://placenie.pl/zaplac/tr_8h2k1j0f9e8d7c6b5a4z","utworzona":"2026-10-03T10:00:00+00:00","oplacona":"2026-10-03T10:01:12+00:00","zwroty":[]}],"ma_wiecej":true}}}}}},"401":{"$ref":"#/components/responses/Blad401"},"422":{"$ref":"#/components/responses/Blad422"},"429":{"$ref":"#/components/responses/Blad429"}}}},"/v1/platnosci/{id}":{"parameters":[{"$ref":"#/components/parameters/IdPlatnosci"}],"get":{"tags":["Płatności"],"operationId":"pobierzPlatnosc","summary":"Pobierz płatność","description":"Aktualny stan płatności razem z listą zwrotów. Dla płatności produkcyjnej w statusie `oczekuje` pytamy operatora\no stan na bieżąco, więc odpowiedź jest aktualna nawet, gdy webhook jeszcze nie dotarł.\n","responses":{"200":{"description":"Płatność.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Platnosc"},"examples":{"oplacona":{"$ref":"#/components/examples/PlatnoscOplacona"}}}}},"401":{"$ref":"#/components/responses/Blad401"},"404":{"$ref":"#/components/responses/Blad404"},"429":{"$ref":"#/components/responses/Blad429"}}},"post":{"tags":["Płatności"],"operationId":"zmienPlatnosc","summary":"Zmień opis albo metadane","description":"Zmienia pola, które nie dotyczą pieniędzy: `opis` i `metadane`. Metadane są scalane: podane klucze nadpisują\nistniejące, wartość `null` usuwa klucz, pozostałe klucze zostają. Kwoty, waluty ani statusu nie da się zmienić.\n","parameters":[{"$ref":"#/components/parameters/IdempotencyKey"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ZmianaPlatnosci"},"examples":{"scalanie":{"value":{"opis":"Zamówienie ZAM-2026-001, wysłane","metadane":{"koszyk":null,"numer_listu":"00340434292135100186"}}}}}}},"responses":{"200":{"description":"Płatność po zmianie.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Platnosc"}}}},"401":{"$ref":"#/components/responses/Blad401"},"404":{"$ref":"#/components/responses/Blad404"},"422":{"$ref":"#/components/responses/Blad422"},"429":{"$ref":"#/components/responses/Blad429"}}}},"/v1/platnosci/{id}/zwroty":{"parameters":[{"$ref":"#/components/parameters/IdPlatnosci"}],"post":{"tags":["Płatności"],"operationId":"zwrocPlatnosc","summary":"Zwróć płatność","description":"Zwrot pełny (bez `kwota`) albo częściowy, tą samą drogą, którą przyszła płatność. Zwrot jest możliwy tylko dla płatności\n`oplacona`, do wysokości `do_zwrotu`. Kilka zwrotów częściowych może razem dojść do pełnej kwoty; po pełnym zwrocie\nstatus płatności to `zwrocona`. W produkcji zwrot może dostać status `zlecony` (czeka u operatora), a po jego\nrozstrzygnięciu dostaniesz `platnosc.zwrot_odrzucony`, jeśli operator odmówił.\n\nOdpowiedź to płatność z pełną listą `zwroty`; ostatni element to nowy zwrot. Zdarzenie `platnosc.zwrot` niesie go w polu `zwrot`.\n","parameters":[{"$ref":"#/components/parameters/IdempotencyKey"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/NowyZwrot"},"examples":{"czesciowy":{"value":{"kwota":2900}},"pelny":{"value":[]}}}}},"responses":{"201":{"description":"Zwrot przyjęty. Płatność z listą zwrotów.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Platnosc"},"examples":{"poZwrocie":{"$ref":"#/components/examples/PlatnoscPoZwrocie"}}}}},"401":{"$ref":"#/components/responses/Blad401"},"404":{"$ref":"#/components/responses/Blad404"},"422":{"description":"Zwrot odrzucony (`zwrot_odrzucony`, np. płatność nieopłacona albo kwota ponad `do_zwrotu`) albo złe pola.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Blad"},"examples":{"zaDuzo":{"value":{"blad":{"typ":"zadanie_nieprawidlowe","kod":"zwrot_odrzucony","opis":"Kwota zwrotu musi być większa od zera i nie większa niż 100,00 zł.","dokumentacja":"https://placenie.pl/docs/bledy#zwrot_odrzucony","zadanie_id":"req_k3j2h1g0f9e8d7c6b5a4z3y2"}}}}}}},"429":{"$ref":"#/components/responses/Blad429"}}}},"/v1/platnosci/{id}/symulacja":{"parameters":[{"$ref":"#/components/parameters/IdPlatnosci"}],"post":{"tags":["Płatności"],"operationId":"symulujWynik","summary":"Symuluj wynik (piaskownica)","description":"Tylko klucz testowy. Ustawia wynik płatności bez przechodzenia ekranu testowego, tą samą drogą co bank testowy:\npowstaje zdarzenie i idzie webhook. Działa dla płatności `nowa` albo `odrzucona`; dla innych 409 `stan_nieprawidlowy`.\nKluczem produkcyjnym: 400 `tylko_piaskownica`.\n","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Symulacja"},"examples":{"sukces":{"value":{"wynik":"oplacona","metoda":"blik"}},"odmowa":{"value":{"wynik":"odrzucona"}}}}}},"responses":{"200":{"description":"Płatność po symulacji.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Platnosc"}}}},"400":{"$ref":"#/components/responses/Blad400"},"401":{"$ref":"#/components/responses/Blad401"},"404":{"$ref":"#/components/responses/Blad404"},"409":{"$ref":"#/components/responses/Blad409"},"422":{"$ref":"#/components/responses/Blad422"},"429":{"$ref":"#/components/responses/Blad429"}}}},"/v1/platnosci-cykliczne":{"post":{"tags":["Płatności cykliczne"],"operationId":"utworzPlatnoscCykliczna","summary":"Utwórz płatność cykliczną","description":"Plan Sklep i wyższe. Tworzy zgodę w stanie `oczekuje` i zwraca `adres_zgody`: wyślij tam klienta. Klient widzi kwotę,\nokres i sposób rezygnacji, zgadza się i płaci pierwszy raz kartą (3-D Secure, dane karty wpisuje w formularz operatora).\nKolejne obciążenia idą z harmonogramu co `okres`, bez udziału klienta; każde to zwykła `platnosc` z polem\n`platnosc_cykliczna`. Kilka dni przed obciążeniem klient dostaje wiadomość. Po odmowie banku ponawiamy po 1, 3 i 5 dniach,\npotem zgoda jest `wstrzymana`, dopóki klient nie poda nowej karty pod tym samym `adres_zgody`.\nKluczem produkcyjnym wymaga podłączonego operatora (409 `operator_niepodlaczony`). Plan bez tej funkcji: 402 `funkcja_poza_planem`.\n","parameters":[{"$ref":"#/components/parameters/IdempotencyKey"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/NowaPlatnoscCykliczna"},"examples":{"miesieczna":{"value":{"kwota":4900,"okres":"miesiac","opis":"Abonament Premium","email_klienta":"klient@example.com","numer_klienta":"K-1024"}}}}}},"responses":{"201":{"description":"Płatność cykliczna czeka na zgodę klienta.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PlatnoscCykliczna"}}}},"401":{"$ref":"#/components/responses/Blad401"},"402":{"$ref":"#/components/responses/Blad402"},"409":{"$ref":"#/components/responses/Blad409"},"422":{"$ref":"#/components/responses/Blad422"},"429":{"$ref":"#/components/responses/Blad429"}}},"get":{"tags":["Płatności cykliczne"],"operationId":"listaPlatnosciCyklicznych","summary":"Lista płatności cyklicznych","description":"Najnowsze pierwsze, z filtrem `status`. Stronicowanie jak w liście płatności.","parameters":[{"$ref":"#/components/parameters/Limit"},{"$ref":"#/components/parameters/Po"},{"$ref":"#/components/parameters/Przed"},{"$ref":"#/components/parameters/Strona"},{"name":"status","in":"query","required":false,"schema":{"$ref":"#/components/schemas/StatusPlatnosciCyklicznej"}}],"responses":{"200":{"description":"Lista obiektów `platnosc_cykliczna`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Lista"}}}},"401":{"$ref":"#/components/responses/Blad401"},"422":{"$ref":"#/components/responses/Blad422"},"429":{"$ref":"#/components/responses/Blad429"}}}},"/v1/platnosci-cykliczne/{id}":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","pattern":"^cy_[a-z0-9]{20}$"}}],"get":{"tags":["Płatności cykliczne"],"operationId":"pobierzPlatnoscCykliczna","summary":"Pobierz płatność cykliczną","description":"Stan zgody, numer ostatniego opłaconego okresu (`cykl`), termin następnego obciążenia i liczba prób po odmowie.","responses":{"200":{"description":"Płatność cykliczna.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PlatnoscCykliczna"}}}},"401":{"$ref":"#/components/responses/Blad401"},"404":{"$ref":"#/components/responses/Blad404"},"429":{"$ref":"#/components/responses/Blad429"}}}},"/v1/platnosci-cykliczne/{id}/anuluj":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","pattern":"^cy_[a-z0-9]{20}$"}}],"post":{"tags":["Płatności cykliczne"],"operationId":"anulujPlatnoscCykliczna","summary":"Anuluj płatność cykliczną","description":"Harmonogram staje od razu, kolejnych obciążeń nie będzie. Ponowne anulowanie niczego nie zmienia. Idzie zdarzenie `platnosc_cykliczna.anulowana`.","parameters":[{"$ref":"#/components/parameters/IdempotencyKey"}],"responses":{"200":{"description":"Płatność cykliczna po anulowaniu.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PlatnoscCykliczna"}}}},"401":{"$ref":"#/components/responses/Blad401"},"404":{"$ref":"#/components/responses/Blad404"},"429":{"$ref":"#/components/responses/Blad429"}}}},"/v1/platnosci-cykliczne/{id}/symulacja":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","pattern":"^cy_[a-z0-9]{20}$"}}],"post":{"tags":["Płatności cykliczne"],"operationId":"symulujObciazenieCykliczne","summary":"Symuluj kolejne obciążenie (piaskownica)","description":"Tylko klucz testowy. Obciąża następny okres od razu, z wynikiem `oplacona` albo `odrzucona`, tą samą drogą co harmonogram:\npowstają zdarzenia i idą webhooki odnowienia, odmowy albo wstrzymania. Działa dla zgody `aktywna` albo `ponawiana`.\n","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["wynik"],"properties":{"wynik":{"type":"string","enum":["oplacona","odrzucona"]}}}}}},"responses":{"200":{"description":"Płatność cykliczna po obciążeniu.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PlatnoscCykliczna"}}}},"400":{"$ref":"#/components/responses/Blad400"},"401":{"$ref":"#/components/responses/Blad401"},"404":{"$ref":"#/components/responses/Blad404"},"409":{"$ref":"#/components/responses/Blad409"},"422":{"$ref":"#/components/responses/Blad422"},"429":{"$ref":"#/components/responses/Blad429"}}}},"/v1/zdarzenia":{"get":{"tags":["Zdarzenia"],"operationId":"listaZdarzen","summary":"Lista zdarzeń","description":"Zdarzenia klucza (tylko jego tryb), najnowsze pierwsze. Każda zmiana stanu płatności zapisuje zdarzenie,\ntakże gdy sklep nie ma webhooka. Treść zdarzenia to dokładnie to, co idzie w webhooku, plus pole `webhook`\nze stanem ostatniej dostawy (albo `null`, gdy adresu webhooka nie ma).\n","parameters":[{"name":"typ","in":"query","description":"Tylko zdarzenia tego typu.","schema":{"$ref":"#/components/schemas/TypZdarzenia"}},{"name":"platnosc","in":"query","description":"Tylko zdarzenia tej płatności (`tr_...`).","schema":{"type":"string","examples":["tr_8h2k1j0f9e8d7c6b5a4z"]}},{"name":"od","in":"query","schema":{"type":"string","format":"date"}},{"name":"do","in":"query","schema":{"type":"string","format":"date"}},{"$ref":"#/components/parameters/Limit"},{"$ref":"#/components/parameters/Po"},{"$ref":"#/components/parameters/Przed"},{"$ref":"#/components/parameters/Strona"}],"responses":{"200":{"description":"Lista zdarzeń.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Lista"},{"type":"object","properties":{"dane":{"type":"array","items":{"$ref":"#/components/schemas/Zdarzenie"}}}}]}}}},"401":{"$ref":"#/components/responses/Blad401"},"422":{"$ref":"#/components/responses/Blad422"},"429":{"$ref":"#/components/responses/Blad429"}}}},"/v1/zdarzenia/{id}":{"parameters":[{"$ref":"#/components/parameters/IdZdarzenia"}],"get":{"tags":["Zdarzenia"],"operationId":"pobierzZdarzenie","summary":"Pobierz zdarzenie","description":"Jedno zdarzenie. Przydatne, gdy odbiornik webhooka chce potwierdzić treść u źródła zamiast ufać samemu żądaniu.","responses":{"200":{"description":"Zdarzenie.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Zdarzenie"},"examples":{"oplacona":{"$ref":"#/components/examples/ZdarzenieOplacona"}}}}},"401":{"$ref":"#/components/responses/Blad401"},"404":{"$ref":"#/components/responses/Blad404"},"429":{"$ref":"#/components/responses/Blad429"}}}},"/v1/zdarzenia/{id}/ponow":{"parameters":[{"$ref":"#/components/parameters/IdZdarzenia"}],"post":{"tags":["Zdarzenia"],"operationId":"ponowWebhook","summary":"Ponów webhook zdarzenia","description":"Wysyła webhook tego zdarzenia jeszcze raz (np. po naprawie odbiornika w sklepie). Nowa dostawa z nowym podpisem,\nta sama treść i ten sam `Placenie-Event-Id`, więc odbiornik powinien być idempotentny po identyfikatorze zdarzenia.\nBez adresu webhooka w panelu: 409 `webhook_nieustawiony`.\n","responses":{"202":{"description":"Dostawa wykonana albo zaplanowana do ponowień. Zdarzenie ze stanem dostawy w polu `webhook`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Zdarzenie"}}}},"401":{"$ref":"#/components/responses/Blad401"},"404":{"$ref":"#/components/responses/Blad404"},"409":{"$ref":"#/components/responses/Blad409"},"429":{"$ref":"#/components/responses/Blad429"}}}},"/v1/openapi.json":{"get":{"tags":["Specyfikacja"],"operationId":"specyfikacja","summary":"Ta specyfikacja (OpenAPI 3.1, JSON)","description":"Aktualna specyfikacja całego API, bez uwierzytelniania. Źródło w repozytorium to `docs/openapi.yaml`.","security":[],"responses":{"200":{"description":"Dokument OpenAPI 3.1.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}}},"webhooks":{"platnosc.oczekuje":{"post":{"summary":"Klient poszedł do operatora (produkcja)","description":"Płatność produkcyjna czeka na wynik u operatora. W piaskownicy to zdarzenie nie występuje.","requestBody":{"$ref":"#/components/requestBodies/Webhook"},"responses":{"200":{"$ref":"#/components/responses/WebhookOk"}}}},"platnosc.oplacona":{"post":{"summary":"Płatność zaksięgowana","description":"Można wydać towar albo usługę. `transakcja.oplacona` ma czas księgowania, `transakcja.metoda` użytą metodę.","requestBody":{"$ref":"#/components/requestBodies/Webhook"},"responses":{"200":{"$ref":"#/components/responses/WebhookOk"}}}},"platnosc.odrzucona":{"post":{"summary":"Bank albo operator odmówił","description":"Klient może spróbować ponownie z tego samego `adres_platnosci` (inną metodą albo kartą); wtedy dostaniesz kolejne zdarzenia tej samej płatności.","requestBody":{"$ref":"#/components/requestBodies/Webhook"},"responses":{"200":{"$ref":"#/components/responses/WebhookOk"}}}},"platnosc.zwrot":{"post":{"summary":"Zwrot wykonany albo zlecony","description":"Treść ma dodatkowe pole `zwrot` (schemat `Zwrot`) z nowym zwrotem; `transakcja.zwrocono` i `transakcja.status` są już po zmianie.","requestBody":{"$ref":"#/components/requestBodies/Webhook"},"responses":{"200":{"$ref":"#/components/responses/WebhookOk"}}}},"platnosc.zwrot_odrzucony":{"post":{"summary":"Operator odrzucił zlecony zwrot","description":"Kwota wraca do `do_zwrotu`, zwrot w polu `zwrot` ma status `odrzucony`. Dotyczy tylko produkcji.","requestBody":{"$ref":"#/components/requestBodies/Webhook"},"responses":{"200":{"$ref":"#/components/responses/WebhookOk"}}}},"platnosc_cykliczna.aktywna":{"post":{"summary":"Zgoda klienta i pierwsze obciążenie","description":"Treść ma pole `platnosc_cykliczna` (schemat `PlatnoscCykliczna`) i `transakcja` pierwszego okresu.","requestBody":{"$ref":"#/components/requestBodies/Webhook"},"responses":{"200":{"$ref":"#/components/responses/WebhookOk"}}}},"platnosc_cykliczna.odnowiona":{"post":{"summary":"Kolejny okres opłacony","description":"`transakcja` to obciążenie tego okresu, `platnosc_cykliczna.nastepne_obciazenie` to termin następnego.","requestBody":{"$ref":"#/components/requestBodies/Webhook"},"responses":{"200":{"$ref":"#/components/responses/WebhookOk"}}}},"platnosc_cykliczna.odmowa":{"post":{"summary":"Obciążenie odrzucone, będzie ponowione","description":"`platnosc_cykliczna.proby` to liczba odmów w tym okresie, `nastepne_obciazenie` to termin ponowienia.","requestBody":{"$ref":"#/components/requestBodies/Webhook"},"responses":{"200":{"$ref":"#/components/responses/WebhookOk"}}}},"platnosc_cykliczna.wstrzymana":{"post":{"summary":"Ponowienia wyczerpane","description":"Harmonogram stoi. Klient może podać nową kartę pod `adres_zgody`, wtedy przyjdzie `platnosc_cykliczna.odnowiona`.","requestBody":{"$ref":"#/components/requestBodies/Webhook"},"responses":{"200":{"$ref":"#/components/responses/WebhookOk"}}}},"platnosc_cykliczna.anulowana":{"post":{"summary":"Rezygnacja klienta albo sklepu","description":"`anulowana_przez` to `klient` albo `sklep`. Kolejnych obciążeń nie będzie.","requestBody":{"$ref":"#/components/requestBodies/Webhook"},"responses":{"200":{"$ref":"#/components/responses/WebhookOk"}}}}},"components":{"securitySchemes":{"kluczApi":{"type":"http","scheme":"bearer","bearerFormat":"plc_test_... albo plc_live_...","description":"Klucz sklepu z panelu (Integracja). Osobny klucz dla piaskownicy i produkcji. Wydanie nowego klucza wycofuje poprzedni od razu."}},"parameters":{"IdPlatnosci":{"name":"id","in":"path","required":true,"description":"Identyfikator płatności (`tr_` i 20 znaków).","schema":{"type":"string","pattern":"^tr_[a-z0-9]{20}$","examples":["tr_8h2k1j0f9e8d7c6b5a4z"]}},"IdZdarzenia":{"name":"id","in":"path","required":true,"description":"Identyfikator zdarzenia (`evt_` i 20 znaków).","schema":{"type":"string","pattern":"^evt_[a-z0-9]{20}$","examples":["evt_0a1b2c3d4e5f6g7h8i9j"]}},"IdempotencyKey":{"name":"Idempotency-Key","in":"header","required":false,"description":"Klucz idempotencji (1 do 255 znaków drukowalnych, np. UUID). Patrz „Idempotencja” we wstępie.","schema":{"type":"string","minLength":1,"maxLength":255,"examples":["0f9d4c2a-6b3e-4e1a-9c7d-2b8f1e3a5d6c"]}},"PlacenieVersion":{"name":"Placenie-Version","in":"header","required":false,"description":"Wersja API (data), którą ma obsłużyć zapytanie. Domyślnie najnowsza.","schema":{"type":"string","enum":["2026-10-01","2026-10-03"]}},"Limit":{"name":"limit","in":"query","description":"Liczba obiektów na stronie, 1 do 100. Domyślnie 100.","schema":{"type":"integer","minimum":1,"maximum":100,"default":100}},"Po":{"name":"po","in":"query","description":"Kursor „następna strona”: identyfikator ostatniego obiektu z poprzedniej strony; zwraca obiekty od niego starsze. Nie łączy się z `przed`.","schema":{"type":"string"}},"Przed":{"name":"przed","in":"query","description":"Kursor „poprzednia strona”: identyfikator pierwszego obiektu z bieżącej strony; zwraca obiekty od niego nowsze. Nie łączy się z `po`.","schema":{"type":"string"}},"Strona":{"name":"strona","in":"query","description":"Numer strony (stronicowanie sprzed kursorów). Ignorowany, gdy podano `po` albo `przed`.","schema":{"type":"integer","minimum":1,"default":1}}},"headers":{"XRequestId":{"description":"Identyfikator zapytania do podania wsparciu. Przy błędzie ten sam w `blad.zadanie_id`.","schema":{"type":"string","pattern":"^req_[a-z0-9]{24}$"}},"PlacenieVersion":{"description":"Wersja API, która obsłużyła zapytanie.","schema":{"type":"string","examples":["2026-10-03"]}},"IdempotentReplayed":{"description":"`true`, gdy to zapisana odpowiedź na wcześniejsze zapytanie z tym samym `Idempotency-Key`.","schema":{"type":"string","enum":["true"]}},"RateLimitLimit":{"description":"Limit zapytań na minutę dla klucza.","schema":{"type":"integer","examples":[120]}},"RateLimitRemaining":{"description":"Ile zapytań zostało w bieżącej minucie.","schema":{"type":"integer"}},"RetryAfter":{"description":"Za ile sekund można ponowić.","schema":{"type":"integer"}},"PlacenieSignature":{"description":"Podpis webhooka: `t=<czas unix>,v1=<hex>`, gdzie `v1` to HMAC-SHA256 z tekstu `<t>.<treść żądania>` sekretem webhooka\nz panelu. Sprawdź podpis stałoczasowo (`hash_equals`) i odrzuć, gdy `|teraz - t| > 300` sekund (ochrona przed powtórką).\n","schema":{"type":"string","examples":["t=1759490400,v1=5257a869e7ecebeda32affa62cdca3fa51cad7e77a0e56ff536d0ce8e108d8c2"]}},"PlacenieEventId":{"description":"Identyfikator zdarzenia (`evt_...`), ten sam co `id` w treści. Odbiornik powinien być idempotentny po tym polu.","schema":{"type":"string"}},"PlacenieEventType":{"description":"Typ zdarzenia, ten sam co `typ` w treści.","schema":{"$ref":"#/components/schemas/TypZdarzenia"}}},"requestBodies":{"Webhook":{"required":true,"description":"`POST` na adres webhooka z panelu (tylko `https`, publiczny host). Nagłówki: `Placenie-Signature`, `Placenie-Event-Id`,\n`Placenie-Event-Type`, `User-Agent: Placenie-Webhook/1`. Odpowiedz kodem 2xx w ciągu 8 sekund. Każda inna odpowiedź\noznacza ponowienie po 1, 5, 15 i 60 minutach, potem po 3, 6 i 12 godzinach, potem dostawa jest porzucona\n(zdarzenie nadal można pobrać przez `GET /v1/zdarzenia/{id}` i ponowić przez `POST /v1/zdarzenia/{id}/ponow`).\nKolejność dostaw nie jest gwarantowana: zawsze patrz na `transakcja.status`, nie na kolejność webhooków.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Zdarzenie"},"examples":{"oplacona":{"$ref":"#/components/examples/ZdarzenieOplacona"}}}}}},"responses":{"WebhookOk":{"description":"Dowolny kod 2xx. Treść odpowiedzi jest ignorowana."},"Blad400":{"description":"Zapytanie nie do wykonania w tym kontekście (`klucz_idempotencji_nieprawidlowy`, `wersja_nieznana`, `tylko_piaskownica`).","headers":{"X-Request-Id":{"$ref":"#/components/headers/XRequestId"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Blad"}}}},"Blad401":{"description":"Brak albo nieprawidłowy klucz API (`klucz_nieprawidlowy`).","headers":{"X-Request-Id":{"$ref":"#/components/headers/XRequestId"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Blad"},"examples":{"bezKlucza":{"value":{"blad":{"typ":"uwierzytelnienie","kod":"klucz_nieprawidlowy","opis":"Brak albo nieprawidłowy klucz API.","dokumentacja":"https://placenie.pl/docs/bledy#klucz_nieprawidlowy","zadanie_id":"req_k3j2h1g0f9e8d7c6b5a4z3y2"}}}}}}},"Blad402":{"description":"Plan albo stan konta nie pozwala (`plan_nieoplacony`, `funkcja_poza_planem`, `sklep_poza_planem`, `limit_demo`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Blad"}}}},"Blad404":{"description":"Nie ma takiego obiektu dla tego klucza (`nie_znaleziono`) albo takiego adresu (`trasa_nieznana`).","headers":{"X-Request-Id":{"$ref":"#/components/headers/XRequestId"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Blad"}}}},"Blad409":{"description":"Konflikt ze stanem (`numer_zamowienia_zajety`, `operator_niepodlaczony`, `klucz_idempotencji_uzyty`, `klucz_idempotencji_w_toku`, `stan_nieprawidlowy`, `webhook_nieustawiony`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Blad"}}}},"Blad422":{"description":"Złe pola (`dane_nieprawidlowe`, `kursor_nieprawidlowy`, `waluta_poza_planem`, `zwrot_odrzucony`).","headers":{"X-Request-Id":{"$ref":"#/components/headers/XRequestId"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Blad"},"examples":{"walidacja":{"value":{"blad":{"typ":"dane_nieprawidlowe","kod":"dane_nieprawidlowe","opis":"Popraw pola zapytania.","pole":"kwota","pola":{"kwota":["The kwota field must be at least 100."]},"dokumentacja":"https://placenie.pl/docs/bledy#dane_nieprawidlowe","zadanie_id":"req_k3j2h1g0f9e8d7c6b5a4z3y2"}}}}}}},"Blad429":{"description":"Przekroczony limit zapytań (`limit_zapytan`). Ponów po czasie z `Retry-After`.","headers":{"Retry-After":{"$ref":"#/components/headers/RetryAfter"},"X-RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Blad"}}}}},"schemas":{"Tryb":{"type":"string","enum":["test","live"],"description":"`test` to piaskownica (klucz `plc_test_`), `live` to produkcja (klucz `plc_live_`)."},"Waluta":{"type":"string","minLength":3,"maxLength":3,"description":"Kod ISO 4217. `PLN` w każdym planie; `EUR`, `USD`, `GBP`, `CZK` w planie Skala i Enterprise.","examples":["PLN","EUR"]},"Metoda":{"type":"string","enum":["blik","card","transfer"],"description":"`blik` to BLIK, `card` karta, `transfer` szybki przelew (pay-by-link)."},"StatusPlatnosci":{"type":"string","enum":["nowa","oczekuje","oplacona","odrzucona","zwrocona"],"description":"- `nowa`: utworzona, klient jeszcze nie zapłacił,\n- `oczekuje`: klient poszedł do operatora, czekamy na wynik (produkcja),\n- `oplacona`: pieniądze zaksięgowane; stan końcowy, z którego możliwy jest tylko zwrot,\n- `odrzucona`: bank albo operator odmówił; klient może spróbować ponownie z tego samego adresu płatności,\n- `zwrocona`: zwrócona w całości.\n"},"StatusZwrotu":{"type":"string","enum":["wykonany","zlecony","odrzucony"],"description":"`wykonany` zakończony, `zlecony` czeka u operatora (produkcja), `odrzucony` operator odmówił (kwota wróciła do puli)."},"TypZdarzenia":{"type":"string","enum":["platnosc.oczekuje","platnosc.oplacona","platnosc.odrzucona","platnosc.zwrot","platnosc.zwrot_odrzucony","platnosc_cykliczna.aktywna","platnosc_cykliczna.odnowiona","platnosc_cykliczna.odmowa","platnosc_cykliczna.wstrzymana","platnosc_cykliczna.anulowana"]},"Metadane":{"type":"object","description":"Dowolne pary klucz: wartość Twojego systemu (numer koszyka, id klienta w CRM). Najwyżej 50 kluczy, klucz do 40 znaków,\nwartość do 500 znaków. Liczby i wartości logiczne są zapisywane jako teksty. Nigdy nie pokazujemy ich kupującemu.\n","maxProperties":50,"propertyNames":{"maxLength":40,"minLength":1},"additionalProperties":{"type":"string","maxLength":500},"examples":[{"koszyk":"c_8812","klient_crm":"4471"}]},"NowaPlatnosc":{"type":"object","required":["kwota"],"properties":{"kwota":{"type":"integer","minimum":100,"maximum":99999999,"description":"Kwota w groszach (najmniejszej jednostce waluty). Od 1,00 do 999 999,99.","examples":[12900]},"waluta":{"allOf":[{"$ref":"#/components/schemas/Waluta"}],"default":"PLN"},"numer_zamowienia":{"type":["string","null"],"maxLength":120,"description":"Twój numer zamówienia. Ten sam numer z tą samą kwotą i walutą zwraca istniejącą płatność zamiast tworzyć drugą.","examples":["ZAM-2026-001"]},"opis":{"type":["string","null"],"maxLength":255,"description":"Opis widoczny dla klienta na ekranie płatności i w panelu."},"email_klienta":{"type":["string","null"],"format":"email","maxLength":160,"description":"Adres klienta; może trafić do operatora jako dane płatnika."},"adres_powrotu":{"type":["string","null"],"format":"uri","maxLength":500,"description":"Dokąd wraca klient po płatności. Dopisujemy `?placenie_id=<id>`. Powrót nie jest potwierdzeniem zapłaty; potwierdzeniem jest webhook albo `GET /v1/platnosci/{id}`."},"metadane":{"$ref":"#/components/schemas/Metadane"}}},"ZmianaPlatnosci":{"type":"object","properties":{"opis":{"type":["string","null"],"maxLength":255},"metadane":{"type":["object","null"],"description":"Scalane z istniejącymi; `null` przy kluczu usuwa ten klucz.","additionalProperties":{"type":["string","number","boolean","null"]}}}},"NowyZwrot":{"type":"object","properties":{"kwota":{"type":"integer","minimum":1,"description":"Kwota zwrotu w groszach. Bez tego pola zwrot całej kwoty pozostałej do zwrotu.","examples":[2900]}}},"Symulacja":{"type":"object","required":["wynik"],"properties":{"wynik":{"type":"string","enum":["oplacona","odrzucona"],"description":"Wynik, który ma dostać płatność."},"metoda":{"allOf":[{"$ref":"#/components/schemas/Metoda"}],"description":"Metoda zapisana przy płatności. Domyślnie wybrana wcześniej na ekranie albo `blik`."}}},"Zwrot":{"type":"object","required":["obiekt","id","platnosc","kwota","waluta","status","zrodlo","utworzony"],"properties":{"obiekt":{"type":"string","const":"zwrot"},"id":{"type":"string","pattern":"^zw_[a-z0-9]{20}$","examples":["zw_9f8e7d6c5b4a3z2y1x0w"]},"platnosc":{"type":"string","description":"Identyfikator płatności, której dotyczy zwrot."},"kwota":{"type":"integer","description":"Kwota zwrotu w groszach."},"waluta":{"$ref":"#/components/schemas/Waluta"},"status":{"$ref":"#/components/schemas/StatusZwrotu"},"zrodlo":{"type":"string","enum":["api","panel"],"description":"Skąd zlecono zwrot."},"utworzony":{"type":"string","format":"date-time"}}},"Platnosc":{"type":"object","description":"Płatność (transakcja). Ta sama postać w odpowiedziach API i w polu `transakcja` zdarzenia.","required":["obiekt","id","tryb","status","kwota","waluta","zwrocono","do_zwrotu","metadane","adres_platnosci","utworzona","zwroty"],"properties":{"obiekt":{"type":"string","const":"platnosc"},"id":{"type":"string","pattern":"^tr_[a-z0-9]{20}$","examples":["tr_8h2k1j0f9e8d7c6b5a4z"]},"tryb":{"$ref":"#/components/schemas/Tryb"},"status":{"$ref":"#/components/schemas/StatusPlatnosci"},"kwota":{"type":"integer","description":"Kwota w groszach."},"waluta":{"$ref":"#/components/schemas/Waluta"},"zwrocono":{"type":"integer","description":"Suma wykonanych i zleconych zwrotów w groszach."},"do_zwrotu":{"type":"integer","description":"Ile jeszcze można zwrócić (0, gdy płatność nie jest `oplacona`)."},"numer_zamowienia":{"type":["string","null"]},"opis":{"type":["string","null"]},"email_klienta":{"type":["string","null"]},"adres_powrotu":{"type":["string","null"]},"metoda":{"oneOf":[{"$ref":"#/components/schemas/Metoda"},{"type":"null"}],"description":"Metoda wybrana przez klienta; `null`, dopóki nie wybrał."},"platnosc_cykliczna":{"type":["string","null"],"description":"Id płatności cyklicznej, gdy to jej obciążenie."},"okres_cykliczny":{"type":["integer","null"],"description":"Numer okresu płatności cyklicznej."},"metadane":{"$ref":"#/components/schemas/Metadane"},"adres_platnosci":{"type":"string","format":"uri","description":"Ekran płatności dla klienta. Przekieruj go tam (albo otwórz w nowej karcie).","examples":["https://placenie.pl/zaplac/tr_8h2k1j0f9e8d7c6b5a4z"]},"utworzona":{"type":"string","format":"date-time"},"oplacona":{"type":["string","null"],"format":"date-time","description":"Czas zaksięgowania; `null` przed zapłatą."},"zwroty":{"type":"array","items":{"$ref":"#/components/schemas/Zwrot"},"description":"Zwroty w kolejności zlecenia."}}},"StatusPlatnosciCyklicznej":{"type":"string","enum":["oczekuje","aktywna","ponawiana","wstrzymana","anulowana"]},"NowaPlatnoscCykliczna":{"type":"object","required":["kwota","okres","opis","email_klienta"],"properties":{"kwota":{"type":"integer","minimum":100,"maximum":99999999,"description":"Kwota każdego obciążenia w groszach."},"waluta":{"$ref":"#/components/schemas/Waluta"},"okres":{"type":"string","enum":["tydzien","miesiac","kwartal","rok"]},"opis":{"type":"string","maxLength":255,"description":"Za co płaci klient; widzi to na ekranie zgody i w wiadomościach."},"email_klienta":{"type":"string","format":"email","maxLength":160,"description":"Na ten adres idą zapowiedzi obciążeń i link do rezygnacji."},"numer_klienta":{"type":["string","null"],"maxLength":120},"adres_powrotu":{"type":["string","null"],"format":"uri","maxLength":500},"metadane":{"$ref":"#/components/schemas/Metadane"}}},"PlatnoscCykliczna":{"type":"object","description":"Zgoda klienta na obciążenia według harmonogramu. Dane karty i token nigdy nie wychodzą.","required":["obiekt","id","tryb","status","kwota","waluta","okres","opis","email_klienta","adres_zgody","cykl","proby","utworzona"],"properties":{"obiekt":{"type":"string","const":"platnosc_cykliczna"},"id":{"type":"string","pattern":"^cy_[a-z0-9]{20}$"},"tryb":{"$ref":"#/components/schemas/Tryb"},"status":{"$ref":"#/components/schemas/StatusPlatnosciCyklicznej"},"kwota":{"type":"integer"},"waluta":{"$ref":"#/components/schemas/Waluta"},"okres":{"type":"string","enum":["tydzien","miesiac","kwartal","rok"]},"opis":{"type":"string"},"email_klienta":{"type":"string"},"numer_klienta":{"type":["string","null"]},"adres_powrotu":{"type":["string","null"]},"metoda":{"type":["string","null"]},"karta":{"type":["string","null"],"description":"Zamaskowany numer karty od operatora."},"metadane":{"$ref":"#/components/schemas/Metadane"},"adres_zgody":{"type":"string","format":"uri","description":"Ekran zgody dla klienta, także do podania nowej karty po odmowie."},"cykl":{"type":"integer","description":"Numer ostatniego opłaconego okresu (0 przed pierwszą płatnością)."},"nastepne_obciazenie":{"type":["string","null"],"format":"date-time"},"proby":{"type":"integer","description":"Liczba odmów w bieżącym okresie."},"zgoda":{"type":["string","null"],"format":"date-time"},"anulowana":{"type":["string","null"],"format":"date-time"},"anulowana_przez":{"type":["string","null"],"enum":["klient","sklep",null]},"utworzona":{"type":"string","format":"date-time"}}},"Zdarzenie":{"type":"object","description":"Zdarzenie (treść webhooka). Pole `webhook` jest tylko w odpowiedziach API, nie w samym webhooku.","required":["obiekt","id","typ","tryb","utworzone","transakcja"],"properties":{"obiekt":{"type":"string","const":"zdarzenie"},"id":{"type":"string","pattern":"^evt_[a-z0-9]{20}$","examples":["evt_0a1b2c3d4e5f6g7h8i9j"]},"typ":{"$ref":"#/components/schemas/TypZdarzenia"},"tryb":{"$ref":"#/components/schemas/Tryb"},"utworzone":{"type":"string","format":"date-time"},"transakcja":{"$ref":"#/components/schemas/Platnosc"},"zwrot":{"allOf":[{"$ref":"#/components/schemas/Zwrot"}],"description":"Tylko przy `platnosc.zwrot` i `platnosc.zwrot_odrzucony`."},"platnosc_cykliczna":{"allOf":[{"$ref":"#/components/schemas/PlatnoscCykliczna"}],"description":"Tylko przy zdarzeniach `platnosc_cykliczna.*`."},"webhook":{"type":["object","null"],"description":"Stan ostatniej dostawy webhooka tego zdarzenia; `null`, gdy sklep nie ma adresu webhooka.","properties":{"status":{"type":"string","enum":["czeka","dostarczony","porzucony"]},"proby":{"type":"integer"},"ostatni_kod":{"type":["integer","null"],"description":"Kod HTTP ostatniej odpowiedzi odbiornika."},"ostatni_blad":{"type":["string","null"]},"nastepna_proba":{"type":["string","null"],"format":"date-time"}}}}},"Lista":{"type":"object","required":["obiekt","adres","dane","ma_wiecej"],"properties":{"obiekt":{"type":"string","const":"lista"},"adres":{"type":"string","description":"Ścieżka listy, np. `/v1/platnosci`."},"dane":{"type":"array","items":{"type":"object"}},"ma_wiecej":{"type":"boolean","description":"Czy są kolejne obiekty za tą stroną (starsze)."},"strona":{"type":"integer","description":"Tylko w stronicowaniu numerem strony."},"stron":{"type":"integer","description":"Tylko w stronicowaniu numerem strony."},"razem":{"type":"integer","description":"Tylko w stronicowaniu numerem strony."}}},"Blad":{"type":"object","required":["blad"],"properties":{"blad":{"type":"object","required":["typ","kod","opis","dokumentacja","zadanie_id"],"properties":{"typ":{"type":"string","enum":["dane_nieprawidlowe","uwierzytelnienie","nie_znaleziono","plan","operator","konflikt","limit","zadanie_nieprawidlowe","blad_serwera"],"description":"Grupa błędu. Obsługuj typ, gdy nie potrzebujesz rozróżniać kodów."},"kod":{"type":"string","description":"Stabilny kod błędu (lista w `x-kody-bledow`)."},"opis":{"type":"string","description":"Opis po polsku, do pokazania w logu albo operatorowi sklepu."},"pole":{"type":"string","description":"Pierwsze pole z błędem (tylko przy błędach pól)."},"pola":{"type":"object","description":"Komunikaty dla wszystkich pól z błędami (tylko przy błędach pól).","additionalProperties":{"type":"array","items":{"type":"string"}}},"dokumentacja":{"type":"string","format":"uri","description":"Opis kodu w dokumentacji."},"zadanie_id":{"type":"string","description":"Identyfikator zapytania, ten sam co nagłówek `X-Request-Id`."},"szczegoly":{"type":"string","description":"Tylko w środowisku deweloperskim przy błędzie serwera."}}}}}},"examples":{"PlatnoscNowa":{"summary":"Świeżo utworzona płatność","value":{"obiekt":"platnosc","id":"tr_8h2k1j0f9e8d7c6b5a4z","tryb":"test","status":"nowa","kwota":12900,"waluta":"PLN","zwrocono":0,"do_zwrotu":0,"numer_zamowienia":"ZAM-2026-001","opis":"Zamówienie ZAM-2026-001","email_klienta":"klient@przyklad.pl","adres_powrotu":"https://twojsklep.pl/zamowienie/ZAM-2026-001/dziekujemy","metoda":null,"metadane":{"koszyk":"c_8812","klient_crm":"4471"},"adres_platnosci":"https://placenie.pl/zaplac/tr_8h2k1j0f9e8d7c6b5a4z","utworzona":"2026-10-03T10:00:00+00:00","oplacona":null,"zwroty":[]}},"PlatnoscOplacona":{"summary":"Płatność po zapłacie BLIK-iem","value":{"obiekt":"platnosc","id":"tr_8h2k1j0f9e8d7c6b5a4z","tryb":"test","status":"oplacona","kwota":12900,"waluta":"PLN","zwrocono":0,"do_zwrotu":12900,"numer_zamowienia":"ZAM-2026-001","opis":"Zamówienie ZAM-2026-001","email_klienta":"klient@przyklad.pl","adres_powrotu":"https://twojsklep.pl/zamowienie/ZAM-2026-001/dziekujemy","metoda":"blik","metadane":{"koszyk":"c_8812","klient_crm":"4471"},"adres_platnosci":"https://placenie.pl/zaplac/tr_8h2k1j0f9e8d7c6b5a4z","utworzona":"2026-10-03T10:00:00+00:00","oplacona":"2026-10-03T10:01:12+00:00","zwroty":[]}},"PlatnoscPoZwrocie":{"summary":"Płatność po zwrocie częściowym","value":{"obiekt":"platnosc","id":"tr_8h2k1j0f9e8d7c6b5a4z","tryb":"test","status":"oplacona","kwota":12900,"waluta":"PLN","zwrocono":2900,"do_zwrotu":10000,"numer_zamowienia":"ZAM-2026-001","opis":"Zamówienie ZAM-2026-001","email_klienta":"klient@przyklad.pl","adres_powrotu":"https://twojsklep.pl/zamowienie/ZAM-2026-001/dziekujemy","metoda":"blik","metadane":{"koszyk":"c_8812","klient_crm":"4471"},"adres_platnosci":"https://placenie.pl/zaplac/tr_8h2k1j0f9e8d7c6b5a4z","utworzona":"2026-10-03T10:00:00+00:00","oplacona":"2026-10-03T10:01:12+00:00","zwroty":[{"obiekt":"zwrot","id":"zw_9f8e7d6c5b4a3z2y1x0w","platnosc":"tr_8h2k1j0f9e8d7c6b5a4z","kwota":2900,"waluta":"PLN","status":"wykonany","zrodlo":"api","utworzony":"2026-10-03T12:30:00+00:00"}]}},"ZdarzenieOplacona":{"summary":"Webhook platnosc.oplacona","value":{"obiekt":"zdarzenie","id":"evt_0a1b2c3d4e5f6g7h8i9j","typ":"platnosc.oplacona","tryb":"test","utworzone":"2026-10-03T10:01:12+00:00","transakcja":{"obiekt":"platnosc","id":"tr_8h2k1j0f9e8d7c6b5a4z","tryb":"test","status":"oplacona","kwota":12900,"waluta":"PLN","zwrocono":0,"do_zwrotu":12900,"numer_zamowienia":"ZAM-2026-001","opis":"Zamówienie ZAM-2026-001","email_klienta":"klient@przyklad.pl","adres_powrotu":"https://twojsklep.pl/zamowienie/ZAM-2026-001/dziekujemy","metoda":"blik","metadane":{"koszyk":"c_8812","klient_crm":"4471"},"adres_platnosci":"https://placenie.pl/zaplac/tr_8h2k1j0f9e8d7c6b5a4z","utworzona":"2026-10-03T10:00:00+00:00","oplacona":"2026-10-03T10:01:12+00:00","zwroty":[]}}}}},"x-kody-bledow":{"description":"Wszystkie kody błędów z `blad.kod`, ich typ i kod HTTP. Opis to domyślny tekst `blad.opis` (konkretne zapytania mogą dostać dokładniejszy).","kody":[{"kod":"dane_nieprawidlowe","typ":"dane_nieprawidlowe","http":422,"opis":"Popraw pola zapytania."},{"kod":"kursor_nieprawidlowy","typ":"dane_nieprawidlowe","http":422,"opis":"Kursor `po` albo `przed` nie wskazuje obiektu z tej listy."},{"kod":"klucz_idempotencji_nieprawidlowy","typ":"dane_nieprawidlowe","http":400,"opis":"Nagłówek Idempotency-Key ma od 1 do 255 znaków drukowalnych."},{"kod":"wersja_nieznana","typ":"zadanie_nieprawidlowe","http":400,"opis":"Nagłówek Placenie-Version wskazuje wersję API, której nie ma."},{"kod":"tylko_piaskownica","typ":"zadanie_nieprawidlowe","http":400,"opis":"Ta operacja działa tylko kluczem testowym (piaskownica)."},{"kod":"metoda_niedozwolona","typ":"zadanie_nieprawidlowe","http":405,"opis":"Ten adres nie obsługuje tej metody HTTP."},{"kod":"klucz_nieprawidlowy","typ":"uwierzytelnienie","http":401,"opis":"Brak albo nieprawidłowy klucz API."},{"kod":"brak_uprawnien","typ":"uwierzytelnienie","http":403,"opis":"Ten klucz nie ma dostępu do tej operacji."},{"kod":"nie_znaleziono","typ":"nie_znaleziono","http":404,"opis":"Nie ma takiego zasobu dla tego klucza."},{"kod":"trasa_nieznana","typ":"nie_znaleziono","http":404,"opis":"Nie ma takiego adresu w API."},{"kod":"waluta_poza_planem","typ":"plan","http":422,"opis":"Ta waluta nie jest w Twoim planie. Wielowalutowość jest w planie Skala."},{"kod":"plan_nieoplacony","typ":"plan","http":402,"opis":"Klucz produkcyjny działa na opłaconym planie. Uruchom plan w panelu."},{"kod":"funkcja_poza_planem","typ":"plan","http":402,"opis":"Płatności cykliczne są w planie Sklep i wyższych. Zmień plan w panelu."},{"kod":"sklep_poza_planem","typ":"plan","http":402,"opis":"Ten sklep jest ponad limit sklepów Twojego planu."},{"kod":"limit_demo","typ":"plan","http":402,"opis":"Konto bez opłaconego planu ma ograniczoną liczbę transakcji testowych (30). Uruchom plan, żeby testować dalej."},{"kod":"operator_niepodlaczony","typ":"operator","http":409,"opis":"Podłącz konto operatora płatności w panelu (Integracja), zanim przyjmiesz prawdziwą płatność."},{"kod":"numer_zamowienia_zajety","typ":"konflikt","http":409,"opis":"Ten numer zamówienia ma już transakcję z inną kwotą albo walutą."},{"kod":"klucz_idempotencji_uzyty","typ":"konflikt","http":409,"opis":"Ten Idempotency-Key był już użyty z innym zapytaniem. Nowy klucz dla nowego zapytania."},{"kod":"klucz_idempotencji_w_toku","typ":"konflikt","http":409,"opis":"Zapytanie z tym Idempotency-Key jest właśnie przetwarzane. Ponów za chwilę."},{"kod":"zwrot_odrzucony","typ":"zadanie_nieprawidlowe","http":422,"opis":"Zwrot nie został przyjęty (płatność nieopłacona, kwota ponad pulę, odmowa operatora)."},{"kod":"stan_nieprawidlowy","typ":"zadanie_nieprawidlowe","http":409,"opis":"Transakcja jest w stanie, który nie pozwala na tę operację."},{"kod":"webhook_nieustawiony","typ":"zadanie_nieprawidlowe","http":409,"opis":"Sklep nie ma adresu webhooka. Ustaw go w panelu (Integracja), potem ponów zdarzenie."},{"kod":"limit_zapytan","typ":"limit","http":429,"opis":"Za dużo zapytań. Odczekaj liczbę sekund z nagłówka Retry-After."},{"kod":"blad_serwera","typ":"blad_serwera","http":500,"opis":"Coś poszło nie tak po naszej stronie. Spróbuj ponownie, a jeśli błąd wraca, podaj zadanie_id wsparciu."}]},"x-piaskownica":{"description":"Piaskownica działa od założenia konta kluczem `plc_test_...`. Konto bez opłaconego planu ma 30 transakcji testowych\n(później 402 `limit_demo`); opłacony plan zdejmuje limit. Pieniądze nie płyną, prowizja testowa to zawsze 0.\nEkran płatności (`adres_platnosci`) prowadzi do banku testowego; wynik wybiera się danymi poniżej.\n","blik":[{"kod":"777777","wynik":"oplacona","opis":"Bank testowy zatwierdza płatność."},{"kod":"111111","wynik":"odrzucona","opis":"Bank testowy odmawia. Płatność wraca do stanu `odrzucona`, klient może spróbować ponownie."},{"kod":"inny sześciocyfrowy","wynik":"błąd formularza","opis":"Ekran prosi o jeden z dwóch kodów powyżej, status bez zmian."}],"karta_i_przelew":[{"przycisk":"Zatwierdź płatność","wynik":"oplacona","opis":"Symulacja 3-D Secure 2 (karta) albo logowania do banku (przelew). Bez numeru karty."},{"przycisk":"Odrzuć w banku","wynik":"odrzucona"}],"api":[{"operacja":"POST /v1/platnosci/{id}/symulacja","cialo":{"wynik":"oplacona","metoda":"card"},"opis":"Wynik bez ekranu, do testów automatycznych; powstaje zdarzenie i webhook."},{"operacja":"POST /v1/platnosci/{id}/symulacja","cialo":{"wynik":"odrzucona"}}],"webhook":{"opis":"Adres webhooka musi być `https` na publicznym hoście (adresy prywatne i lokalne są odrzucane). Do testów lokalnych użyj tunelu (np. cloudflared, ngrok)."}}}