Przejdź do treści
Oplac

Zacznij

Szybki start z pierwszą płatnością w 5 minut

Pięć kroków od założenia konta do działającego webhooka. Każdy krok ma orientacyjny czas i gotowe żądanie w czterech językach. Pracujesz na kluczu testowym sk_test_, więc nic nie kosztuje i nie rusza pieniędzy. Na końcu zamieniasz klucz na produkcyjny i reszta zostaje bez zmian.

Klucz testowy w przykładach

Wklej klucz sk_test_ z panelu (zakładka Deweloperzy), a każdy przykład będzie gotowy do uruchomienia. Klucz zostaje w tej karcie przeglądarki, nie wysyłamy go nigdzie.

Przykłady używają Twojego klucza testowego. Produkcyjnego klucza nie przyjmujemy.

Tryb testowy

Zanim zaczniesz#

Potrzebujesz adresu e-mail, terminala z curl albo dowolnego języka z klientem HTTP i serwera, który przyjmie żądanie POST z publicznego internetu (do webhooka). Do testów bez publicznego adresu zamiast kroku 4 użyj zdarzenia próbnego i podglądu zdarzeń w panelu.

  • Adres API: https://oplac.pl/api, wszystkie trasy pod /v1.
  • Treść żądań i odpowiedzi to JSON. Kwoty w groszach, czas jako znacznik Unix. Reszta konwencji w Konwencje.
  • Nie ma biblioteki SDK do zainstalowania. Przykłady używają wbudowanego curl w PHP, fetch w Node i requests w Pythonie.

Krok 1. Klucz testowy (1 minuta)#

Kliknij Zacznij przyjmować płatności, podaj adres e-mail i wpisz kod z maila. Otwiera się panel w piaskownicy. W zakładce Deweloperzy kliknij Utwórz klucz przy kluczu testowym i skopiuj wartość sk_test_... od razu: pełny klucz widać tylko raz, w bazie zostaje wyłącznie jego skrót.

Wklej klucz w karcie Klucz testowy w przykładach na górze tej strony. Od tej chwili każdy przykład w dokumentacji jest gotowy do uruchomienia. Klucz zostaje w Twojej przeglądarce i nigdzie go nie wysyłamy.

Sprawdź klucz pierwszym wywołaniem: GET /v1/account zwraca plan, moduły i to, czy konto przyjmuje płatności.

curl https://oplac.pl/api/v1/account \
  -H "Authorization: Bearer sk_test_TWOJ_KLUCZ"
$ch = curl_init('https://oplac.pl/api/v1/account');
curl_setopt_array($ch, [
    CURLOPT_HTTPHEADER => ['Authorization: Bearer sk_test_TWOJ_KLUCZ'],
    CURLOPT_RETURNTRANSFER => true,
]);
$account = json_decode(curl_exec($ch), true);
const res = await fetch('https://oplac.pl/api/v1/account', {
  headers: { Authorization: 'Bearer sk_test_TWOJ_KLUCZ' },
});
const account = await res.json();
import requests

res = requests.get(
    "https://oplac.pl/api/v1/account",
    headers={"Authorization": "Bearer sk_test_TWOJ_KLUCZ"},
)
account = res.json()
Odpowiedź
{
  "id": "acct_Ab12Cd34Ef56Gh",
  "object": "account",
  "name": "Sklep Testowy",
  "plan": "demo",
  "modules": ["accept", "api", "plan"],
  "currencies": ["PLN"],
  "charges_enabled": true,
  "provider_connected": false,
  "webhook_configured": false,
  "livemode": false,
  "created": 1760000000
}

Krok 2. Utwórz płatność (1 minuta)#

Jedno żądanie POST /v1/payments. Wymagane są tylko amount w groszach i currency. Podaj też return_url, na który klient wróci po zapłacie, i metadata z numerem zamówienia, żeby webhook dało się dopasować do Twojej bazy. Nagłówek Idempotency-Key sprawia, że ponowione żądanie (timeout, błąd sieci) nie utworzy drugiej płatności.

