Search

Are you looking for test card numbers?

Would you like to contact support?

Default icon

Referenced refunds

Enable cross-channel returns with simple reconciliation and better fraud protection.

Customers appreciate the possibility of cross-channel returns, allowing them to return an ecommerce purchase to a physical store, or return their in-store purchase by sending it to your distribution center. With referenced refunds, you can offer cross-channel returns with a minimum of operational burden.

Simpler reconciliation

On our unified payments platform we assign a unique identifier to each transaction. This identifier is known as the PSP reference. When you issue a referenced refund, you specify the PSP reference of the original payment. In this way, you can match each refund against a payment, regardless of the sales channel. You'll have the complete audit trail of a payment including any full or partial refunds.

Better fraud protection

A referenced refund returns the funds to the payment method that was used for the original payment, not to the card the shopper is presenting in the store or as cash. This helps combat various return fraud types like returning stolen merchandise, receipt fraud, and cross-retailer returns.

Also, when using referenced refunds, payments can't be refunded multiple times, or for an amount exceeding 100% of the payment value.

Synchronize your back-end systems

A requirement for cross-channel returns is that you have access to transaction information of all sales channels. For referenced refunds, this transaction information must include the PSP reference.

Ideally you have a central database where you store information from both ecommerce and point-of-sale transactions. If you store the ecommerce and point-of-sale transaction information separately on different systems, these systems must be able read each other's data.

Processing refunds

Refunds are not processed synchronously. When you send an API request for a referenced (or unreferenced) refund, the response confirms we received the request. Then we try to process the refund asynchronously, and will inform you of the result through a REFUND notification 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.

By default, refunds are deducted from the merchant account that processed the original payment. For example, if a sale took place on MerchantAccount_ECOM and the product is returned to MerchantAccount_POS, the funds are taken from the ECOM account.

If you want to process cross-channel returns between multiple merchant accounts, contact our Support Team to enable refunds on the company level. This will allow you to use the /payments/{paymentPspReference}/refunds endpoint to submit returns for any merchant account under your company account.

Refund options

To issue a full or partial referenced refund, you have these options:

  • Terminal API reversal request: Your cash register sends a Terminal API ReversalRequest to the payment terminal. The request includes the PSP reference of the original (in-store or ecommerce) purchase. The terminal generates a receipt, and the funds are returned to the original card or other payment method without the need for the customer to present a card to the payment terminal.

  • Server-to-server refund: You make a POST request to the /payments/{paymentPspReference}/refunds endpoint, where paymentPspReference is the PSP reference of the original (in-store or ecommerce) purchase.

  • Refund from your Customer Area. This is a good option if you don't issue refunds often. We describe this in the Account section of our documentation.

Terminal API reversal request

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.

However, the tenderReference is generated by the payment terminal, and is missing for an ecommerce payment. In that case you include the PSP reference in the format .pspReference, and the currency of the original ecommerce payment.

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. You can also make multiple partial refunds.

