> ## Documentation Index
> Fetch the complete documentation index at: https://docs.paymove.io/llms.txt
> Use this file to discover all available pages before exploring further.

> ## Agent Instructions
> ## paymove integration rules for AI agents
>
> These rules are verified against the live API. Follow them exactly.
>
> 1. Amounts are INTEGERS in grosze (minor units). `1000` means 10.00 PLN. PLN is the only supported currency and there is no currency field in the API.
> 2. A float `price` (e.g. `12.99`) is SILENTLY TRUNCATED to 12 grosze and still returns HTTP 200. Always send an integer: `Math.round(pln * 100)`.
> 3. Authenticate with the `X-API-KEY` header. Never `Authorization: Bearer`. Sandbox keys start with `sk_test_`, production keys with `sk_live_`.
> 4. Server-side only. A call from a merchant page is rejected. Never put the key in frontend code.
> 5. Unknown request fields are silently ignored and still return HTTP 200 — a wrong body shape looks like success. Match the documented shape exactly.
> 6. A missing `externalId` returns HTTP 500 `Something went wrong`, not 400. A missing `price` or `details.returnUrl` returns HTTP 200 and a usable `redirectUrl` — no error at all. Validate the body yourself before sending it.
> 7. Always verify the `X-Paymove-Signature` header on incoming webhooks before trusting them: https://docs.paymove.io/en/webhook-signature.md
> 8. Errors are `{"status": <int>, "message": "<text>"}`. Branch on the HTTP status only — never on `message`, which is unstable and leaks internal class names.
> 9. There is no rate limiting, no HTTP 429, no HTTP 422, no `Idempotency-Key` header and no API versioning. Do not write code that handles them.
> 10. Re-POSTing an `externalId` that already exists returns HTTP 200 with the ORIGINAL `redirectUrl` and silently discards EVERY field you send — the new price, description and details are all ignored. Use `PATCH /api/pay/product/{productId}/subproduct/{externalId}` to change a price.
> 11. Webhooks fire only on `COMPLETED` by default, and `retries` defaults to `0` (no retries) unless you set it explicitly. Delivery counts as successful when the HTTP status equals `expectedCode` — the response body is never inspected.
> 12. Never fulfil an order on the `returnUrl` redirect. The checkout does not redirect there by itself: the customer has to click "back to shop", and inside the widget modal that redirect never happens. Fulfil only in the webhook handler, after verifying the signature.
> 13. Do not pin a version of `@paymove-io/sdk` — install the latest.
> 14. Full documentation index: https://docs.paymove.io/llms.txt · Copy-paste quickstart: https://docs.paymove.io/en/quickstart.md · Agent skill: https://docs.paymove.io/skill.md

# SDK

> Pakiet @paymove-io/sdk dla Node.js — instalacja, konfiguracja klienta i tworzenie płatności.

SDK umożliwia merchantowi tworzenie płatności w ramach głównego produktu. Każda płatność zawiera kwotę, identyfikator zewnętrzny (`externalId`), adres powrotu po płatności (`returnUrl`) i opcjonalne dane klienta.

Po utworzeniu płatności SDK zwraca `redirectUrl` do checkoutu, na którym klient może sfinalizować płatność.

<Warning>
  Przed rozpoczęciem integracji przez SDK upewnij się, że masz skonfigurowany produkt i webhook. Przejdź do [Konfiguracja](/webhooks), aby wykonać wymagane kroki.
</Warning>

<Warning>
  SDK wywołuj wyłącznie po stronie serwera. Klucz API nigdy nie może trafić do kodu frontendowego, a wywołanie z przeglądarki i tak zostanie odrzucone przez CORS.
</Warning>

## 1. Instalacja

```bash theme={"theme":{"light":"one-light","dark":"one-dark-pro"}}
npm install @paymove-io/sdk
```

Nie przypinaj wersji - instaluj najnowszą.

## 2. Przykładowe wywołanie