W odpowiedzi dostajesz obiekt payment ze statusem pending i polem checkout_url. To hostowana strona płatności: w piaskownicy u nas, z testowymi kodami BLIK, w produkcji u operatora płatności Twojego konta.

curl https://oplac.pl/api/v1/payments \
  -H "Authorization: Bearer sk_test_TWOJ_KLUCZ" \
  -H "Idempotency-Key: 5f0c2a4e-7d1b-4e8a-9b2f-1c3d5e7f9a0b" \
  -H "Content-Type: application/json" \
  -d '{
    "amount": 12900,
    "currency": "PLN",
    "description": "Zamówienie 10482",
    "return_url": "https://sklep.example.com/powrot",
    "metadata": {"order_id": "10482"}
  }'
$ch = curl_init('https://oplac.pl/api/v1/payments');
curl_setopt_array($ch, [
    CURLOPT_POST => true,
    CURLOPT_HTTPHEADER => [
        'Authorization: Bearer sk_test_TWOJ_KLUCZ',
        'Idempotency-Key: 5f0c2a4e-7d1b-4e8a-9b2f-1c3d5e7f9a0b',
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => json_encode([
        'amount' => 12900,
        'currency' => 'PLN',
        'description' => 'Zamówienie 10482',
        'return_url' => 'https://sklep.example.com/powrot',
        'metadata' => ['order_id' => '10482'],
    ]),
    CURLOPT_RETURNTRANSFER => true,
]);
$payment = json_decode(curl_exec($ch), true);

header('Location: ' . $payment['checkout_url'], true, 302);
const res = await fetch('https://oplac.pl/api/v1/payments', {
  method: 'POST',
  headers: {
    Authorization: 'Bearer sk_test_TWOJ_KLUCZ',
    'Idempotency-Key': '5f0c2a4e-7d1b-4e8a-9b2f-1c3d5e7f9a0b',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    amount: 12900,
    currency: 'PLN',
    description: 'Zamówienie 10482',
    return_url: 'https://sklep.example.com/powrot',
    metadata: { order_id: '10482' },
  }),
});
const payment = await res.json();

reply.redirect(payment.checkout_url);
import requests

res = requests.post(
    "https://oplac.pl/api/v1/payments",
    headers={
        "Authorization": "Bearer sk_test_TWOJ_KLUCZ",
        "Idempotency-Key": "5f0c2a4e-7d1b-4e8a-9b2f-1c3d5e7f9a0b",
    },
    json={
        "amount": 12900,
        "currency": "PLN",
        "description": "Zamówienie 10482",
        "return_url": "https://sklep.example.com/powrot",
        "metadata": {"order_id": "10482"},
    },
)
payment = res.json()

return redirect(payment["checkout_url"], code=302)
Odpowiedź
HTTP/1.1 201 Created
X-Request-Id: req_7mK2pQ9rT4vX1bN8cD3fG6hJ
{
  "id": "pay_Ab12Cd34Ef56Gh",
  "object": "payment",
  "amount": 12900,
  "currency": "PLN",
  "status": "pending",
  "description": "Zamówienie 10482",
  "checkout_url": "https://oplac.pl/p/Ab12Cd34Ef56Gh",
  "return_url": "https://sklep.example.com/powrot",
  "metadata": {"order_id": "10482"},
  "livemode": false,
  "expires_at": 1760086400,
  "created": 1760000000
}

Krok 3. Zapłać w piaskownicy (1 minuta)#

Otwórz checkout_url z odpowiedzi w przeglądarce. Strona piaskownicy wygląda jak strona płatności klienta: wybierz BLIK i wpisz kod 777 123. Płatność przechodzi w status succeeded, a przeglądarka wraca na return_url z parametrem ?payment=pay_.... Kod 777 000 daje odmowę (failed, blik_rejected), 777 408 zły kod. Przy karcie zamiast numeru są dwa przyciski wyniku.

