Search

Are you looking for test card numbers?

Would you like to contact support?

Point-of-sale icon

Tax-free shopping with secure card sharing

Learn about tax-free shopping and how to support it.

Tax-Free Shopping (TFS) allows international travelers to claim back the sales tax or Value-Added Tax (VAT) on their purchases from a Tax-Free Shopping provider (TFS provider) such as Global Blue. A TFS provider is an organization that refunds the shopper and takes care of the paperwork with the authorities. We can share the shopper's encrypted card number with the TFS provider so that they can easily refund the shopper on their card. This is referred to as secure card sharing.

Supporting TFS drives sales from international shoppers because of its convenience, and can be a great source of data about international shoppers. To offer TFS to your shoppers, your cash register system needs to support it.

You can offer TFS with secure card sharing if you are located in a country that allows VAT refunds and where our point-of-sale solution is supported: the European Union, Iceland, Norway, Singapore, Switzerland, and the United Kingdom.

TFS is not supported on standalone Adyen terminals.

How it works

The role of Adyen in the tax-free flow is limited to passing on information from the terminal to the cash register, and from the terminal to the TFS provider for secure card sharing.

After you have set up TFS:

  1. You make a card acquisition request to get the issuer country code and the Bank Identification Number (BIN) of the shopper's card.
  2. The cash register system uses the issuer country code and the BIN to determine whether the purchase qualifies for a tax refund.
  3. If the purchase qualifies, you optionally ask the shopper for consent to share their encrypted card number with your TFS provider. This makes it easier for them to refund on the card. If the shopper declines, they can still claim the refund with the TFS provider.
  4. You make a payment:
    • If the shopper gave their consent, you set the taxfree.indicator flag to true in your payment request. This tells us to send a notification to the TFS provider with the shopper's encrypted card number.
    • If the shopper didn't give their consent, you either omit the taxfree.indicator flag from your payment request or set it to false.
  5. After the shopper completes the payment, you give the shopper the tax-free form issued by the cash register, and a receipt.

With the tax-free form and the receipt, the shopper can claim the VAT refund from the TFS provider. As part of this process, the shopper has to take the tax-free form to the customs desk at the airport or border, to get export validation. Customs will place a customs stamp on the form, or use an electronic system for validation. The (electronically) validated form then needs to be sent or handed in to the TFS provider.

Notifications to your TFS provider

To make it easier for your TFS provider to refund the shopper on their card, we can send a Send card number to <TFS provider> notification to your TFS provider. This notification includes:

  • The PSP reference of the transaction.
  • The shopper's encrypted card number.
  • The BIN of the shopper's card.

Whether we send this notification, is determined through your payment request. The shopper can claim the tax refund regardless of whether the TFS provider is notified of the shopper's encrypted card number.
If the notification is sent, you'll see this on the transaction in your Customer Area. The POS tile of the transaction will include:

  • Tax Free Indicator: true
  • Tax Free Identifier: The ID that the TFS provider returned to acknowledge the card details.

Set up tax-free shopping

Before you begin offering TFS to your shoppers:

  1. Contact a TFS provider to set up a tax-free process.
  2. Contact your cash register provider to set up the cash register software for TFS support.
  3. Contact your Adyen account manager or the POS Support Team to configure a Send card number to <TFS provider> notification.

    This notification needs to be set up for testing and when you go live.

  4. Enable receiving the issuer country:
    1. In your Customer Area, go to Account > API URLs.
    2. On the Additional data settings tab, select Issuer country.

Acquire card details

