Are you looking for test card numbers?

Would you like to contact support?

Point-of-sale icon

Refund a payment

Learn how to issue a point-of-sale refund.

Not refunding point-of-sale payments often?

If you want to return funds to a shopper after a payment has been Approved, you need to refund the payment.

We offer two types of refund:

  • Referenced refund: A ReversalRequest. Referenced refunds are connected to the original payment, using a unique identifier of that payment.
  • Unreferenced refund: A PaymentRequest with PaymentType Refund. Unreferenced refunds need to be manually reconciled, and let you return any amount to any card presented in-store. You can use this for example to issue a refund to someone who did not make the original payment, such as a gift recipient.

You can implement one or both types of refund.

Referenced refunds offer the following advantages over unreferenced refunds:

  • Simpler reconciliation: A refund can be matched against a payment, using the pspReference.
  • Lower risk of return fraud: A payment can't be refunded multiple times, or for an amount exceeding 100% of the payment value.
  • Support for refunds to QR code payment methods, such as Alipay and WeChat Pay.
  • Cross-channel refunds: Refunds can be issued in-store, from your call center, or your fulfillment center.
  • Refunding BankAxept payments requires an additional contract with the BankAxept scheme and is only possible in stores where the shopper has made a purchase.

  • The following card schemes only support unreferenced refunds.
    • Dankort
    • Interac

Processing refunds

Refunds are not processed synchronously. When you send a request for a referenced or unreferenced refund, the Terminal API response confirms we received the request. For a full referenced refund, the payment amount is not present in the Terminal API response if the terminal on which you make the refund request is not the one used to make the initial payment.

We process the refund asynchronously, and will inform you of the result through a REFUND webhook.

When a refund has been processed, it is deducted from your in-process funds, and will appear in your shopper's account within a few days.

Referenced refunds

When you make an in-store payment, the Terminal API response returns the transaction identifier of the payment in the format tenderReference.pspReference. To make a referenced refund, you specify this transaction identifier in your refund request. This lets us validate the refund against the original payment, to ensure that it hasn't already been refunded.

You can make a:

  • Full refund to return the total value of the purchase to the shopper.
  • Partial refund to return part of the purchase to the shopper. For example, when a shopper returns one of the items they purchased. You can also make multiple partial refunds. For example, when a shopper returns several items at different times.

Make a referenced refund