Nie chcesz klikać? Ten sam wynik ustawisz żądaniem POST /v1/test_helpers/payments/{id}/confirm. Uruchamia dokładnie te same zdarzenia i webhooki co zapłata na stronie.

Po powrocie klienta nigdy nie ufaj samemu adresowi: potwierdź stan żądaniem GET /v1/payments/{id} (status succeeded), a zamówienie oznaczaj dopiero po zdarzeniu z webhooka z kroku 4.

curl https://oplac.pl/api/v1/test_helpers/payments/pay_Ab12Cd34Ef56Gh/confirm \
  -H "Authorization: Bearer sk_test_TWOJ_KLUCZ" \
  -H "Content-Type: application/json" \
  -d '{"blik_code": "777123"}'
$ch = curl_init('https://oplac.pl/api/v1/test_helpers/payments/pay_Ab12Cd34Ef56Gh/confirm');
curl_setopt_array($ch, [
    CURLOPT_POST => true,
    CURLOPT_HTTPHEADER => ['Authorization: Bearer sk_test_TWOJ_KLUCZ', 'Content-Type: application/json'],
    CURLOPT_POSTFIELDS => json_encode(['blik_code' => '777123']),
    CURLOPT_RETURNTRANSFER => true,
]);
$payment = json_decode(curl_exec($ch), true);
const res = await fetch('https://oplac.pl/api/v1/test_helpers/payments/pay_Ab12Cd34Ef56Gh/confirm', {
  method: 'POST',
  headers: { Authorization: 'Bearer sk_test_TWOJ_KLUCZ', 'Content-Type': 'application/json' },
  body: JSON.stringify({ blik_code: '777123' }),
});
const payment = await res.json();
import requests

res = requests.post(
    "https://oplac.pl/api/v1/test_helpers/payments/pay_Ab12Cd34Ef56Gh/confirm",
    headers={"Authorization": "Bearer sk_test_TWOJ_KLUCZ"},
    json={"blik_code": "777123"},
)
payment = res.json()
Odpowiedź
HTTP/1.1 200 OK
{
  "id": "pay_Ab12Cd34Ef56Gh",
  "object": "payment",
  "amount": 12900,
  "currency": "PLN",
  "status": "succeeded",
  "method": "blik",
  "paid_at": 1760000040,
  "metadata": {"order_id": "10482"},
  "livemode": false
}

Krok 4. Odbierz webhook (2 minuty)#

Zapisz adres webhooka żądaniem POST /v1/webhook_endpoints (albo w panelu, w zakładce Deweloperzy). Odpowiedź zawiera sekret whsec_, który wraca tylko raz: zapisz go w konfiguracji serwera. Od tej chwili każde zdarzenie z listy enabled_events przychodzi jako POST z JSON obiektu event i nagłówkiem Oplac-Signature.

Twój odbiorca robi trzy rzeczy: sprawdza podpis HMAC SHA-256 (sekret, ciąg <t>.<surowa treść>), odpowiada 200 w ciągu 10 sekund i obsługuje zdarzenie idempotentnie po id, bo to samo zdarzenie może przyjść więcej niż raz. Gotowe funkcje w PHP, Node i Pythonie są w przewodniku Webhooki.

Przy payment.succeeded odczytaj data.object.metadata.order_id i oznacz zamówienie jako opłacone. Teraz powtórz krok 3: webhook powinien dotrzeć w ciągu sekundy, a historia dostarczeń jest w panelu i pod GET /v1/events.

curl https://oplac.pl/api/v1/webhook_endpoints \
  -H "Authorization: Bearer sk_test_TWOJ_KLUCZ" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://sklep.example.com/oplac/webhook",
    "enabled_events": ["payment.succeeded", "payment.failed", "refund.succeeded"]
  }'