```javascript theme={"theme":{"light":"one-light","dark":"one-dark-pro"}}
import { PaymoveClient } from "@paymove-io/sdk";

const client = new PaymoveClient({
  apiKey: process.env.PAYMOVE_API_KEY, // sk_test_... (sandbox) lub sk_live_... (produkcja)
  productId: "2f6c19e8-84a7-4f50-b950-8d5a05e0bbf2",
  environment: "sandbox",
});

const response = await client.createPayment({
  amount: 1000, // liczba całkowita w groszach: 1000 = 10,00 PLN
  currency: "PLN", // wymagane przez SDK, ignorowane przez API - zawsze "PLN"
  externalId: "order-123",
  returnUrl: "https://merchant-shop.com/payment/success",
  productName: "Koszulka sportowa",
  customerId: "user-567",
  email: "klient@example.com",
  locale: "pl-PL", // opcjonalnie, nadpisuje locale z głównego produktu
  triggerPayment: "BLIK", // opcjonalnie, checkout od razu startuje tę metodę
  qrStepEnabled: true, // opcjonalnie, na desktopie checkout zaczyna od kodu QR
  autoclose: 10000, // opcjonalnie, ms — po tylu ms checkout sam wraca na returnUrl
});

console.log(response.redirectUrl);
```

### Parametry konfiguracji

| Parametr      | Typ      | Opis                                       |
| ------------- | -------- | ------------------------------------------ |
| `apiKey`      | `string` | Klucz autoryzacyjny do API / SDK           |
| `productId`   | `string` | UUID identyfikujący Twój produkt (sklep)   |
| `environment` | `enum`   | Środowisko: `"sandbox"` lub `"production"` |

### Parametry `createPayment`