Select a tab to see the parameters that you need to specify for a full referenced refund, or a partial referenced refund.

  1. Make a POST request to a Terminal API endpoint, to initiate a referenced refund for the full amount.

    • ReversalRequest: The request body with:
      Parameter Required Description
      OriginalPOITransaction.POITransactionID -white_check_mark- An object with:
      • TransactionID: Transaction identifier of the original payment: the tender reference and/or the PSP reference. See the allowed formats.
      • TimeStamp: Date and time in UTC format of the original payment. For example, 2000-01-01T00:00:00.000Z
      OriginalPOITransaction.POIID Unique ID of the terminal that processed the original payment. Include this when you know the tender reference but not the PSP reference of the original payment.
      ReversalReason -white_check_mark- MerchantCancel
      SaleData.SaleToAcquirerData The currency of the refund, in the format currency=ABC where ABC is the three-letter currency code. This must match the currency of the original payment. Include this when you know the PSP reference but not the tender reference of the original payment.
      To specify the original TransactionID, use one of the following formats:
      Format Example
      tenderReference.pspReference 7JLX001566393198001.851556019495143C Recommended format
      .pspReference .851556019495143C Don't forget the leading dot (.). Use this together with the SaleData.SaleToAcquirerData.currency field when you don't know the tender reference.
      tenderReference 7JLX001566393198001 Use this together with the OriginalPOITransaction.POIID field when you don't know the PSP reference.

    The next example shows how to make a full refund, with the TransactionID in the recommended format.

    {
        "SaleToPOIRequest":{
            "MessageHeader":{
                "ProtocolVersion":"3.0",
                "MessageClass":"Service",
                "MessageCategory":"Reversal",
                "MessageType":"Request",
                "SaleID":"POSSystemID12345",
                "ServiceID":"0207111107",
                "POIID":"V400m-324688179"
            },
            "ReversalRequest":{
                "OriginalPOITransaction":{
                    "POITransactionID":{
                        "TransactionID":"7JLX001566393198001.851556019495143C",
                        "TimeStamp":"2019-03-07T10:11:04+00:00"
                    }
                },
                "ReversalReason":"MerchantCancel"
            }
        }
    }
    String saleID = "YOUR_CASH_REGISTER_ID";
    String serviceID = "YOUR_UNIQUE_ATTEMPT_ID";
    String POIID = "YOUR_TERMINAL_ID";
    String transactionID = "YOUR_UNIQUE_TRANSACTION_ID";
    
    SaleToPOIRequest saleToPOIRequest = new SaleToPOIRequest();
    MessageHeader messageHeader = new MessageHeader();
    messageHeader.setProtocolVersion("3.0");
    messageHeader.setMessageClass( MessageClassType.SERVICE );
    messageHeader.setMessageCategory( MessageCategoryType.REVERSAL );
    messageHeader.setMessageType( MessageType.REQUEST );
    messageHeader.setSaleID(saleID);
    messageHeader.setServiceID(serviceID);
    messageHeader.setPOIID(POIID);
    saleToPOIRequest.setMessageHeader(messageHeader);
    
    ReversalRequest reversalRequest = new ReversalRequest();
    OriginalPOITransaction originalPOITransaction = new OriginalPOITransaction();
    TransactionIdentification pOITransactionID = new TransactionIdentification();
    pOITransactionID.setTransactionID(transactionID);
    pOITransactionID.setTimeStamp(DatatypeFactory.newInstance().newXMLGregorianCalendar(new GregorianCalendar()));
    originalPOITransaction.setPOITransactionID(pOITransactionID);
    reversalRequest.setOriginalPOITransaction(originalPOITransaction);
    reversalRequest.setReversalReason( ReversalReasonType.MERCHANT_CANCEL );
    saleToPOIRequest.setReversalRequest(reversalRequest);
    terminalAPIRequest.setSaleToPOIRequest(saleToPOIRequest);
  2. Check whether we received your request for a full or partial refund.
    If we received your request, the ReversalResponse contains:

    • POIData.POITransactionID.TransactionID: The PSP reference for this refund request.
    • Response.Result: Success

    If your request failed, the ReversalResponse contains:

    • Response.Result: Failure
    • AdditionalResponse: Includes a message explaining why the request failed. Use this to fix the request and try again. For example, Original pspReference required for thisoperation.

    Response when we received your reversal request
    {
       "SaleToPOIResponse":{
           "ReversalResponse":{
               "POIData":{
                   "POITransactionID":{
                       "TimeStamp":"2019-05-23T10:32:32.928Z",
                       "TransactionID":"881566557882697F"
                   }
               },
               "Response":{
                   "Result":"Success",
                   ...
               }
           },
           ...
       }
    }
  1. Wait for the REFUND webhook to learn the result. Refunds are always processed asynchronously. If successful, the refund is issued to the shopper's account.

For a complete list of fields you can pass and receive for a referenced refund, see the ReversalRequest API reference and the ReversalResponse API reference.

Refunding an offline point-of-sale payment

An offline point-of-sale payment has a tender reference, which is generated by the terminal. But the PSP reference is missing because that is generated on the Adyen payments platform. To refund an offline point-of-sale payment, the Terminal API reversal request must include:

  • TransactionID: The tender reference of the original payment. For example: 7JLX001566393198001
  • POIID: The unique ID of the terminal that processed the original payment. With the POIID, we can find the missing information. In case of a full refund on the same terminal that processed the original transaction, you can omit the POIID field.
{
   "SaleToPOIRequest":{
      "MessageHeader":{
         "ProtocolVersion":"3.0",
         "MessageClass":"Service",
         "MessageCategory":"Reversal",
         "MessageType":"Request",
         "SaleID":"POSSystemID12345",
         "ServiceID":"207111108",
         "POIID":"V400m-324688179"
      },
      "ReversalRequest":{
         "OriginalPOITransaction":{
            "POITransactionID":{
               "TransactionID":"7JLX001566393198001",
               "TimeStamp":"2019-03-07T10:11:04+00:00"
            },
            "POIID":"P400Plus-275008565"
         },
         "ReversalReason":"MerchantCancel"
      }
   }
}

