Przejdź do treści
Oplac

Zacznij

Hostowana strona płatności

Najprostsza integracja: Twój serwer tworzy płatność i przekierowuje klienta na checkout_url. Stronę płatności, metody (BLIK, karta, Apple Pay, Google Pay, szybki przelew), 3D Secure i obsługę błędów bierze na siebie strona hostowana. Klient wraca na return_url, a Twój system dowiaduje się o wyniku z webhooka. Nie dotykasz danych kart i nie potrzebujesz formularza płatności.

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

Przepływ krok po kroku#

  1. 01Klient klika „Zapłać” w Twoim sklepie. Serwer wywołuje POST /v1/payments z kwotą, walutą, return_url i metadata z numerem zamówienia.
  2. 02Serwer odpowiada przekierowaniem 302 na checkout_url z odpowiedzi (albo oddaje adres aplikacji, która go otwiera).
  3. 03Klient płaci na stronie hostowanej. W piaskownicy to strona Oplac z kodami BLIK; w produkcji strona operatora płatności Twojego konta.
  4. 04Po zapłacie klient wraca na return_url z parametrem ?payment=pay_.... Pokaż stronę „Dziękujemy” i sprawdź stan żądaniem GET /v1/payments/{id}.
  5. 05Niezależnie od powrotu Twój serwer dostaje zdarzenie payment.succeeded albo payment.failed. Na nim oznaczasz zamówienie, bo klient może zamknąć kartę przed powrotem.

Płatność żyje domyślnie 24 godziny (expires_at). Po tym czasie strona przestaje przyjmować zapłatę, płatność dostaje status canceled i przychodzi zdarzenie payment.canceled. Krótszy termin ustawisz polem expires_at (znacznik Unix w przyszłości).

curl https://oplac.pl/api/v1/payments \
  -H "Authorization: Bearer sk_test_TWOJ_KLUCZ" \
  -H "Idempotency-Key: zamowienie-10482" \
  -H "Content-Type: application/json" \
  -d '{
    "amount": 12900,
    "currency": "PLN",
    "description": "Zamówienie 10482",
    "return_url": "https://sklep.example.com/zamowienie/10482/powrot",
    "expires_at": 1760003600,
    "customer": {"email": "[email protected]", "name": "Anna Nowak"},
    "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: zamowienie-10482',
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => json_encode([
        'amount' => 12900,
        'currency' => 'PLN',
        'description' => 'Zamówienie 10482',
        'return_url' => 'https://sklep.example.com/zamowienie/10482/powrot',
        'expires_at' => time() + 3600,
        'customer' => ['email' => '[email protected]', 'name' => 'Anna Nowak'],
        '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': 'zamowienie-10482',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    amount: 12900,
    currency: 'PLN',
    description: 'Zamówienie 10482',
    return_url: 'https://sklep.example.com/zamowienie/10482/powrot',
    expires_at: Math.floor(Date.now() / 1000) + 3600,
    customer: { email: '[email protected]', name: 'Anna Nowak' },
    metadata: { order_id: '10482' },
  }),
});
const payment = await res.json();

reply.redirect(payment.checkout_url);
import time
import requests

res = requests.post(
    "https://oplac.pl/api/v1/payments",
    headers={
        "Authorization": "Bearer sk_test_TWOJ_KLUCZ",
        "Idempotency-Key": "zamowienie-10482",
    },
    json={
        "amount": 12900,
        "currency": "PLN",
        "description": "Zamówienie 10482",
        "return_url": "https://sklep.example.com/zamowienie/10482/powrot",
        "expires_at": int(time.time()) + 3600,
        "customer": {"email": "[email protected]", "name": "Anna Nowak"},
        "metadata": {"order_id": "10482"},
    },
)
payment = res.json()

return redirect(payment["checkout_url"], code=302)
Odpowiedź
HTTP/1.1 201 Created
{
  "id": "pay_Ab12Cd34Ef56Gh",
  "object": "payment",
  "amount": 12900,
  "currency": "PLN",
  "status": "pending",
  "checkout_url": "https://oplac.pl/p/Ab12Cd34Ef56Gh",
  "return_url": "https://sklep.example.com/zamowienie/10482/powrot",
  "customer": "cus_Xy98Zw76Vu54Ts",
  "customer_email": "[email protected]",
  "metadata": {"order_id": "10482"},
  "livemode": false,
  "expires_at": 1760003600,
  "created": 1760000000
}

