> ## 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

# Utwórz produkt (sklep)

> Tworzy produkt reprezentujący Twój sklep w systemie Paymove.
Wszystkie płatności są tworzone w ramach tego produktu. Produkt tworzysz jednorazowo, przy starcie integracji.
Pole `id` z odpowiedzi to `productId` używany w pozostałych wywołaniach.




## OpenAPI

````yaml /openapi.yaml post /api/product/pay
openapi: 3.1.0
info:
  title: Paymove Payment Gateway API
  version: 1.0.0
  description: >
    API bramki płatniczej Paymove umożliwia merchantom tworzenie płatności
    online

    oraz zarządzanie webhookami i produktami.


    ## Zanim zaczniesz — sześć rzeczy, które trzeba wiedzieć


    1. **Kwoty to liczby całkowite w groszach.** `1000` = 10,00 PLN. Wartość z
    częścią
       dziesiętną (np. `12.99`) zostanie po cichu obcięta do `12` groszy, a API zwróci `200`.
       Przeliczaj przez `Math.round(kwota * 100)`.
    2. **Bramka rozlicza wyłącznie w PLN.** W żądaniu nie ma pola waluty.

    3. **Autoryzacja nagłówkiem `X-API-KEY`**, nigdy `Authorization: Bearer`.
    Wywołuj API
       wyłącznie po stronie serwera — żądanie z przeglądarki zostanie odrzucone.
    4. **Nieznane pola w body są po cichu ignorowane**, a API zwraca `200`. Zły
    kształt
       żądania wygląda więc jak sukces — trzymaj się dokładnie udokumentowanej struktury.
    5. **Brak `externalId` kończy się kodem `500`**, a nie `400`. Brak `price`
    albo
       `details.returnUrl` nie zgłasza natomiast żadnego błędu — dostajesz `200`.
    6. **Błędy mają kształt `{"status": <int>, "message": "<tekst>"}`.**
    Rozgałęziaj logikę
       po statusie HTTP — treść `message` bywa niestabilna i nie należy jej parsować.

    Nie istnieją: limity zapytań, kod `429`, kod `422`, nagłówek
    `Idempotency-Key`

    ani wersjonowanie API.
  contact:
    name: Paymove Integration Team
    email: integration@paymove.io
    url: https://paymove.io
servers:
  - url: https://gateway-api.sandbox.paymove.io
    description: Środowisko Sandbox (testowe)
  - url: https://api.paymove.io
    description: Środowisko produkcyjne
security:
  - ApiKeyAuth: []
tags:
  - name: Płatności
    description: Tworzenie płatności
  - name: Produkty
    description: Zarządzanie produktami (merchantami)
  - name: Webhooki
    description: Rejestracja i przypisywanie webhooków
paths:
  /api/product/pay:
    post:
      tags:
        - Produkty
      summary: Utwórz produkt (sklep)
      description: >
        Tworzy produkt reprezentujący Twój sklep w systemie Paymove.

        Wszystkie płatności są tworzone w ramach tego produktu. Produkt tworzysz
        jednorazowo, przy starcie integracji.

        Pole `id` z odpowiedzi to `productId` używany w pozostałych wywołaniach.
      operationId: createProduct
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateProductRequest'
            example:
              partnerId: 78562c79-2f5c-4415-8af4-c871eea92ef2
              productType: PAY
              name: Sklep Testowy
              shortName: SHOP1
              location: Warszawa
              timezone: Europe/Warsaw
              productMetadata:
                locale: pl-PL
      responses:
        '200':
          description: Produkt utworzony — zwraca pełny obiekt produktu
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Product'
              example:
                id: 891412c8-8717-4449-9543-e34112bec470
                name: Sklep Testowy
                location: Warszawa
                partner:
                  id: 78562c79-2f5c-4415-8af4-c871eea92ef2
                  name: Nazwa Partnera Sp. z o.o.
                  productTypes:
                    - PAY
                timezone: Europe/Warsaw
                shortName: SHOP1
                emailEnabled: true
                smsEnabled: false
                fee:
                  id: 01f9754e-78e3-4b2c-8186-d6862598a95a
                  minimum: 30
                  amount: 5
                  fixed: false
                productType: PAY
                status: ACTIVE
                creator: PAYMOVE
                reviewEnabled: false
                createdAt: 1783246791.7453525
                updatedAt: 1783246791.7453525
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '500':
          $ref: '#/components/responses/ServerError'
      x-codeSamples:
        - lang: Shell
          label: curl
          source: |
            curl --request POST \
              --url https://gateway-api.sandbox.paymove.io/api/product/pay \
              --header 'Content-Type: application/json' \
              --header 'X-API-KEY: sk_test_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' \
              --data '{
                "partnerId": "78562c79-2f5c-4415-8af4-c871eea92ef2",
                "productType": "PAY",
                "name": "Sklep Testowy",
                "shortName": "SHOP1",
                "location": "Warszawa",
                "timezone": "Europe/Warsaw",
                "productMetadata": { "locale": "pl-PL" }
              }'