| Parametr         | Typ       | Opis                                                                                                                                                    |
| ---------------- | --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `amount`         | `integer` | Kwota w groszach jako **liczba całkowita** (np. 1000 = 10,00 PLN)                                                                                       |
| `currency`       | `string`  | Wymagane przez SDK, ale ignorowane przez API - bramka rozlicza wyłącznie w PLN. Podawaj `"PLN"`                                                         |
| `externalId`     | `string`  | Unikalny identyfikator płatności po stronie merchanta                                                                                                   |
| `returnUrl`      | `string`  | URL powrotu klienta po płatności                                                                                                                        |
| `productName`    | `string`  | Nazwa produktu widoczna na checkoucie                                                                                                                   |
| `customerId`     | `string`  | Dowolna wartość przekazywana na wylot - checkout jej nie wyświetla                                                                                      |
| `email`          | `string`  | Opcjonalnie -  adres e-mail klienta, uzupełniany na checkoucie                                                                                          |
| `locale`         | `string`  | Opcjonalnie -  nadpisuje locale z głównego produktu                                                                                                     |
| `triggerPayment` | `enum`    | Opcjonalnie -  metoda płatności wybrana z góry w checkoucie (Google Pay i Apple Pay startują automatycznie)                                             |
| `qrStepEnabled`  | `boolean` | Opcjonalnie -  kod QR na desktopie, klient kończy płatność na telefonie                                                                                 |
| `autoclose`      | `integer` | Opcjonalnie -  po ilu ms od udanej płatności checkout sam wraca na `returnUrl` (odliczanie w przycisku „Wróć do sklepu", interakcja klienta je anuluje) |

Wszystkie parametry przekazujesz płasko, jednym poziomem -  SDK samo składa z nich obiekt `details` wysyłany do API. Dowolne dodatkowe pola trafią tam razem z pozostałymi.

<Warning>
  `amount` musi być liczbą całkowitą. SDK sprawdza tylko, czy wartość jest liczbą większą od zera, więc `49.99` przejdzie walidację, a API **po cichu obetnie ją do 49 groszy**. Przeliczaj złotówki przez `Math.round(kwota * 100)`.
</Warning>

### Automatyczne uruchomienie metody płatności

Pole `triggerPayment` z góry wybiera metodę płatności w checkoucie, dzięki czemu klient nie musi jej szukać na liście.

| Wartość       | Metoda             |
| ------------- | ------------------ |
| `GPAY`        | Google Pay         |
| `APAY`        | Apple Pay          |
| `BLIK`        | BLIK               |
| `CARD`        | Płatność kartą     |
| `TRANSFER`    | Przelew tradycyjny |
| `PAY_BY_LINK` | Pay by Link        |
| `PAYPO`       | PayPo              |

Inna wartość kończy się błędem `PaymoveValidationError` (pole `triggerPayment`). Pominięcie pola lub `null` oznacza standardowy checkout z wyborem metody.

<Warning>
  Automatyczny start - czyli otwarcie płatności tak, jakby klient kliknął **Zapłać** - dotyczy **wyłącznie Google Pay i Apple Pay**. Przy pozostałych pięciu metodach kafelek jest tylko zaznaczony.
</Warning>

<Info>
  Nawet dla portfeli auto-start zadziała tylko wtedy, gdy checkout zna adres e-mail klienta -  przekaż go w `email`. Nie zadziała też w [widgecie osadzonym w modalu](/sdk/widget) ani gdy metoda nie jest dostępna dla Twojego produktu.
</Info>

Auto-start działa wyłącznie przy pierwszym wyświetleniu checkoutu. Gdy klient sam wybierze metodę płatności, nie uruchomi się ponownie -  aż do odświeżenia strony.

<Warning>
  Google Pay i Apple Pay otwierają natywne okno przeglądarki, które zwykle wymaga gestu klienta -  automatyczne uruchomienie może zostać przez nią zablokowane. Klient zobaczy wtedy standardowy ekran płatności i opłaci zamówienie ręcznie.
</Warning>

### Krok z kodem QR

Pole `qrStepEnabled` włącza dodatkowy ekran startowy checkoutu na desktopie: zamiast formularza płatności klient widzi kod QR, skanuje go telefonem i kończy płatność na nim. Przydaje się przy BLIK-u i portfelach dostępnych wyłącznie na telefonie.

Krok jest opcjonalny -  pominięcie pola albo `false` oznacza, że checkout od razu pokazuje formularz płatności.

<Info>
  Kod QR pojawia się wyłącznie na desktopie. Na telefonie oraz przy ustawionym `triggerPayment` checkout pomija ten krok niezależnie od wartości pola.
</Info>

<Info>
  `qrStepEnabled` trafiło do typów SDK po wydaniu `0.2.0`. W starszej wersji pole nadal działa (SDK przekazuje nieznane klucze dalej), ale TypeScript go nie podpowie -  wystarczy zaktualizować pakiet do najnowszej wersji.
</Info>

### Automatyczny powrót do sklepu

Po udanej płatności checkout pokazuje ekran potwierdzenia z przyciskiem „Wróć do sklepu". Pole `autoclose` (w milisekundach) sprawia, że ten powrót wykona się sam: pozostałe sekundy widać w przycisku (`Wróć do sklepu (10s)`), a po ich upływie klient trafia na `returnUrl`. W widgecie zamiast przekierowania zamyka się modal i wywoływany jest `onComplete`.

Dowolna interakcja klienta -  kliknięcie, dotknięcie, klawisz -  anuluje odliczanie na stałe, więc nikt nie zostanie wyrzucony w połowie akcji, na przykład przy pobieraniu potwierdzenia PDF. Pominięcie pola oznacza, że potwierdzenie zostaje na ekranie do czasu, aż klient sam z niego wyjdzie.

<Info>
  `autoclose` trafiło do typów SDK w wydaniu `0.3.0`. W starszej wersji pole nadal działa (SDK przekazuje nieznane klucze dalej), ale TypeScript go nie podpowie.
</Info>

### Odpowiedź

| Pole          | Typ      | Opis                                                                              |
| ------------- | -------- | --------------------------------------------------------------------------------- |
| `redirectUrl` | `string` | Adres checkoutu -  przekieruj klienta pod ten URL w celu sfinalizowania płatności |

## 3. Przekierowanie klienta

```javascript theme={"theme":{"light":"one-light","dark":"one-dark-pro"}}
window.location.href = response.redirectUrl;
```

Po zakończonej płatności checkout pokazuje ekran potwierdzenia z przyciskiem „Wróć do sklepu", który przenosi klienta pod adres podany w `returnUrl`. Cały proces płatności jest bezobsługowy -  Paymove zarządza checkoutem i przetwarzaniem, a Ty realizujesz zamówienie po zweryfikowanym [webhooku](/webhook-signature), nie po powrocie klienta.

<Info>
  Zamiast przekierowania możesz otworzyć ten sam adres w modalu na stronie sklepu — opisuje to [Widget przeglądarkowy](/sdk/widget), który dokłada też gotowy przycisk i pasek z metodami płatności.
</Info>