To check whether the shopper is eligible for a tax refund, you do a card acquisition.

  1. Make a CardAcquisitionRequest without specifying an amount.

    {
        "SaleToPOIRequest": {
            "MessageHeader": {
                "ProtocolVersion": "3.0",
                "MessageClass": "Service",
                "MessageCategory": "CardAcquisition",
                "MessageType": "Request",
                "SaleID": "POSSystemID12345",
                "ServiceID": "0207111104",
                "POIID": "MX925-284691408"
            },
            "CardAcquisitionRequest": {
                "SaleData": {
                    "SaleTransactionID": {
                        "TimeStamp": "2019-05-17T14:59:09.000Z",
                        "TransactionID": "933"
                    }
                 },
                "CardAcquisitionTransaction": {}
            }
        }
    }
    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.CARD_ACQUISITION );
    messageHeader.setMessageType( MessageType.REQUEST );
    messageHeader.setSaleID(saleID);
    messageHeader.setServiceID(serviceID);
    messageHeader.setPOIID(POIID);
    saleToPOIRequest.setMessageHeader(messageHeader);
    
    CardAcquisitionRequest cardAcquisitionRequest = new CardAcquisitionRequest();
    SaleData saleData = new SaleData();
    TransactionIdentification saleTransactionID = new TransactionIdentification();
    saleTransactionID.setTimeStamp(DatatypeFactory.newInstance().newXMLGregorianCalendar(new GregorianCalendar()));
    saleTransactionID.setTransactionID(transactionID);
    saleData.setSaleTransactionID(saleTransactionID);
    cardAcquisitionRequest.setSaleData(saleData);
    
    CardAcquisitionTransaction cardAcquisitionTransaction = new CardAcquisitionTransaction();
    cardAcquisitionRequest.setCardAcquisitionTransaction(cardAcquisitionTransaction);
    saleToPOIRequest.setCardAcquisitionRequest(cardAcquisitionRequest);
    terminalAPIRequest.setSaleToPOIRequest(saleToPOIRequest);
  2. When you receive the response, get the following details.

    • POIData.POITransactionID.TimeStamp and POIData.POITransactionID.TransactionID: You need to specify these card acquisition details later on, in your payment request.

    • CardData.CardCountryCode: The issuer country code, for example 528. Also included in the AdditionalResponse.

    • From the AdditionalResponse (you'll receive either a string of key-value pairs or a Base64 string that you need to decode to get a JSON object):
      • cardIssuerCountryId: The issuer country code, for example 528. Also included in CardData.CardCountryCode.
      • cardBin: The BIN of the shopper's card, for example 541333.
    Card acquisition response
    {
        "SaleToPOIResponse": {
            "CardAcquisitionResponse": {
                "POIData": {
                    "POITransactionID": {
                        "{hint:For use in the CardAcquisitionReference of the payment request}TimeStamp": "2019-05-17T14:59:08.000Z{/hint}",
                        "{hint:For use in the CardAcquisitionReference of the payment request}TransactionID": "jM6S001558097948000{/hint}"
                    }
                },
                "SaleData": {
                    "SaleTransactionID": {
                        "TimeStamp": "2019-05-17T14:59:09.000Z",
                        "TransactionID": "933"
                    }
                },
                "PaymentInstrumentData": {
                    "CardData": {
                        "{hint:Issuer country code}CardCountryCode{/hint}": "528",
                        "MaskedPan": "541333*****9999",
                        "PaymentBrand": "mc",
                        "SensitiveCardData": {
                            "ExpiryDate": "0228"
                    },
                    "PaymentInstrumentType": "Card"
                },
                "Response": {
                    "{hint:Contains the BIN and the issuer country code}AdditionalResponse{/hint}": "...cardBin=541333...cardIssuerCountryId=528...",
                    "Result": "Success"
                }
            },
            "MessageHeader": {...}
        }
    }
  3. Pass the issuer country code and the card BIN to your cash register for the eligibility check.

The cash register will either handle the eligibility check locally or through the TFS provider, and inform your store staff of the result.

Optionally, you can ask the shopper whether they agree to sharing their encrypted card number with your TFS provider. This makes it easier for them to refund the shopper on their card. If the shopper declines, they can still claim the refund with the TFS provider.
Depending on your cash register system and TFS provider, you can collect the shopper's agreement on the cash register. Alternatively, you can make an input request to collect the information on the terminal:

  1. Make a Confirmation input request with:

    • OutputContent.OutputText: An array of four Text fields containing:

      1. A title. For example:
        Tax-free shopping
      2. An explanation and a question. This text can be long and is scrollable. For example:
        You are eligible for tax-free shopping. Would you like the tax-free provider to refund you on your card?
      3. A "No" button on the left of the display.
      4. A "Yes" button on the right of the display.
    • InputData.MaxInputTime: (Integer) Time-out in seconds. This is the time that the shopper gets to answer the question.
  2. When you receive the input response, check the InputResult for the shopper's answer:

    • Input.ConfirmedFlag: true indicates the shopper gives their consent.
    • Input.ConfirmedFlag: false indicates the shopper doesn't give their consent.
  3. Pass the shopper's answer to the cash register system.

Make a payment

The final step is to make a payment request with a reference to the card acquisition.
If the shopper agreed to sharing their card details with the TFS provider, you also set taxfree.indicator to true.
If you didn't ask the shopper's consent or if the shopper didn't agree, you omit taxfree.indicator or set it to false.

  • Make a PaymentRequest with:

    Parameter Required Description
    PaymentData.CardAcquisitionReference -white_check_mark- An object containing data from the card acquisition:
    • TimeStamp: The timestamp returned in the POIData.POITransactionID of the card acquisition response.
    • TransactionID: The transaction ID returned in the POIData.POITransactionID of the card acquisition response.
    SaleData.SaleToAcquirerData A flag that tells us whether to send the shopper's encrypted card number to your TFS provider .
    • If the shopper gave their consent: Set taxfree.indicator to true.
    • If the shopper didn't give their consent: Set taxfree.indicator to false or omit this field.

    Pass the SaleToAcquirerData in one of the following formats:

    • Option 1: A JSON object converted to a Base64 encoded string.
      If the shopper gave their consent, this is the JSON object:

      {
          "additionalData": {
              "taxfree.indicator": true
          }
      }

      After encoding, pass this in your request:

      "SaleToAcquirerData": "ewogICAgImFkZGl0aW9uYWxEYXRhIjogewogICAgICAgICJ0YXhmcmVlLmluZGljYXRvciI6IHRydWUKICAgIH0KfQ=="
    • Option 2: A form-encoded key-value pair. If the shopper gave their consent:
      "SaleToAcquirerData": "taxfree.indicator=true"

    The example below shows how you would make a payment request for a shopper who agreed to sharing their encrypted card number with your TFS provider.

    {
         "SaleToPOIRequest": {
           "MessageHeader": {
             "ProtocolVersion": "3.0",
             "MessageClass": "Service",
             "MessageCategory": "Payment",
             "MessageType": "Request",
             "SaleID": "POSSystemID12345",
             "ServiceID": "0207111104",
             "POIID": "MX925-284691408"          
           },
           "PaymentRequest": {
             "SaleData": {
               "SaleToAcquirerData": "taxfree.indicator=true",
               "SaleTransactionID": {
                 "TransactionID": "27908",
                 "TimeStamp": "2019-03-07T10:11:04+00:00"
               }            
             },
             "PaymentTransaction": {
               "AmountsReq": {
                 "Currency": "EUR",
                 "RequestedAmount": 176.99
               }
             },        
             "PaymentData": {
               "CardAcquisitionReference": {
                 "TransactionID": "jM6S001558097948000",
                 "TimeStamp": "2019-05-17T12:59:08.000Z"
               }
             }
           }
         }
       }
    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();
    saleData.setSaleToAcquirerData("TaxFreeIndicator=True");
    TransactionIdentification saleTransactionID = new TransactionIdentification();
    saleTransactionID.setTransactionID(transactionID);
    saleTransactionID.setTimeStamp(DatatypeFactory.newInstance().newXMLGregorianCalendar(new GregorianCalendar()));
    saleData.setSaleTransactionID(saleTransactionID);
    paymentRequest.setSaleData(saleData);
    
    PaymentTransaction paymentTransaction = new PaymentTransaction();
    AmountsReq amountsReq = new AmountsReq();
    amountsReq.setCurrency("EUR");
    amountsReq.setRequestedAmount( BigDecimal.valueOf(176.99) );
    paymentTransaction.setAmountsReq(amountsReq);
    paymentRequest.setPaymentTransaction(paymentTransaction);
    
    PaymentData paymentData = new PaymentData();
    TransactionIdentification cardAcquisitionReference = new TransactionIdentification();
    cardAcquisitionReference.setTransactionID(transactionID);
    cardAcquisitionReference.setTimeStamp(DatatypeFactory.newInstance().newXMLGregorianCalendar(new GregorianCalendar()));
    paymentData.setCardAcquisitionReference(cardAcquisitionReference);
    paymentRequest.setPaymentData(paymentData);
    saleToPOIRequest.setPaymentRequest(paymentRequest);
    terminalAPIRequest.setSaleToPOIRequest(saleToPOIRequest);

    The request is routed to the terminal, for the shopper to complete the transaction.

Testing the tax-free flow

In most cases, your TFS provider will organize an end-to-end test between themselves, Adyen, you, and your cash register provider.

In general, to test the happy flow, you need to use a card with a BIN that's eligible for tax refunds. Otherwise, the TFS provider will return a message that a tax refund is not possible.

  1. Make sure we configured Send card number to <TFS provider> notifications for your test account.
  2. Discuss with your TFS provider which card numbers (PAN) on your test card are allowed to use for tax refund testing. (The PAN includes the BIN.)
  3. During the card acquisition step, use one of the allowed test card PANs and the associated currency.
    Depending on how the eligibility check is set up with your TFS provider and cash register, the cash register should now indicate in some way that the card is eligible for a tax refund.
  4. Send a payment request with taxfree.indicator set to true, and complete the payment on the terminal. Note the PSP reference of the transaction.
  5. Issue a tax-free form from the cash register.
  6. In your Customer Area, look up the transaction by PSP reference and check that the POS tile contains an ID in the Tax Free Identifier field. If this field is empty, contact your TFS provider to discover what went wrong.

See also