> ## 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. Registering a webhook requires both `retries` and `expectedCode` - omitting either returns HTTP 500, and `retries: 0` means no retry at all. 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. If the merchant has no `productId` yet, do not stop at a placeholder: ask for the API key, the `partnerId` and the shop name, propose defaults for `location` and `timezone` (`Europe/Warsaw`), offer the optional fields once, then create the product for them with `POST /api/product/pay` and take `productId` from `id` in the response. Do the same for the webhook: register it, then assign it to the product. Guided procedure: https://docs.paymove.io/skill.md (Steps 1-2).
> 15. 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

# Start

> Przycisk płatności paymove - widget, który jednym skryptem osadza na Twojej stronie proces płatności za Twój produkt. Bez backendu i bez klucza API.

Przycisk płatności to widget, który osadzasz na swojej stronie jednym plikiem `sdk.js`. Na stronie pojawia się pływający przycisk paymove - klient klika go i - bez opuszczania strony - przechodzi w modalu cały proces płatności za Twój produkt: od wyboru, przez płatność, po potwierdzenie.

Widget działa z produktem skonfigurowanym w paymove. Kroki procesu, ceny i metody płatności wynikają z konfiguracji produktu - klient widzi w modalu dokładnie to samo, co na stronie płatności otwartej z linku albo z kodu QR.

<Frame caption="Przycisk widgetu z dymkiem w prawym dolnym rogu strony">
  <img src="https://mintcdn.com/paymove/ztZW1d97Uc2P1tsz/images/app-widget/pl/page.png?fit=max&auto=format&n=ztZW1d97Uc2P1tsz&q=85&s=9bbede78eac0087775f89e7547c28371" alt="Strona z przyciskiem widgetu „Zapłać online” i dymkiem „Szybka płatność” w prawym dolnym rogu" width="2200" height="1280" data-path="images/app-widget/pl/page.png" />
</Frame>

## Szybki start

<Steps>
  <Step title="Przygotuj identyfikator produktu">
    Potrzebujesz `productId` istniejącego produktu - UUID z odpowiedzi na utworzenie produktu (pole `id`) albo z [panelu paymove](https://panel.paymove.io). Zamiast UUID możesz podać publiczny alias produktu (`shortName`).
  </Step>

  <Step title="Wklej skrypt do strony">
    Jeden znacznik w `<head>` albo na końcu `<body>`. Adres skryptu dobierz do produktu z tabeli [Adresy skryptu](#adresy-skryptu):

    ```html theme={"theme":{"light":"one-dark-pro","dark":"one-dark-pro"}}
    <script
      defer
      src="https://pay.sandbox.paymove.io/v1/sdk.js"
      data-product-id="d0a834f9-94a4-4b3a-aa10-27d911e3633f"
      data-button-label="Zapłać online"
      data-locale="pl"
    ></script>
    ```

    Nie potrzebujesz kontenera w `<body>` - widget sam dokłada przycisk w prawym dolnym rogu ekranu.
  </Step>

  <Step title="Przetestuj płatność">
    Kliknij przycisk, przejdź proces w modalu i zapłać BLIK-iem. W sandboksie zadziała dowolny 6-cyfrowy kod zaczynający się od `777`, np. `777123`.
  </Step>

  <Step title="Przełącz na produkcję">
    Zamień adres skryptu na produkcyjny i podaj identyfikator produktu z produkcji. Produkty sandboksowe i produkcyjne to osobne byty - identyfikator z jednego środowiska nie zadziała w drugim.
  </Step>
</Steps>

## Adresy skryptu

Adres skryptu zależy od rodzaju produktu i od środowiska. Ścieżka jest zawsze ta sama: `/v1/sdk.js`.

| Produkt | Sandbox | Produkcja |
| - | - | - |
| Płatności za usługi i dokumenty, darowizny i zbiórki | `https://pay.sandbox.paymove.io/v1/sdk.js` | `https://pay.paymove.io/v1/sdk.js` |
| Bilety na wydarzenia i atrakcje | `https://go.sandbox.paymove.io/v1/sdk.js` | `https://go.paymove.io/v1/sdk.js` |
| Parkingi | `https://park.sandbox.paymove.io/v1/sdk.js` | `https://park.paymove.io/v1/sdk.js` |

* `/v1/` to wersja interfejsu widgetu. Zmiany niezgodne wstecz trafią pod nową ścieżkę, więc istniejąca integracja nie zepsuje się po aktualizacji.
* Ładuj skrypt bezpośrednio z domeny paymove - nie kopiuj go na własny serwer. Skrypt rozpoznaje się po własnym adresie i nie uruchomi się z innej domeny.
* Nie wiesz, którego adresu użyć dla swojego produktu? Napisz na [integration@paymove.io](mailto:integration@paymove.io).

## Co widzi klient

1. **Przycisk** z sygnetem paymove i Twoim tekstem, przypięty do rogu ekranu. Opcjonalnie nad przyciskiem pojawia się **dymek** z tytułem i opisem - po najechaniu kursorem albo przy nawigacji klawiaturą.
2. Po kliknięciu: **modal** z ekranem ładowania, który od razu przechodzi w stronę płatności - bez przeładowania Twojej strony.
3. **Proces płatności** produktu - z tymi samymi krokami, cenami i formularzami co poza widgetem. Przez widget nie zmienisz kwot ani kroków.
4. **Ekran potwierdzenia** - modal zostaje otwarty, żeby klient zobaczył potwierdzenie. Przycisk **„Zakończ"** zamyka modal.

Zamknięcie modala w trakcie procesu kasuje wpisane dane - ponowne otwarcie startuje od pierwszego kroku. Nie anuluje jednak płatności, którą klient już rozpoczął, np. potwierdzając BLIK w aplikacji banku.

## Metody płatności

W modalu dostępne są **BLIK**, **Google Pay** i **Apple Pay** - w zakresie włączonym dla Twojego produktu. Kwoty są zawsze w PLN. Apple Pay wyświetla się tylko w przeglądarkach, które go obsługują (Safari na urządzeniach Apple), a w modalu na Twojej domenie wymaga jednorazowej rejestracji domeny - zobacz [Aktywacja Apple Pay](/app-widget/apple-pay).

<Warning>
  Zdarzenie `paymove:completed` w przeglądarce to sygnał dla interfejsu, a nie potwierdzenie księgowe. Rozliczenia i realizację zamówień opieraj na [webhookach](/products/docpay/rest-api#6-webhooki) albo na danych z [panelu paymove](https://panel.paymove.io).
</Warning>

## Co dalej

<CardGroup cols={2}>
  <Card title="Konfiguracja" icon="sliders-horizontal" href="/app-widget/configuration">
    Wszystkie atrybuty `data-*`: tekst przycisku, dymek, język, położenie, kilka widgetów na stronie.
  </Card>

  <Card title="Sterowanie widgetem" icon="code" href="/app-widget/javascript-api">
    Własne przyciski, otwieranie z kodu i zdarzenie po płatności.
  </Card>

  <Card title="Aktywacja Apple Pay" icon="apple" href="/app-widget/apple-pay">
    `merchantDomain` w produkcie i plik weryfikacyjny Apple na Twojej domenie.
  </Card>
</CardGroup>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.