Refunds

Return money of a completed payin, in full or in parts. A refund is its own transaction with its own id, merchant_reference and status. When a refund completes, the payin moves to refunded and its refunded_amount grows; later refunds of a refunded payin add to refunded_amount.

method_type of the payin Refund
payin_card Full or partial
payin_apple_pay Full or partial
payin_google_pay Full or partial
payin_blik 501 not_supported_yet

Use the key of the payin shop that holds the payin.

Flow

  1. Generate a merchant_reference for the refund and save it before the call.
  2. Create the refund: POST /v2/payins/{payin_id}/refunds. Save id from the response.
  3. Wait for the webhook refund.completed or refund.failed. Verify the signature and act on data.object — the full refund.
  4. Fallback: if no webhook has come for a minute, you can start polling the status with GET /v2/transactions/{transaction_id} until it is final (R20).

POST /v2/payins/{payin_id}/refunds

Request

Headers: Authorization: Bearer <payin shop key>, Content-Type: application/json.

Field In Type Required Format and limits
payin_id path string yes id of the payin
merchant_reference body string yes 1–100 letters, digits, _, -. Unique per merchant across payins, refunds, payouts and pay sessions. The idempotency key of this call
amount body object no The whole refundable remainder if omitted
amount.value body string yes, in amount Major units, at most two decimals, at least 0.01, up to the refundable remainder: "20.00"
amount.currency body string yes, in amount The payin currency: EUR
description body string no Why you refund, up to 255 characters

The refundable remainder is the payin amount minus its refunds that are not failed, including refunds still in progress.

curl -X POST https://payments-api.mrcr.io/v2/payins/3e9c7b5d-0f4a-4b1e-8d6c-8a5f1b4e7da3/refunds \
  -H "Authorization: Bearer $PAYIN_SHOP_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "merchant_reference": "refund-10001", "amount": { "value": "20.00", "currency": "EUR" } }'

Response 201 Created

The Refund object in data. A repeat with the same merchant_reference and body returns the existing refund in its current status.

Header Meaning
Idempotent-Replayed: true The same merchant_reference and body were sent before. This is the existing refund; nothing was created again
{
  "data": {
    "id": "7c3a1f9b-4d8e-4f5c-8b0a-2e9d5f8c1be7",
    "object": "refund",
    "merchant_reference": "refund-10001",
    "method_type": "refund",
    "payin_id": "3e9c7b5d-0f4a-4b1e-8d6c-8a5f1b4e7da3",
    "status": "created",
    "status_details": null,
    "amount": { "value": "20.00", "currency": "EUR" },
    "created_at": "2026-09-29T11:00:00Z",
    "updated_at": "2026-09-29T11:00:00Z"
  }
}

Errors

No refund is created on any of them.

HTTP code When Retry
400 validation_failed A field is missing or malformed — details[] names it No. Fix the request
401 authentication_failed The key is missing, malformed, revoked, or sent to the wrong host No
403 method_not_enabled A payout shop key No. Use the payin shop key
404 resource_not_found No such payin in this shop No
409 action_not_allowed The payin is not completed, nothing is left to refund, or amount is above the remainder No
409 merchant_reference_conflict The reference was used with a different body No. Resend the original body, or use a new reference for a new refund
501 not_supported_yet A BLIK payin No
429 rate_limited Too many requests Yes, after Retry-After seconds
500 internal_error Failure on our side Yes, the identical request

The Refund object

Returned by the create and by GET /v2/transactions/{transaction_id}, and sent in webhooks as data.object. It has the common fields of every transaction, with these values and fields for a refund:

Field Type Always set Meaning
id string yes UUID
object string yes refund
method_type string yes refund
payin_id string yes The payin the money is returned from
status string yes created, processing, completed, failed — see Statuses
status_details.code string when failed provider_declined or internal_error

Refunds of one payin: GET /v2/transactions?payin_id=… — see Transactions.

Statuses

Status What it means Webhook What you do Next
created Accepted and recorded; the amount is reserved from the remainder — Wait processing, failed
processing At the provider — Wait completed, failed
completed Final. Returned to the payer; the payin is refunded and its refunded_amount grows refund.completed, and payin.refunded for the payin Mark the refund done —
failed Final. Not returned; the amount is back in the remainder refund.failed Refund again with a new merchant_reference —

Webhooks

type When data.object
refund.completed The refund reaches completed The Refund object
refund.failed The refund reaches failed The Refund object, with status_details
payin.refunded The refund completes The payin, with refunded_amount

Headers, signature check and redelivery — Webhooks.

Next: Webhooks