Przejdź do treści

Piaskownica

Klucz testowy działa od założenia konta: pieniądze nie płyną, ekran płatności prowadzi do banku testowego, a webhooki wychodzą tak samo jak w produkcji. Tu są dane testowe, scenariusze, symulacja przez API i lista kontrolna przed przejściem na produkcję.

Klucz testowy #

Klucz plc_test_… wydajesz w panelu, w zakładce Integracja i klucze (przycisk Wydaj klucz przy pozycji Klucz testowy). Nie potrzebujesz karty, planu ani umowy z operatorem. Klucz pokazujemy raz; wymiana wycofuje poprzedni od razu.

Wszystko, co utworzysz tym kluczem, ma tryb: "test" i jest niewidoczne dla klucza produkcyjnego. W panelu transakcje testowe są oznaczone osobno.

Dane testowe #

Ekran płatności (adres_platnosci) w piaskownicy prowadzi do banku testowego. Wynik wybierasz kodem BLIK albo przyciskiem.

MetodaDaneWynikOpis
BLIK 777777 oplacona Bank testowy zatwierdza płatność.
BLIK 111111 odrzucona Bank testowy odmawia. Płatność wraca do stanu odrzucona, klient może spróbować ponownie.
BLIK inny sześciocyfrowy błąd formularza Ekran prosi o jeden z dwóch kodów powyżej, status bez zmian.
Karta, szybki przelew przycisk „Zatwierdź płatność” oplacona Symulacja 3-D Secure 2 (karta) albo logowania do banku (przelew). Bez numeru karty.
Karta, szybki przelew przycisk „Odrzuć w banku” odrzucona

Scenariusze #

Płatność zatwierdzona

Jak: BLIK 777777 albo przycisk Zatwierdź płatność

Wynik: status oplacona, webhook platnosc.oplacona, oplacona z czasem księgowania, do_zwrotu równe kwocie

Odmowa banku i druga próba

Jak: BLIK 111111, potem 777777 z tego samego adresu

Wynik: najpierw odrzucona i platnosc.odrzucona, potem oplacona i platnosc.oplacona dla tej samej płatności

Zwrot częściowy

Jak: POST /v1/platnosci/{id}/zwroty z kwota

Wynik: status bez zmian, zwrocono rośnie, do_zwrotu maleje, zdarzenie platnosc.zwrot z polem zwrot

Zwrot pełny

Jak: POST /v1/platnosci/{id}/zwroty bez ciała

Wynik: status zwrocona, do_zwrotu równe 0

Zwrot ponad pulę

Jak: kwota większa niż do_zwrotu

Wynik: 422 zwrot_odrzucony z opisem kwoty, stan bez zmian

Powtórzone zamówienie

Jak: drugi POST z tym samym numer_zamowienia, kwotą i walutą

Wynik: 200 z tą samą płatnością; inna kwota to 409 numer_zamowienia_zajety

Ponowienie po przerwaniu

Jak: ten sam Idempotency-Key i ta sama treść

Wynik: zapisana odpowiedź z nagłówkiem Idempotent-Replayed: true, nic nie wykonuje się drugi raz

Waluta spoza planu

Jak: waluta EUR bez planu Skala

Wynik: 422 waluta_poza_planem

Koniec limitu demo

Jak: 31. płatność bez opłaconego planu

Wynik: 402 limit_demo

Za dużo zapytań

Jak: ponad 120 zapytań w minucie jednym kluczem

Wynik: 429 limit_zapytan z nagłówkiem Retry-After

Symulacja wyniku przez API #

Do testów automatycznych służy POST /v1/platnosci/{id}/symulacja: ustawia wynik bez ekranu, tą samą drogą co bank testowy, więc powstaje zdarzenie i idzie webhook. Pole wynik to oplacona albo odrzucona, opcjonalne metoda (blik, card, transfer) zapisuje się przy płatności.

  • Tylko klucz testowy. Kluczem produkcyjnym: 400 tylko_piaskownica.
  • Tylko płatność w stanie nowa albo odrzucona. Dla oplacona i zwrocona: 409 stan_nieprawidlowy.
  • Po odrzucona możesz zasymulować drugą próbę z wynikiem oplacona, tak jak klient na ekranie.
curl -X POST "https://placenie.pl/api/v1/platnosci/tr_8h2k1j0f9e8d7c6b5a4z/symulacja" \
  -H "Authorization: Bearer plc_test_..." \
  -H "Content-Type: application/json" \
  -d '{
      "wynik": "oplacona",
      "metoda": "blik"
  }'
$ch = curl_init('https://placenie.pl/api/v1/platnosci/tr_8h2k1j0f9e8d7c6b5a4z/symulacja');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'POST',
    CURLOPT_HTTPHEADER => [
        'Authorization: Bearer plc_test_...',
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => json_encode([
        'wynik' => 'oplacona',
        'metoda' => 'blik',
    ]),
    CURLOPT_RETURNTRANSFER => true,
]);

$platnosc = json_decode(curl_exec($ch), true);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);

