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

# Wymień sekret podpisujący webhooka

> Generuje nowy `signingSecret` dla webhooka.

Poprzedni sekret przestaje działać **natychmiast** — nie ma okresu przejściowego,
w którym oba byłyby akceptowane. Zaktualizuj konfigurację po swojej stronie w tym
samym momencie, w przeciwnym razie weryfikacja podpisu zacznie odrzucać powiadomienia.




## OpenAPI

````yaml /openapi.yaml post /api/pay/plugin/webhook/{webhookId}/rotate-secret
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/pay/plugin/webhook/{webhookId}/rotate-secret:
    post:
      tags:
        - Webhooki
      summary: Wymień sekret podpisujący webhooka
      description: >
        Generuje nowy `signingSecret` dla webhooka.


        Poprzedni sekret przestaje działać **natychmiast** — nie ma okresu
        przejściowego,

        w którym oba byłyby akceptowane. Zaktualizuj konfigurację po swojej
        stronie w tym

        samym momencie, w przeciwnym razie weryfikacja podpisu zacznie odrzucać
        powiadomienia.
      operationId: rotateWebhookSecret
      parameters:
        - name: webhookId
          in: path
          required: true
          description: Identyfikator webhooka
          schema:
            type: string
            format: uuid
            example: 6b23ecd9-14c8-47fc-add0-b71ec50e9d66
      responses:
        '200':
          description: Nowy sekret wygenerowany
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Webhook'
              example:
                id: 6b23ecd9-14c8-47fc-add0-b71ec50e9d66
                name: OrderPaymentHook
                signingSecret: whsec_yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/ServerError'
      x-codeSamples:
        - lang: Shell
          label: curl
          source: |
            curl --request POST \
              --url https://gateway-api.sandbox.paymove.io/api/pay/plugin/webhook/6b23ecd9-14c8-47fc-add0-b71ec50e9d66/rotate-secret \
              --header 'X-API-KEY: sk_test_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
components:
  schemas:
    Webhook:
      type: object
      description: Obiekt webhooka zwracany przez API
      properties:
        id:
          type: string
          format: uuid
          description: Identyfikator webhooka (`webhookId`)
        name:
          type: string
        endpoint:
          type: string
          format: uri
        method:
          type: string
        requestTemplate:
          type: object
        responseTemplate:
          type: object
        expectedCode:
          type: integer
        expectedResponse:
          type: string
        retries:
          type: integer
        type:
          type: string
        headers:
          type: object
          additionalProperties:
            type: array
            items:
              type: string
        signingSecret:
          type: string
          description: >-
            Sekret do weryfikacji podpisu żądań przychodzących od Paymove —
            przechowuj bezpiecznie
    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:
    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
    NotFound:
      description: >-
        Zasób o podanym identyfikatorze nie istnieje. Treść message zawiera
        wewnętrzną nazwę encji — nie opieraj na niej logiki.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ApiErrorResponse'
          example:
            status: 404
            message: PayProductEntity not found
    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.

````