Refunding an ecommerce payment

An ecommerce payment does have a PSP reference, but the tender reference is missing because that is generated by the terminal. To refund an ecommerce payment, the Terminal API reversal request must include:

  • TransactionID: The PSP reference of the original payment in the format .pspReference.
    Don't forget the leading dot (.). For example: .851556019495143C
  • SaleToAcquirerData: The currency of the refund, in the format currency=ABC where ABC is the three-letter currency code. This must match the currency of the original payment. For example: currency=EUR
{
    "SaleToPOIRequest": {
        "MessageHeader": {
            "ProtocolVersion": "3.0",
            "MessageClass": "Service",
            "MessageCategory": "Reversal",
            "MessageType": "Request",
            "SaleID": "POSSystemID12345",
            "ServiceID": "207111108",
            "POIID": "V400m-324688179"
        },
        "ReversalRequest": {
            "OriginalPOITransaction": {
                "POITransactionID": {
                    "TransactionID": ".851556019495143C",
                    "TimeStamp": "2019-03-07T10:11:04+00:00"
                }
            },
            "SaleData": {
                "SaleToAcquirerData": "currency=EUR"
            },
            "ReversalReason": "MerchantCancel"
        }
    }
}

Unreferenced refunds

If you are using unreferenced refunds, we highly recommend that your cash register system is able to reconcile a refund against an original purchase. This reduces the risk of return fraud (a payment being refunded multiple times), and human error (store staff enter the wrong refund amount).

It's not possible to make an unreferenced refund to a QR code payment method, such as Alipay and WeChat Pay. To refund these payment methods you must make a referenced refund.

Enable unreferenced refunds

Before you can make unreferenced refunds, contact our POS Support Team team and ask them to:

  • Enable unreferenced refunds for your merchant account.
  • Optional Set a refund delay so you have time to cancel an unreferenced refund when necessary.

Make an unreferenced refund