if ($status >= 400) {
    throw new RuntimeException($platnosc['blad']['kod'].': '.$platnosc['blad']['opis']);
}
const odpowiedz = await fetch('https://placenie.pl/api/v1/platnosci/tr_8h2k1j0f9e8d7c6b5a4z/symulacja', {
  method: 'POST',
  headers: {
    Authorization: 'Bearer plc_test_...',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    wynik: 'oplacona',
    metoda: 'blik',
  }),
});

const platnosc = await odpowiedz.json();

if (!odpowiedz.ok) {
  throw new Error(`${platnosc.blad.kod}: ${platnosc.blad.opis}`);
}
import requests

odpowiedz = requests.post(
    "https://placenie.pl/api/v1/platnosci/tr_8h2k1j0f9e8d7c6b5a4z/symulacja",
    headers={"Authorization": "Bearer plc_test_..."},
    json={
        "wynik": "oplacona",
        "metoda": "blik",
    },
)
platnosc = odpowiedz.json()

if not odpowiedz.ok:
    raise RuntimeError(f"{platnosc['blad']['kod']}: {platnosc['blad']['opis']}")
Odpowiedź 200
{
    "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": "[email protected]",
    "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": []
}

Czym piaskownica różni się od produkcji #

ElementPiaskownica (plc_test_)Produkcja (plc_live_)
Dostępod założenia kontaopłacony plan i podłączone konto operatora
Ekran płatnościbank testowy (kody BLIK i przyciski)formularz operatora płatności, prawdziwy bank
Status oczekujenie występujepo przejściu klienta do operatora, do czasu wyniku; GET odświeża stan u operatora
Zwrotyod razu wykonanymogą być zlecony u operatora, a potem wykonany albo odrzucony (platnosc.zwrot_odrzucony)
SymulacjaPOST /v1/platnosci/{id}/symulacja400 tylko_piaskownica
Pieniądze i prowizjanie płyną, prowizja 0rozlicza operator, prowizja według planu
Webhooki, podpis, ponowienia, APIidentyczne

Limity #

LimitWartośćPo przekroczeniu
Płatności testowe bez opłaconego planu30 na konto402 limit_demo; opłacony plan zdejmuje limit
Zapytania do API120 na minutę na klucz429 limit_zapytan, Retry-After w sekundach
Specyfikacja openapi.json60 na minutę na adres IP429
Kwota płatności100 do 99 999 999 groszy422 dane_nieprawidlowe
Metadane50 kluczy, klucz 40, wartość 500 znaków422 dane_nieprawidlowe
Obiekty na stronie listy1 do 100 (limit)422 dane_nieprawidlowe
Klucz idempotencji1 do 255 znaków, ważny 24 h400 klucz_idempotencji_nieprawidlowy
Czas odpowiedzi odbiornika webhooka8 sponowienie według harmonogramu

Przejście na produkcję #

Produkcja różni się od piaskownicy tylko kluczem i tym, że po drugiej stronie stoi operator płatności. Kod, który przeszedł scenariusze powyżej, przechodzi na produkcję bez zmian, jeśli obsługuje stany, których piaskownica nie pokazuje.

  1. 1

    Opłacony plan

    Klucz produkcyjny i podłączenie operatora działają w opłaconym planie. Plan uruchamiasz samodzielnie w panelu; ceny są na stronie cennika.

  2. 2

    Konto operatora płatności

    W panelu, w Integracja i klucze, podłącz konto operatora (dziś PayU: id punktu płatności, drugi klucz MD5, client_id i client_secret). Bez tego POST /v1/platnosci kluczem produkcyjnym zwraca 409 operator_niepodlaczony.

  3. 3

    Klucz produkcyjny

    Wydaj plc_live_… w panelu i trzymaj go w konfiguracji serwera, nigdy w repozytorium ani w kodzie przeglądarki. Klucz produkcyjny widzi tylko transakcje produkcyjne.

  4. 4

    Webhook i sekret

    Adres https na publicznym hoście, sekret podpisu w konfiguracji, weryfikacja podpisu z tolerancją 300 sekund, odpowiedź 2xx w mniej niż 8 sekund.

  5. 5

    Stany, których nie ma w piaskownicy

    Status oczekuje (klient u operatora), zwrot zlecony i zdarzenie platnosc.zwrot_odrzucony. Nie wydawaj towaru przy oczekuje.

  6. 6

    Potwierdzenie zapłaty

    Towar albo usługa wychodzi po webhooku platnosc.oplacona albo po GET ze statusem oplacona, nigdy po samym powrocie klienta na adres_powrotu.

  7. 7

    Idempotencja

    Idempotency-Key przy każdym POST, który tworzy płatność albo zwrot; numer_zamowienia przy każdej płatności.

  8. 8

    Obsługa błędów

    Kod obsługuje blad.typ (grupa) i loguje blad.zadanie_id (ten sam co X-Request-Id). 429 ponawia po Retry-After.

  9. 9

    Zgodność w przód

    Klient ignoruje nieznane pola w odpowiedziach; nowe pola dochodzą bez zmiany wersji.