Powrót klienta na return_url#

Klient wraca na return_url z parametrem payment równym identyfikatorowi płatności. Adres powrotu to sygnał, nie dowód: parametr można wpisać ręcznie, a klient może wrócić zanim operator potwierdzi zapłatę. Dlatego na stronie powrotu zawsze pobierz płatność i pokaż stan według pola status.

Status po powrocieCo pokazać
succeeded potwierdzenie i dalsze kroki zamówienia
processing, requires_confirmation „płatność jest w trakcie”, odśwież po chwili albo czekaj na webhook
pending klient wrócił bez zapłaty; pokaż przycisk „Zapłać ponownie” z tym samym checkout_url
failed odmowa; powód w failure_code, zaproponuj inną metodę nową płatnością
canceled płatność wygasła albo została anulowana; utwórz nową
curl https://oplac.pl/api/v1/payments/pay_Ab12Cd34Ef56Gh \
  -H "Authorization: Bearer sk_test_TWOJ_KLUCZ"
$id = preg_replace('/[^A-Za-z0-9_]/', '', $_GET['payment'] ?? '');
$ch = curl_init('https://oplac.pl/api/v1/payments/' . $id);
curl_setopt_array($ch, [
    CURLOPT_HTTPHEADER => ['Authorization: Bearer sk_test_TWOJ_KLUCZ'],
    CURLOPT_RETURNTRANSFER => true,
]);
$payment = json_decode(curl_exec($ch), true);

if (($payment['status'] ?? null) === 'succeeded') {
    // pokaż potwierdzenie; zamówienie oznacza webhook payment.succeeded
}
const id = String(req.query.payment || '').replace(/[^A-Za-z0-9_]/g, '');
const res = await fetch(`https://oplac.pl/api/v1/payments/${id}`, {
  headers: { Authorization: 'Bearer sk_test_TWOJ_KLUCZ' },
});
const payment = await res.json();

if (payment.status === 'succeeded') {
  // pokaż potwierdzenie; zamówienie oznacza webhook payment.succeeded
}
import re
import requests

payment_id = re.sub(r"[^A-Za-z0-9_]", "", request.args.get("payment", ""))
res = requests.get(
    f"https://oplac.pl/api/v1/payments/{payment_id}",
    headers={"Authorization": "Bearer sk_test_TWOJ_KLUCZ"},
)
payment = res.json()

if payment.get("status") == "succeeded":
    pass  # pokaż potwierdzenie; zamówienie oznacza webhook payment.succeeded
Odpowiedź
HTTP/1.1 200 OK
{
  "id": "pay_Ab12Cd34Ef56Gh",
  "object": "payment",
  "status": "succeeded",
  "method": "blik",
  "amount": 12900,
  "currency": "PLN",
  "paid_at": 1760000040,
  "metadata": {"order_id": "10482"},
  "livemode": false
}

Dane klienta i NIP#

Pole customer przyjmuje identyfikator istniejącego klienta cus_ albo obiekt z email, name, tax_id i address; wtedy klient powstaje razem z płatnością i jego identyfikator wraca w odpowiedzi. Dzięki temu płatności, subskrypcje i faktury jednej osoby są połączone, a strona płatności ma wstępnie wypełniony adres e-mail. Jeśli klient poda NIP na stronie płatności, znajdziesz go w polu tax_id płatności. Zapisane metody płatności przechowuje operator płatności, nie Oplac.

Produkcja i rola operatora płatności#

W trybie produkcyjnym checkout_url prowadzi na stronę płatności operatora płatności podpiętego do Twojego konta; dane kart i 3D Secure zostają po jego stronie. Płatność produkcyjna bez podpiętego operatora kończy się błędem 402 provider_not_connected. Przy Smart routingu (plan Skala) pole provider_account mówi, które konto operatora obsłużyło płatność; przy Connect (plan Platforma) płatność trafia do sprzedawcy platformy z pola connected_account po potrąceniu application_fee.

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.