For an unreferenced refund to a gift card, you need to specify more parameters than we describe here. Refer to Make a refund to a gift card.

  1. Make a POST request to a Terminal API endpoint, specifying:

    • PaymentRequest: The request body with:

      Parameter Required Description
      SaleData.SaleTransactionID -white_check_mark- An object with:
      • TransactionID: Your unique reference for the refund. In your Customer Area and Adyen reports, this will show as the merchant reference.

        If the original payment was an offline payment, you can make reconciliation easier by including the tender reference of the offline payment.

      • TimeStamp: Date and time of the refund in UTC format.
      PaymentTransaction.AmountsReq -white_check_mark- An object with:
      • Currency: The transaction currency.
      • RequestedAmount: The amount being refunded to the card.
      PaymentData.PaymentType Refund

    The example below shows how to refund EUR 10.99 to a card.

    {
        "SaleToPOIRequest":{
            "MessageHeader":{
                "ProtocolVersion":"3.0",
                "MessageClass":"Service",
                "MessageCategory":"Payment",
                "MessageType":"Request",
                "SaleID":"POSSystemID12345",
                "ServiceID":"12392",
                "POIID":"V400m-324688179"
            },
            "PaymentRequest":{
                "SaleData":{
                    "SaleTransactionID":{
                        "TimeStamp":"2019-04-23T12:15:01+00:00",
                        "TransactionID":"YOUR_REFUND_REFERENCE"
                    }
                },
                "PaymentTransaction":{
                    "AmountsReq":{
                        "Currency":"EUR",
                        "RequestedAmount":10.99
                    }
                },
                "PaymentData":{
                    "PaymentType":"Refund"
                }
            }
        }
    }
    String saleID = "YOUR_CASH_REGISTER_ID";
    String serviceID = "YOUR_UNIQUE_ATTEMPT_ID";
    String POIID = "YOUR_TERMINAL_ID";
    String transactionID = "YOUR_UNIQUE_TRANSACTION_ID";
    
    SaleToPOIRequest saleToPOIRequest = new SaleToPOIRequest();
    MessageHeader messageHeader = new MessageHeader();
    messageHeader.setProtocolVersion("3.0");
    messageHeader.setMessageClass( MessageClassType.SERVICE );
    messageHeader.setMessageCategory( MessageCategoryType.PAYMENT );
    messageHeader.setMessageType( MessageType.REQUEST );
    messageHeader.setSaleID(saleID);
    messageHeader.setServiceID(serviceID);
    messageHeader.setPOIID(POIID);
    saleToPOIRequest.setMessageHeader(messageHeader);
    
    PaymentRequest paymentRequest = new PaymentRequest();
    SaleData saleData = new SaleData();
    TransactionIdentification saleTransactionID = new TransactionIdentification();
    saleTransactionID.setTimeStamp(DatatypeFactory.newInstance().newXMLGregorianCalendar(new GregorianCalendar()));
    saleTransactionID.setTransactionID(transactionID);
    saleData.setSaleTransactionID(saleTransactionID);
    paymentRequest.setSaleData(saleData);
    
    PaymentTransaction paymentTransaction = new PaymentTransaction();
    AmountsReq amountsReq = new AmountsReq();
    amountsReq.setCurrency("EUR");
    amountsReq.setRequestedAmount( BigDecimal.valueOf(10.99) );
    paymentTransaction.setAmountsReq(amountsReq);
    paymentRequest.setPaymentTransaction(paymentTransaction);
    
    PaymentData paymentData = new PaymentData();
    paymentData.setPaymentType( PaymentType.REFUND );
    paymentRequest.setPaymentData(paymentData);
    saleToPOIRequest.setPaymentRequest(paymentRequest);
    terminalAPIRequest.setSaleToPOIRequest(saleToPOIRequest);

    The refund request is routed to the terminal.

  2. Present the card to the terminal, and follow the instructions on the terminal screen.

  3. Check whether we received your refund request. If we received it:

    • Approved is shown on the terminal.
    • You receive a JSON response with:
    {
        "SaleToPOIResponse": {
            "PaymentResponse": {
                "POIData": {
                    "POITransactionID": {
                        "TimeStamp": "2019-06-03T15:49:36.000Z",
                        "TransactionID": "4rVu001559576976000.881559576981487A"
                    },
                    ...
                },
                ...
                "Response": {
                    "Result": "Success",
                    ...
                }
            },
            ...
        }
    }
  4. Wait for the REFUND webhook to learn the result. Refunds are always processed asynchronously. If successful, the refund is issued to the shopper's account.

For a complete list of fields you can pass and receive for an unreferenced refund, see the PaymentRequest API reference and the PaymentResponse API reference.

REFUND webhooks

To receive notifications about your refunds, you must set up notification webhooks.

You get the outcome of the refund request asynchronously, in a notification webhook that includes:

  • eventCode: REFUND.
  • pspReference: The pspReference from the response for your refund request.
  • success: Indicates whether the refund request was successful. Possible values:
    • true: The refund request was successful. This usually means that the refund was successful. For information on exceptions, refer to REFUND_FAILED webhook, and REFUND_REVERSED webhook.
    • false: The refund request failed. The webhook includes a reason field with a short description of the problem. Review the reason, fix the issue if possible, and resubmit the refund request.
{
   "live":"false",
   "notificationItems":[
      {
         "NotificationRequestItem":{
            "amount":{
               "currency":"EUR",
               "value":2500
            },
            "eventCode":"REFUND",
            "eventDate":"2021-11-01T00:19:34+01:00",
            "merchantAccountCode":"YOUR_MERCHANT_ACCOUNT",
            "merchantReference": "YOUR_UNIQUE_REFERENCE",
            "originalReference":"8836183819713023",
            "paymentMethod":"visa",
            "pspReference":"8412534564722331",
            "reason":"",
            "success":"true"
         }
      }
   ]
}

