Skip to main content
The widget is a single sdk.js file that adds two things to your shop:
  • the <paymove-checkout> element — a payment button or an information bar with the Paymove mark and payment-method logos, ready to drop into a cart or a list of payment methods,
  • a checkout modal — the same URL you redirect to today, rendered in an iframe on your own page.
The widget never creates a payment. Payments are created server-side — through the Node.js SDK or the REST API — and the widget receives the resulting redirectUrl.
The API key stays on the server. The widget only ever takes a redirectUrl, never an apiKey — and a browser call to the API would be rejected by CORS anyway.

1. Load the script

The script registers the <paymove-checkout> element and exposes window.Paymove. Everything renders inside a Shadow DOM, so your styles and the widget’s styles never leak into each other. With async the script may arrive after your code — wait for ready():
The /v1/ path is a versioning alias - the very same file is also served at /sdk.js. Prefer /v1/, so that a future /v2/ will not break existing integrations.
The script URL matches the checkout environment. A sdk.js build only embeds its own domain, so the production script cannot open a sandbox checkout and vice versa — load it from the same domain your redirectUrl points to.

2. The <paymove-checkout> element

The shortest version is the tag alone:
It renders a button with the Paymove mark and, underneath, a card with the payment-method logos. Attributes configure it: Text after a · renders in bold, so label="Pay · 149.00 PLN" gives “Pay · 149.00 PLN”. The first three logos are shown; the rest collapse into a +N badge.
The Paymove mark cannot be hidden or recoloured — two versions are available, black and white. Everything else is themeable — see the Appearance section.

3. Readonly mode

mode="readonly" renders the bar alone: the mark, your text and the method logos. It is non-interactive by default — an informational row, the kind you put next to shipping and payment options in a cart.
To make the bar itself start a payment, add interactive and attach a controller (next section). The element then emits a paymove:click event, handles Enter and Space, and exposes the right roles to screen readers.

Single-method tiles

The method attribute turns the bar into a tile for one method: logo, name and description come from the SDK’s built-in catalog — the shop maintains no logos or copy of its own. The examples below are live, rendered by the sdk.js loaded on this page:
The logo always stays. The name and description can be hidden (hide-label, hide-description) or overridden (label, description):
By default the tile has no background, border or padding — it blends into a row of your own methods list, while rows, borders and radio buttons stay on the shop’s side. The CSS variables from the Appearance section (--paymove-bg, --paymove-border-color, --paymove-padding, --paymove-radius) turn it into a standalone card. With interactive the tile is clickable and emits paymove:click — and with the texts hidden the method name stays in aria-label, so screen readers still announce it correctly.

4. Opening the checkout in a modal

The modal is driven by a controller from window.Paymove:
mount() takes over clicks on the element and switches the button into a loading state while the URL is fetched. If you already have the redirectUrl when the page renders, pass it instead of fetchCheckoutUrl:
fetchCheckoutUrl is the better default: the payment is created at the moment of the click, so customers who only browse the cart never leave abandoned payments behind.

createCheckout configuration

The configuration also accepts every button appearance field (label, methods, variant…), so you can describe the element entirely in JavaScript and mount it into an empty <div>.
The externalId handed to onSuccess and onComplete is details.orderId when you passed one while creating the payment, and the 10-character Paymove hash only when you did not. If you match orders on that value, set details.orderId consistently so you always receive the same identifier.

Controller

When you only need to open the modal — with no button of your own — use the shortcut:

5. Redirect instead of a modal

Same configuration, one extra field:
The customer lands on the Paymove checkout and, after paying, sees a confirmation screen with a “back to shop” button that takes them to the returnUrl passed when the payment was created. Modal and redirect differ by this field only, so you can switch between them without touching the rest of the integration.
In modal flow returnUrl is not used at all - the back button closes the modal and fires onComplete. If your integration relies on a returnUrl handler, it will never run inside the modal. The webhook remains the source of truth.

6. How the modal behaves

  • On desktop it is a 398 px panel, centred over a dimmed backdrop. Its height follows the checkout content.
  • At viewport widths up to 640 px it slides up from the bottom like a native sheet: at most 90% of the viewport height, with a drag handle — dragging it down closes the payment.
  • While loading, a static Paymove mark is shown. There is no close button at that point — it appears only if the checkout stays silent for 10 seconds, as an escape hatch.
  • Once loaded, closing is handled by the checkout’s own header. Esc and a click on the backdrop work as well.
  • The page underneath does not scroll, and returns to its previous position after the modal closes.
  • The checkout reports its own height, so the modal does not jump between steps.
  • The modal can close itself after a successful payment, but you configure that when creating the subproduct, through details.autoclose (in milliseconds), not from the SDK. The checkout then counts down inside the “Back to store” button and closes the modal when it runs out, firing onComplete. Any interaction from the customer cancels the countdown.
Some banks in Pay by Link and PayPo refuse to be embedded in an iframe. The checkout opens those in a new window and returns to the modal afterwards — nothing is required on your side, but do not block pop-ups in your own code.

7. Appearance

Colours, radius and typography of the button can be set through the configuration or directly with CSS variables on the element:
The widget inherits your page’s typeface until you set --paymove-font-family.

8. React and Next.js

After the amount changes, checkout.current.update({ label: 'Pay · 199.00 PLN' }) is enough — the element re-renders without remounting.
In React, mount the widget into an empty <div> rather than a JSX <paymove-checkout>. The element keeps its content in Shadow DOM, so React has nothing to manage — and you avoid hydration mismatch warnings.

9. Limits

  • sdk.js only embeds its own checkout domain. A URL from any other origin fails with INVALID_CHECKOUT_URL before anything is shown.
  • Payments are always created by your backend — the widget knows no API key and never calls the Paymove API.
  • Fulfil orders only after a verified webhook. onSuccess is a UI signal, not a confirmation of settlement.
  • The modal requires your page to be allowed to embed the checkout in an iframe — the checkout sends Content-Security-Policy with frame-ancestors https:, so your shop must run over HTTPS (except localhost in development).