To return funds to your customer:

  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 (ideally tender reference and PSP reference) of the original payment that you want to refund. See the allowed formats.
      • TimeStamp: Date and time in UTC format of the original payment. For example, 2000-01-01T00:00:00.000Z
      ReversalReason -white_check_mark- MerchantCancel
      POIID Unique terminal ID of the terminal that processed the original payment.

      Include this when you only know the tender reference part of the TransactionID.

      SaleData.SaleToAcquirerData The currency of the refund, in the format currency=EUR. This must match the currency of the original payment.

      Include this when you only know the PSP reference part of the TransactionID.

      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 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);

    Refunding an offline point-of-sale payment

    The next example shows how to make a full refund when you don't know the PSP reference of the original payment. Use this to refund an offline payment: Because the PSP reference is generated on the Adyen payments platform, it is missing for offline payments.
    The request must include:

    • TransactionID in the format tenderReference
      For example: 7JLX001566393198001
    • POIID: Unique terminal 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.
    Reversal request when the PSP reference is unknown
    {
       "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

    The next example shows how to make a full refund when you know the PSP reference of the original payment, but don't know the tender reference. Use this to refund an ecommerce payment: Because the tender reference is generated by the terminal, it is missing for ecommerce payments.
    The request must include:

    • TransactionID in the format .pspReference
      Don't forget the leading dot (.), for example: .851556019495143C
    • A SaleData.SaleToAcquirerData field with the currency of the original payment.
    Reversal request when the tender reference is unknown
    {
       "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"
          }
       }
    }
    • ReversalRequest: The request body with:

      Parameter Required Description
      OriginalPOITransaction.POITransactionID -white_check_mark- An object with:
      • TransactionID: Transaction identifier (ideally tender reference and PSP reference) of the original payment that you want to refund. See the allowed formats.
      • TimeStamp: Date and time in UTC format of the original payment. For example, 2000-01-01T00:00:00.000Z
      ReversalReason -white_check_mark- MerchantCancel
      POIID Unique terminal ID of the terminal that processed the original payment.

      Include this when you only know the tender reference part of the TransactionID.

      ReversedAmount -white_check_mark- The amount being returned to the shopper in the partial refund.
      SaleData.SaleToAcquirerData -white_check_mark- The currency of the refund, in the format currency=EUR. This must match the currency of 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.
      • TimeStamp: Date and time in UTC format of the partial refund.

      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 SaleToAcquirerData.currency field when you don't know the tender reference.

      tenderReference 7JLX001566393198001

      Use this together with the POIID field when you don't know the PSP reference.

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

    {
          "SaleToPOIRequest":{
             "MessageHeader":{
                "ProtocolVersion":"3.0",
                "MessageClass":"Service",
                "MessageCategory":"Reversal",
                "MessageType":"Request",
                "SaleID":"POSSystemID12345",
                "ServiceID":"207111108",
                "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);

    Partially refunding an offline point-of-sale payment

    The next example shows how to make a partial refund when you don't know the PSP reference of the original payment. Use this to partially refund an offline payment: Because the PSP reference is generated on the Adyen payments platform, it is missing for offline payments.
    The request must include:

    • TransactionID in the format tenderReference
      For example: 7JLX001566393198001
    • POIID: Unique terminal ID of the terminal that processed the original payment. With the POIID, we can find the missing information.
    Partial reversal when the PSP reference is unknown
     {
          "SaleToPOIRequest":{
             "MessageHeader":{
                "ProtocolVersion":"3.0",
                "MessageClass":"Service",
                "MessageCategory":"Reversal",
                "MessageType":"Request",
                "SaleID":"POSSystemID12345",
                "ServiceID":"207111108",
                "POIID":"V400m-324688179"
             },
             "ReversalRequest":{x
                "OriginalPOITransaction":{
                   "POITransactionID":{
                      "TransactionID":"pZtU001251034513719",
                      "TimeStamp":"2019-08-12T15:40:03+00:00"
                   }
                },
                "POIID":"P400Plus-275008565",
                "ReversalReason":"MerchantCancel",
                "ReversedAmount":6.00,
                "SaleData":{
                   "SaleToAcquirerData":"currency=EUR",
                   "SaleTransactionID":{
                      "TimeStamp":"2019-08-15T12:00:00+00:00",
                      "TransactionID":"27911"
                   }
                }
             }
          }
        }
     }

    Partially refunding an ecommerce payment

    The next example shows how to make a partial refund when you know the PSP reference of the original payment, but don't know the tender reference. Use this to refund an ecommerce payment: Because the tender reference is generated by the terminal, it is missing for ecommerce payments.
    The request must include:

    • TransactionID in the format .pspReference
      Don't forget the leading dot (.), for example: .851556019495143C
    • A SaleData.SaleToAcquirerData field with the currency of the original payment.
    Partial reversal when the tender reference is unknown
    {
          "SaleToPOIRequest":{
             "MessageHeader":{
                "ProtocolVersion":"3.0",
                "MessageClass":"Service",
                "MessageCategory":"Reversal",
                "MessageType":"Request",
                "SaleID":"POSSystemID12345",
                "ServiceID":"207111108",
                "POIID":"V400m-324688179"
             },
             "ReversalRequest":{
                "OriginalPOITransaction":{
                   "POITransactionID":{
                      "TransactionID":".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"
                   }
                }
             }
          }
        }
     }
  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
    Response when we received your reversal request
    {
       "SaleToPOIResponse":{
          "ReversalResponse":{
             "POIData":{
                "POITransactionID":{
                   "TimeStamp":"2019-05-23T10:32:32.928Z",
                   "TransactionID":"881566557882697F"
                }
             },
             "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.
    Response for a failed reversal request
    {
       "SaleToPOIResponse":{
          "ReversalResponse":{
             "Response":{
                "Result":"Failure",
                "AdditionalResponse":"tid=24687685&...&message=Original%20pspReference%20required%20for%20this%20operation&posAmountCashbackValue=0&posEntryMode=UNKNOWN&posAuthAmountValue=0",
                "ErrorCondition":"NotAllowed"
             }
          },
          ...
          }
       }
    }
  3. Wait for the REFUND notification webhook to learn the result.
    Refunds are always processed asynchronously. If successful, the refund is issued to the shopper's account.

Server-to-server refund

To return funds to your customer:

  1. Make a POST request to the /payments/{paymentPspReference}/refunds endpoint, where paymentPspReference is the pspReference of the authorisation that you want to refund. In your request, include:
    • merchantAccount: The name of your merchant account that is used to process the payment.
    • amount: The amount that you want to refund.
      • The value must be the same or, in case of a partial refund, less than the captured amount.
      • The currency must match the currency used in authorisation.
    • reference: Your reference for the refund, for example for tagging a partial refund for future reconciliation. The reference parameter is required for GrabPay refunds.
    curl https://checkout-test.adyen.com/checkout/v67/payments/8836183819713023/refunds \
    -H 'X-API-Key: YOUR_API_KEY' \
    -H 'Content-Type: application/json' \
    -d '{
        "merchantAccount": "YOUR_MERCHANT_ACCOUNT",
        "amount": {
            "value": 2500,
            "currency": "EUR"
        },
        "reference": "Refund123"
    }'
  2. When you receive the /payments/{paymentPspReference}/refunds response, note:
    • paymentPspReference: The PSP reference of the authorisation you want to refund.
    • pspReference: Adyen's unique reference associated with this refund request.
    {
        "merchantAccount": "YOUR_MERCHANT_ACCOUNT",
        "paymentPspReference": "8836183819713023",
        "pspReference" : "8412534564722331",
        "reference": "Refund123",
        "status" : "received"
    }
  3. Wait for the REFUND notification webhook to learn the outcome of the refund request.

REFUND notification webhook

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 /payments/{paymentPspReference}/refunds response.
  • 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 REFUNDED_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": "Refund123",
            "originalReference":"8836183819713023",
            "paymentMethod":"visa",
            "pspReference":"8412534564722331",
            "reason":"",
            "success":"true"
         }
      }
   ]
}
{
   "live":"false",
   "notificationItems":[
      {
         "NotificationRequestItem":{
            "amount":{
               "currency":"EUR",
               "value":2500
            },
            "eventCode":"REFUND",
            "eventDate":"2021-11-01T00:19:34+01:00",
            "merchantAccountCode":"YOUR_MERCHANT_ACCOUNT",
            "merchantReference": "Refund123",
            "originalReference":"8836183819713023",
            "paymentMethod":"visa",
            "pspReference":"8412534564722331",
            "reason":"Transaction hasn't been captured, refund not possible",
            "success":"false"
         }
      }
   ]
}

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

Failed refund request

When a refund request fails, you receive success: false in the REFUND webhook. Below are 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.

The successful webhook means that the request has been sent to the card scheme, but it can still be rejected by the card scheme at this point. This may 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, you will receive a webhook containing:

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

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

REFUNDED_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. For example, this may happen if the shopper's bank account is no longer valid. To resolve these scenarios, check with the shopper the status of their bank account.

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

  • eventCode: REFUNDED_REVERSED
  • success: true

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

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

See also