Skip to main content
You can request a refund yourself with a single HTTP call. A GET on the same path returns the refunds of that payment, so you check a refund’s state exactly where you requested it.
API refunds are not available to every partner. The feature is enabled individually, after you let Paymove know in advance - do not assume your account has it until you have confirmed that. Write to integration@paymove.io to have it switched on; until it is active, every call returns 403.
Call the API server-side only. A refund moves money - the API key must never reach frontend code.

1. Endpoints

One path, two methods: POST creates a refund, GET lists the refunds of that payment.

Headers

POST needs a key with write access, GET with read access. A key without it returns 401; generate the right one in the panel.
The pay segment in the path selects the payment gateway. Other paymove products have their own segments (go, parking, multi) - refund under the segment of the product the payment belongs to.

Where to get orderId

{orderId} is the internal order id assigned by Paymove, for example PAY1784798914400. You get it in two places:
orderId is not your externalId, and not the 10-character payment hash from redirectUrl. Neither of those works in this path. Store orderId when you handle the webhook - otherwise every refund needs a status query first.

2. Creating a refund

The same in Node.js:
The shortest valid request is an empty body {} - it refunds the full payment amount.

Body parameters

The request carries no productId. Paymove reads the product - and with it the settlement details - from the payment itself. A productId you send is silently ignored, like every unknown field.
Mind the field name: the amount is amountMinor here, while creating a payment calls it price. The unit is the same in both places - grosz as an integer.

Response

POST returns one refund, GET an array of exactly the same type - one parser serves both calls.
orderId in the response identifies the refund, not the payment. The payment’s id is in parentOrderId. Storing the refund’s orderId as the payment id is the easiest mistake to make on this page.

3. Refund statuses

status takes the same values as a payment status:
A 200 does not mean the money is back with the customer. It means Paymove accepted the refund for processing - the typical response is status: "PENDING". Poll GET …/refund for the terminal state; refunds usually settle within a minute.
A successful refund sets the status of the whole payment to REFUNDED.

4. Listing a payment’s refunds

A payment with no refunds returns an empty array []. This is the endpoint to poll for a refund’s state - call it every few seconds until status is terminal.
The list also contains failed attempts. Every refund is recorded before it is submitted for settlement, so an attempt that is rejected outright is not lost - the POST answers 400 and the attempt shows up in the list with status: ERROR.

5. What cannot be refunded

Each of these returns 400:
  • An incomplete payment. Only a COMPLETED payment can be refunded. There is nothing to refund on INITIALIZED, PENDING, CANCELED or ERROR.
  • A payment that already has a refund. An existing refund in PENDING or COMPLETED blocks further attempts - one refund per payment.
  • An amount other than the full one. An amountMinor different from the payment amount is rejected; partial refunds are not supported.
  • Some payments cannot be refunded over the API at all, depending on how they were settled. If you get a 400 on a completed payment with the full amount, write to integration@paymove.io - we will issue the refund for you.
PayPo refunds are supported, but the confirmation arrives asynchronously - the POST response always carries status: "PENDING", never COMPLETED straight away.

6. Limitations

No partial refunds and one refund per payment. amountMinor must equal the full payment amount, and a second refund attempt on the same payment is rejected. Both limits exist because a refund is settled under the payment’s own reference, so a second one would be indistinguishable from the first.
There is no idempotency key. Two identical requests mean two refunds - today the “one refund per payment” check stops the second one, but do not build retry logic on that. Check GET …/refund before you repeat a POST.

7. Status codes

A payment that does not exist and a payment that belongs to another partner both return the same 403. That is intentional - a 404 would confirm which order ids exist in Paymove. Do not infer from a 403 whether a payment exists.
Ownership is part of the lookup, not a check after it: the payment is fetched by orderId and by the partner your key belongs to. There is no way to refund another partner’s payment or to point a refund at their settlement details.
  1. When you handle the webhook, store the payment’s orderId next to your own externalId.
  2. Before refunding, confirm the payment is COMPLETED and that you have not refunded it already - GET …/refund.
  3. Send POST …/refund. Store the refund’s id and orderId from the response.
  4. Poll GET …/refund until the refund’s status is terminal. COMPLETED means settled; ERROR means it was rejected.
  5. Mark the refund as done on your side only after COMPLETED.

What’s next

Payment statuses

Where to get orderId and how to check a payment’s status.

Errors

The error format and the mechanisms this API does not have.

REST API

Creating the payment you later refund.

Support

Contact us when a refund cannot be done over the API.