Search

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 PaymentRequest with MessageCategory Reversal. 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 may want to support one type of refund, or both.

For most use cases, we recommend using referenced refunds, because they 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 non-card 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.

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.

  • 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

Referenced refunds

When you make a point of sale payment, we connect the shopper's payment details to the payment. In the response we return 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 allows us to validate the refund against the original payment, to ensure that it hasn't already been refunded.
For a full refund using the same terminal that was used in the original payment, it is sufficient to specify the tenderReference, because all information is available in that terminal. In all other cases the .pspReference is required.

Depending on what the shopper is returning, you can either make a:

  • Full refund: Returns the total value of the purchase to the shopper.
  • Partial refund: Returns part of the purchase to the shopper. For example, when a shopper wishes to return one of the items they purchased.
    You can also make multiple partial refunds. These can be useful when, for example, a shopper is returning several items at different times.

To see what your options are if you want to make a refund when your internet connection is down, refer to Refunding an offline payment.

Make a referenced refund

Full and partial refund requests are very similar, but there are a few additional parameters for a partial refund.

  1. Make a POST request to a Terminal API endpoint, to initiate a referenced refund for the full amount or a partial amount. Select a tab to see the parameters that you need to specify.

    • ReversalRequest: The request body with:

      Parameter Required Description
      OriginalPOITransaction.POITransactionID -white_check_mark- An object with:
      • TransactionID: Transaction identifier of the original payment that you want to refund. See the allowed formats.
      • TimeStamp: Date and time of the original transaction in UTC format.
      ReversalReason -white_check_mark- MerchantCancel

      To specify the original TransactionID, use one of the following formats:

      Format Example
      tenderReference.pspReference 7JLX001566393198001.851556019495143C

      Recommended format

      0000000000000000.pspReference 0000000000000000.851556019495143C

      This has 16 zeroes instead of a tender reference.

      .pspReference .851556019495143C

      This works from terminal software version 1.44. Don't forget the leading dot (.).

      tenderReference 7JLX001566393198001

      Only for a full refund using the same terminal as the original payment.

    This example shows how you would make a full refund.

    {
          "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);
    • ReversalRequest: The request body with:

      Parameter Required Description
      OriginalPOITransaction.POITransactionID -white_check_mark- An object with:
      • TransactionID: Transaction identifier of the original payment that you want to refund. See the allowed formats.
      • TimeStamp: Date and time of the original transaction in UTC format.
      ReversalReason -white_check_mark- MerchantCancel
      ReversedAmount The amount being returned to the shopper in the partial refund.
      SaleData.SaleToAcquirerData The currency of the refund, in the format currency=EUR. This must match the currency used to make the original payment.
      SaleData.SaleTransactionID An object with:
      • TransactionID: Your unique reference for the partial refund. In your Customer Area and Adyen reports, this will show as the merchant reference for the transaction.
      • TimeStamp: Date and time of the partial refund in UTC format.

      To specify the original TransactionID, use one of the following formats:

      Format Example
      tenderReference.pspReference 7JLX001566393198001.851556019495143C

      Recommended

      0000000000000000.pspReference 0000000000000000.851556019495143C

      This has 16 zeroes instead of a tender reference.

      .pspReference .851556019495143C

      This works from terminal software version 1.44. Don't forget the leading dot (.).

      tenderReference 7JLX001566393198001

      Only for a full refund using the same terminal as the original payment.

    This example shows how you would make a partial refund of 6.00 EUR.

    {
          "SaleToPOIRequest":{
             "MessageHeader":{
                "ProtocolVersion":"3.0",
                "MessageClass":"Service",
                "MessageCategory":"Reversal",
                "MessageType":"Request",
                "SaleID":"POSSystemID12345",
                "ServiceID":"0207111108",
                "POIID":"V400m-324688179"
             },
             "ReversalRequest":{
                "OriginalPOITransaction":{
                   "POITransactionID":{
                      "TransactionID":"pZtU001251034513719.881566567357804C",
                      "TimeStamp":"2019-08-12T15:40:03+00:00"
                   }
                },
                "ReversalReason":"MerchantCancel",
                "ReversedAmount":6.00,
                "SaleData":{
                   "SaleToAcquirerData":"currency=EUR",
                   "SaleTransactionID":{
                      "TimeStamp":"2019-08-15T12:00:00+00:00",
                      "TransactionID":"27911"
                   }
                }
             }
          }
        }
    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 );
    reversalRequest.setReversedAmount(6.0);
    
    SaleData saleData = new SaleData();
    saleData.setSaleToAcquirerData("currency=EUR");
    TransactionIdentification saleTransactionID = new TransactionIdentification();
    saleTransactionID.setTimeStamp(DatatypeFactory.newInstance().newXMLGregorianCalendar(new GregorianCalendar()));
    saleTransactionID.setTransactionID(transactionID);
    saleData.setSaleTransactionID(saleTransactionID);
    reversalRequest.setSaleData(saleData);
    saleToPOIRequest.setReversalRequest(reversalRequest);
    terminalAPIRequest.setSaleToPOIRequest(saleToPOIRequest);
  2. When your full or partial refund request is processed, check the result.

    • If successful, the ReversalResponse contains:

      • POIData.POITransactionID.TransactionID: The PSP reference` for this refund request.
      • Response.Result: Success
    Response for a successful refund
    {
       "SaleToPOIResponse":{
          "ReversalResponse":{
             "POIData":{
                "POITransactionID":{
                   "TimeStamp":"2019-05-23T10:32:32.928Z",
                   "TransactionID":"881566557882697F"
                }
             },
             "Response":{
                "Result":"Success",
                ...
             }
          },
          ...
       }
    }
    • If unsuccessful, the ReversalResponse contains:

      • Response.Result: Failure
      • AdditionalResponse: Contains a message explaining why the request failed.
    Response for a failed refund
    {
       "SaleToPOIResponse":{
          "ReversalResponse":{
             "Response":{
                "Result":"Failure",
                "AdditionalResponse":"tid=24687685&...&message=Original%20pspReference%20required%20for%20this%20operation&posAmountCashbackValue=0&posEntryMode=UNKNOWN&posAuthAmountValue=0",
                "ErrorCondition":"NotAllowed"
             }
          },
          ...
          }
       }
    }

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.

We attempt to issue the refund asynchronously, and inform you whether this is successful with a webhook notification. If successful, the refund is issued to the shopper's account.

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 your 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.

Before you begin

Before you can make unreferenced refunds, some configuration is needed.

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 for the transaction.
      • 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 you would refund 10.99 EUR 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.

    If your refund request is successfully received:

    • Approved is displayed on the terminal screen.
    • You receive a JSON response with:
    {
        "SaleToPOIResponse": {
            "PaymentResponse": {
                "POIData": {
                    "POITransactionID": {
                        "TimeStamp": "2019-06-03T15:49:36.000Z",
                        "TransactionID": "4rVu001559576976000.881559576981487A"
                    },
                    ...
                },
                ...
                "Response": {
                    "Result": "Success",
                    ...
                }
            },
            ...
        }
    }

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.

We attempt to issue the refund asynchronously, and inform you whether this is successful with a webhook notification. If successful, the refund is issued to the card presented to the terminal.

Refund notifications

When we receive your refund request, we send you a webhook notification to inform you whether this request was processed. This notification contains:

  • eventCode: REFUND
  • pspReference: Matches the TransactionID of the refund request.
  • success: Indicates whether the refund request was processed:

    • true: We processed your refund request. This usually results in the refund being issued.
    • false: We did not process your refund request. This means you do not have sufficient in-process funds to issue the refund. You should increase your in-process funds, and request the refund again.

In rare cases, after your refund request is processed you can receive a notification indicating that this refund:

An overview of failed and reversed refunds is available in your Payment accounting report.

Refund failed

If there was a technical issue when we attempt to issue a refund, we send you a notification that contains:

  • eventCode: REFUND_FAILED
  • originalReference: The pspReference of the payment you are refunding.
  • pspReference: Our unique identifier for the refund that failed.

When a refund fails we will try to fix the issue, then attempt the refund again.

Refunded reversed

If we try and refund a payment, and the shopper's account is no longer valid (for example, they have closed their account), we send you a notification that contains:

  • eventCode: REFUNDED_REVERSED
  • originalReference: The pspReference of the failed refund request.
  • success: true

This means that the funds have been returned to Adyen, and are back in your merchant account.

Next steps