components:
  schemas:
    CreateProductRequest:
      type: object
      required:
        - partnerId
        - productType
        - name
        - location
        - timezone
      properties:
        partnerId:
          type: string
          format: uuid
          description: Identyfikator partnera (nadawany przez Paymove)
        productType:
          type: string
          enum:
            - PAY
          description: Typ produktu — dla bramki płatniczej `PAY`
        name:
          type: string
          description: Nazwa produktu (sklepu)
        shortName:
          type: string
          description: Opcjonalnie — krótka nazwa wyświetlana
        location:
          type: string
          description: Lokalizacja (np. miasto)
        timezone:
          type: string
          description: Strefa czasowa IANA
          example: Europe/Warsaw
        productMetadata:
          type: object
          properties:
            locale:
              type: string
              example: pl-PL
    Product:
      type: object
      description: Pełny obiekt produktu zwracany przez API
      properties:
        id:
          type: string
          format: uuid
          description: >-
            Identyfikator produktu (`productId`) używany w pozostałych
            wywołaniach
        name:
          type: string
        location:
          type: string
        partner:
          type: object
          properties:
            id:
              type: string
              format: uuid
            name:
              type: string
            productTypes:
              type: array
              items:
                type: string
        timezone:
          type: string
        shortName:
          type: string
        emailEnabled:
          type: boolean
        smsEnabled:
          type: boolean
        fee:
          type: object
          description: Prowizja skonfigurowana dla produktu
          properties:
            id:
              type: string
              format: uuid
            minimum:
              type: integer
            amount:
              type: integer
            fixed:
              type: boolean
        productType:
          type: string
        status:
          type: string
          example: ACTIVE
        creator:
          type: string
          example: PAYMOVE
        reviewEnabled:
          type: boolean
        createdAt:
          type: number
          description: Znacznik czasu (epoch, sekundy)
        updatedAt:
          type: number
          description: Znacznik czasu (epoch, sekundy)
    ApiErrorResponse:
      type: object
      description: >-
        Jednolity kształt odpowiedzi błędu. Rozgałęziaj logikę po statusie HTTP
        — treść pola message bywa niestabilna i może zawierać wewnętrzne nazwy
        klas.
      properties:
        status:
          type: integer
          description: Kod statusu HTTP, powielony w treści odpowiedzi
          example: 401
        message:
          type: string
          description: Opis błędu przeznaczony dla człowieka — nie parsuj go w kodzie
          example: Invalid API key
  responses:
    BadRequest:
      description: >-
        Żądanie odrzucone. Najczęstsza przyczyna to niepoprawny JSON lub
        nieprawidłowa wartość pola typu wyliczeniowego.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ApiErrorResponse'
          example:
            status: 400
            message: Malformed JSON request. Please check your request body.
    Unauthorized:
      description: Brak klucza API lub klucz nieprawidłowy, wygasły albo odwołany.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ApiErrorResponse'
          examples:
            missingCredentials:
              summary: Brak nagłówka X-API-KEY
              value:
                status: 401
                message: Missing credentials
            invalidApiKey:
              summary: Klucz nieprawidłowy
              value:
                status: 401
                message: Invalid API key
    ServerError:
      description: >-
        Błąd po stronie Paymove. Uwaga: ten kod zwracany jest także wtedy, gdy w
        żądaniu zabrakło `externalId` albo gdy identyfikator w ścieżce nie jest
        poprawnym UUID — zanim ponowisz wywołanie, sprawdź kompletność body i
        poprawność ścieżki.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ApiErrorResponse'
          example:
            status: 500
            message: Something went wrong
  securitySchemes:
    ApiKeyAuth:
      type: apiKey
      in: header
      name: X-API-KEY
      description: >
        Klucz API generowany w [Panelu Paymove](https://panel.paymove.io).


        Format: 51 znaków z prefiksem środowiska — `sk_test_` w sandboxie,

        `sk_live_` na produkcji.

        Przykład: `sk_test_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx`


        Klucz przekazuj wyłącznie z serwera. Żądanie wysłane ze strony sklepu
        zostanie

        odrzucone — a klucz i tak nigdy nie może trafić do kodu frontendowego.

````