Przejdź do głównej treści
Zwrot płatności zlecisz samodzielnie, jednym wywołaniem HTTP. Pod tym samym adresem GET zwraca listę zwrotów danej płatności, więc po zleceniu zwrotu sprawdzasz jego stan tam, gdzie go zleciłeś.
Zwroty przez API nie są dostępne dla każdego partnera. To funkcja włączana indywidualnie, po uprzednim zgłoszeniu do Paymove - nie zakładaj, że Twoje konto ją ma, dopóki tego nie potwierdzisz. Napisz na integration@paymove.io, żeby ją włączyć; dopóki nie jest aktywna, każde wywołanie kończy się kodem 403.
Wywołuj API wyłącznie po stronie serwera. Zwrot przenosi pieniądze - klucz API nigdy nie może trafić do kodu frontendowego.

1. Endpointy

Jedna ścieżka, dwie metody: POST tworzy zwrot, GET zwraca listę zwrotów tej płatności.

Nagłówki

POST wymaga klucza z uprawnieniem do zapisu, GET - do odczytu. Klucz bez wymaganego uprawnienia kończy się kodem 401; właściwy wygenerujesz w Panelu.
Segment pay w ścieżce wskazuje bramkę płatniczą. Pozostałe produkty paymove mają własne segmenty (go, parking, multi) - zwrot wykonuj pod segmentem produktu, w ramach którego powstała płatność.

Skąd wziąć orderId

{orderId} to wewnętrzny identyfikator zamówienia nadany przez Paymove, na przykład PAY1784798914400. Masz go w dwóch miejscach:
orderId to nie jest Twój externalId ani 10-znakowy skrót płatności z redirectUrl. Ani jednego, ani drugiego nie da się użyć w tej ścieżce. Zapisz orderId u siebie przy obsłudze webhooka - inaczej przed każdym zwrotem będziesz musiał odpytać o status płatności.

2. Wykonanie zwrotu

To samo w Node.js:
Najkrótsze poprawne żądanie to puste body {} - zwraca całą kwotę płatności.

Parametry body

Żądanie nie zawiera productId. Produkt - a wraz z nim dane rozliczeniowe - Paymove odczytuje z samej płatności. Jeśli wyślesz productId, zostanie po cichu zignorowany, jak każde nieznane pole.
Zwróć uwagę na nazwę pola: tutaj kwota to amountMinor, podczas gdy przy tworzeniu płatności jest to price. Jednostka jest w obu miejscach ta sama - grosze jako liczba całkowita.

Odpowiedź

POST zwraca jeden zwrot, GET tablicę obiektów dokładnie tego samego typu - jeden parser obsłuży oba wywołania.
orderId w odpowiedzi to identyfikator zwrotu, nie płatności. Identyfikator płatności znajdziesz w parentOrderId. Zapisanie orderId zwrotu jako identyfikatora płatności to najłatwiejsza do popełnienia pomyłka na tej stronie.

3. Statusy zwrotu

Pole status przyjmuje te same wartości co status płatności:
Kod 200 nie znaczy, że pieniądze wróciły do klienta. Oznacza, że Paymove przyjął zwrot do realizacji - typową odpowiedzią jest status: "PENDING". Stan końcowy sprawdzaj przez GET …/refund; zwroty rozliczają się zwykle w ciągu kilkudziesięciu sekund.
Udany zwrot ustawia status całej płatności na REFUNDED.

4. Lista zwrotów płatności

Płatność bez zwrotów zwraca pustą tablicę []. To właściwy endpoint do odpytywania o stan zwrotu - polling po kilku sekundach, aż status będzie końcowy.
Lista zawiera także nieudane próby. Każdy zwrot zapisujemy przed skierowaniem go do rozliczenia, więc próba odrzucona od razu nie przepada - POST odpowiada wtedy 400, a na liście widać ją ze statusem ERROR.

5. Czego nie da się zwrócić

Każdy z tych przypadków kończy się kodem 400:
  • Płatność nieukończona. Zwrócić można wyłącznie płatność ze statusem COMPLETED. Płatności INITIALIZED, PENDING, CANCELED i ERROR nie ma po co zwracać.
  • Płatność, która ma już zwrot. Istniejący zwrot w stanie PENDING lub COMPLETED blokuje kolejne próby - jeden zwrot na płatność.
  • Kwota inna niż pełna. amountMinor różne od kwoty płatności jest odrzucane; zwroty częściowe nie są obsługiwane.
  • Części płatności nie da się zwrócić przez API w ogóle - zależy to od sposobu, w jaki zostały rozliczone. Jeśli dostajesz 400 przy ukończonej płatności i pełnej kwocie, napisz na integration@paymove.io - zwrot wykonamy za Ciebie.
Zwroty płatności PayPo są obsługiwane, ale potwierdzenie przychodzi asynchronicznie - odpowiedź POST ma zawsze status: "PENDING", nigdy od razu COMPLETED.

6. Ograniczenia

Brak zwrotów częściowych i jeden zwrot na płatność. amountMinor musi być równe pełnej kwocie płatności, a druga próba zwrotu tej samej płatności jest odrzucana. Oba ograniczenia wynikają z tego, że zwrot rozlicza się pod referencją samej płatności - drugi byłby nie do odróżnienia od pierwszego.
Nie ma klucza idempotencji. Dwa identyczne żądania to dwa zwroty - dziś drugi z nich zatrzyma kontrola „jeden zwrot na płatność”, ale nie buduj na tym logiki ponawiania. Zanim ponowisz POST, sprawdź GET …/refund.

7. Kody statusów

Płatność, która nie istnieje, i płatność należąca do innego partnera zwracają ten sam kod 403. Jest to zamierzone - 404 potwierdzałoby, które identyfikatory zamówień istnieją w Paymove. Nie wnioskuj z 403 o tym, czy płatność istnieje.
Własność płatności jest częścią wyszukiwania, a nie kontrolą po nim: płatność szukamy po orderId i po partnerze, do którego należy Twój klucz. Nie da się więc zwrócić płatności innego partnera ani skierować zwrotu na jego dane rozliczeniowe.

8. Zalecany przepływ

  1. Przy obsłudze webhooka zapisz u siebie orderId płatności obok swojego externalId.
  2. Przed zwrotem upewnij się, że płatność ma status COMPLETED i że nie zwróciłeś jej już wcześniej - GET …/refund.
  3. Wyślij POST …/refund. Zapisz id i orderId zwrotu z odpowiedzi.
  4. Odpytuj GET …/refund, aż status zwrotu będzie końcowy. COMPLETED oznacza zwrot rozliczony; ERROR - odrzucony.
  5. Dopiero po COMPLETED oznacz zwrot jako zrealizowany u siebie.

Co dalej

Statusy płatności

Skąd wziąć orderId i jak sprawdzić status płatności.

Kody błędów

Format błędów i mechanizmy, których API nie posiada.

REST API

Tworzenie płatności, którą potem zwracasz.

Wsparcie

Kontakt, gdy zwrotu nie da się wykonać przez API.