$ch = curl_init('https://oplac.pl/api/v1/webhook_endpoints');
curl_setopt_array($ch, [
    CURLOPT_POST => true,
    CURLOPT_HTTPHEADER => ['Authorization: Bearer sk_test_TWOJ_KLUCZ', 'Content-Type: application/json'],
    CURLOPT_POSTFIELDS => json_encode([
        'url' => 'https://sklep.example.com/oplac/webhook',
        'enabled_events' => ['payment.succeeded', 'payment.failed', 'refund.succeeded'],
    ]),
    CURLOPT_RETURNTRANSFER => true,
]);
$endpoint = json_decode(curl_exec($ch), true);
// $endpoint['secret'] zapisz w konfiguracji: nie wraca w GET
const res = await fetch('https://oplac.pl/api/v1/webhook_endpoints', {
  method: 'POST',
  headers: { Authorization: 'Bearer sk_test_TWOJ_KLUCZ', 'Content-Type': 'application/json' },
  body: JSON.stringify({
    url: 'https://sklep.example.com/oplac/webhook',
    enabled_events: ['payment.succeeded', 'payment.failed', 'refund.succeeded'],
  }),
});
const endpoint = await res.json();
// endpoint.secret zapisz w konfiguracji: nie wraca w GET
import requests

res = requests.post(
    "https://oplac.pl/api/v1/webhook_endpoints",
    headers={"Authorization": "Bearer sk_test_TWOJ_KLUCZ"},
    json={
        "url": "https://sklep.example.com/oplac/webhook",
        "enabled_events": ["payment.succeeded", "payment.failed", "refund.succeeded"],
    },
)
endpoint = res.json()
# endpoint["secret"] zapisz w konfiguracji: nie wraca w GET
Odpowiedź
HTTP/1.1 201 Created
{
  "id": "we_test_Ab12Cd34Ef56Gh",
  "object": "webhook_endpoint",
  "url": "https://sklep.example.com/oplac/webhook",
  "enabled_events": ["payment.succeeded", "payment.failed", "refund.succeeded"],
  "status": "enabled",
  "secret": "whsec_Ab12Cd34Ef56Gh78Ij90Kl12Mn34Op56Qr78St90",
  "livemode": false,
  "created": 1760000000
}

Krok 5. Produkcja (bez zmian w kodzie)#

Produkcję włączasz sam w panelu: wybierasz plan z cennika, w zakładce Deweloperzy wklejasz klucz operatora płatności swojego konta (sekcja Dostawca) i tworzysz klucz sk_live_. Zapisz też produkcyjny adres webhooka, bo adres i sekret są osobne dla każdego trybu.

W kodzie zmieniasz wyłącznie klucz. Trasy, pola, zdarzenia i obiekty są identyczne, a livemode: true w odpowiedziach mówi, że pieniądze są prawdziwe. Obiekty testowe i produkcyjne nie widzą się nawzajem: sk_live_ nie znajdzie płatności pay_ utworzonej w piaskownicy.

  • Strona płatności w produkcji działa u operatora płatności Twojego konta; Oplac nie przyjmuje ani nie przechowuje środków.
  • Pomocnicy testowi (/v1/test_helpers) z kluczem sk_live_ zwracają 403 test_helpers_live_mode.
  • Limit zapytań rośnie z 25 do 100 na sekundę. Szczegóły w Limity zapytań.

Co dalej#

  • Hostowana strona płatności: pełny przepływ z checkout_url, return_url i wygasaniem.
  • Webhooki: weryfikacja podpisu w PHP, Node i Pythonie, ponowienia, obsługa idempotentna.
  • Błędy: jeden obiekt błędu i katalog kodów, do którego prowadzi doc_url.
  • Referencja API: każdy zasób i każda operacja.

Powiązane

Klucz testowy dostajesz od razu po zapisie

Adres e-mail, kod z maila i piaskownica z kodami BLIK. Produkcję włączasz sam w panelu: plan, dostawca płatności, klucz sk_live_. Wolisz, żeby wdrożenie w sklepie zrobił nasz zespół? To też jest za darmo.

Zamów integrację za darmo

BLIK, karty, subskrypcje i KSeF w jednym panelu.