For more information about the included fields, see the REFUND notification reference.

Failed refund request

When a refund request fails, you receive a REFUND webhook with success: false and the reason why the request failed. The next table shows the most common reason values in the REFUND webhook.

reason Description
Requested refund amount too high No chargeback or refund has been processed, and the requested refund amount is more than the balance on the payment.
Already partially refunded, new requested refund amount too high Partial refund(s) has(/have) been processed, and the requested refund amount is more than the balance on the payment.
Already partially disputed, new requested refund amount too high Partial chargeback(s) has(/have) been processed, and the requested refund amount is more than the balance on the payment.
Already fully refunded, no balance available for new requested refund Full refund has been processed, and the remaining balance on the payment is 0.
Partially refunded and partially disputed, no balance available for new requested refund Partial refund(s) and chargeback(s) have been processed, and the requested refund amount is more than the balance on the payment.
Partial refund(s) and chargeback(s) have been processed, and the balance on the payment is a negative amount.
Already fully disputed, no balance available for new requested refund Full chargeback has been processed, and the balance on the payment is 0.
A full chargeback and partial refund(s) have been processed, and the balance on the payment is a negative amount.
Insufficient in-process funds on account for refunding this payment There is not enough balance on your merchant account to process the refund.
Transaction hasn't been captured, refund not possible The refund was requested before the transaction was captured. You need to cancel the transaction instead or wait until the transaction is settled.
The maximum period for this operation has expired The refund was requested past the expiration date permitted by the payment method to process the request.

Balance on the payment

The balance on the payment refers to the amount that remains from the original payment. For example, if a transaction has a total of 10 EUR and no refund or chargeback is processed, then the balance on the payment is 10 EUR. After a refund or chargeback of 3 EUR is processed, the remaining balance on the payment is 7 EUR.

REFUND_FAILED webhook

Although rare, a refund can fail after you received a REFUND webhook with success: true. A successful REFUND webhook means that the request has been sent to the card scheme, but the refund can still be rejected by the card scheme. This can happen even a few days after you submitted the refund request.

Most of the time Adyen can fix the issue, so that the shopper will eventually receive the funds. Sometimes, however, you need to take action yourself. To learn why a refund can fail and what, if anything, you need to do in each case, refer to Failed refunds.

When a refund fails after you received success: true in the REFUND webhook, we inform you of this with another webhook containing:

  • eventCode: REFUND_FAILED
  • pspReference: The pspReference of the refund request.

For more information about the included fields, see the REFUND_FAILED notification reference.
An overview of failed refunds is available in your Payment accounting report.

REFUND_REVERSED webhook

For some payment methods, for example bank transfers, iDEAL, or Bancontact, the status of the payment can change from Refunded to RefundedReversed. This means that the funds have been returned to Adyen, and are back in your account. This can happen, for example, if the shopper's bank account is no longer valid. Before you retry the refund, contact the shopper about the status of their bank account.

When a refund is reversed, we inform you of this with a webhook containing:

  • eventCode: REFUND_REVERSED
  • success: true

For more information about the included fields, see the REFUND_REVERSED notification reference.
An overview of reversed refunds is available in your Payment accounting report.

Transaction routing and refunds

Adyen-supplied payment terminals support both credit and debit cards. Depending on the transaction routing, a debit card is processed either over a debit network like Maestro, Interac, and Pulse, or over a credit network like MasterCard and Visa. All credit networks are dual-messaging, meaning that you can issue a referenced refund against an existing transaction. Some debit networks however are single-messaging, meaning that a referenced refund is not possible and that the refund must be done by inserting the card into the terminal.

To determine the allowed refund method, keep track of the paymentMethodVariant in the payment response. This field returns the network over which the transaction was routed. Keep in mind that the routing is independent of the funding source of the card. To determine whether the card itself is a credit, debit, or prepaid card, check the fundingSource. Keeping track of the fundingSource along with the paymentMethodVariant allows you to determine both the type of card and the routing so transactions can be refunded appropriately.

See also