Search

Are you looking for test card numbers?

Would you like to contact support?

Point-of-sale icon

Card acquisition

Retrieve card and shopper details before making a payment.

Card acquisition allows you to retrieve card and shopper details before creating a payment request. There are various situations when doing so can be beneficial, for example:

  • Recognizing the card or shopper based on the card alias or shopper reference you receive in the response. You can then personalize the shopping experience, or gain insights through data analysis. See Shopper recognition for more information.
  • Performing an eligibility check for tax-free shopping.

How it works

Before triggering a payment:

  1. You make a card acquisition request (see Step 1). You can include the payable amount in this request.
  2. The payment terminal prompts the shopper to present their card.

    For a contact chip transaction, the shopper should not remove the card from the terminal.

  3. You apply your business logic after receiving the card acquisition response. For example:
    • You could use the issuer country and card BIN in the response to determine whether tax free shopping is allowed.
    • You could check whether this shopper is recognized. If no, you could make an input request to ask them to enroll in your loyalty program. If yes, you could check if they qualify for a discount, gift, or special offer.
  4. You make a payment request that includes the TransactionID from the card acquisition (see Step 2). Depending on your business logic, you may need to include specific fields in this request or change the amount. To the shopper, the card acquisition and subsequent payment will appear to be a single action.
  5. The terminal shows the amount due and the payment is completed.

    If the amount in the payment request is the same as the amount in the card acquisition request, a shopper using a contactless card needs to tap their card only once. Otherwise, they will need to tap their card twice: once for the card details and again for the payment.

You can also cancel the card acquisition instead of continuing with a payment. You would do this for example if the retrieved card data does not qualify for a transaction.

Before you begin

Before starting with card acquisition:

  1. Make sure that you have built an integration that can make a payment.
  2. In your Customer Area, go to Account > API URLs and on the Additional data settings tab select the data that you need for your use case. For example, recurring details for shopper recognition. Terminal API returns these data in the AdditionalResponse.

Step 1: Acquire card details

To retrieve card and shopper details before making a payment:

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

    • MessageHeader: This follows the standard MessageHeader structure, explained in Terminal API fundamentals, which includes:

      • ProtocolVersion: 3.0
      • MessageClass: Service
      • MessageCategory: CardAcquisition
      • MessageType: Request
      • SaleID: Your unique ID for the cash register.
      • ServiceID: Your unique ID for this transaction attempt, consisting of 1-10 alphanumeric characters. This value needs to be unique within the last 48 hours.
      • POIID: Unique ID of the terminal. This indicates which terminal the request will be routed to.

    • CardAcquisitionRequest: The request body for the card acquisition request, which includes:
      • SaleData.SaleTransactionID.TransactionID: Your unique reference for this request.
      • SaleData.SaleTransactionID.TimeStamp: Date and time of the request, in UTC format.
      • SaleData.TokenRequestedType Optional: Customer. This returns the card alias in the TokenValue field of the response. If you do not include the TokenRequestedType field, the card alias is returned only in the AdditionalResponse, and you will need to decode that to obtain the card alias.
      • CardAcquisitionTransaction: This object is either empty, or contains:
        • TotalAmount: Transaction amount.
          If the amount is the same as in the subsequent payment request, a contactless transaction will not require tapping the card again for the payment.
          You can change the amount later (in the payment request) based on input from the cash register, for example to give a loyalty discount. If you expect the amount to change in most cases, for example if you do a card acquisition as soon as the first item is scanned, you can choose to omit the TotalAmount field.

    For a complete list of fields you can pass in a card acquisition request and receive in the response, see the CardAcquisitionRequest API reference and the CardAcquisitionResponse API reference.

    {
        "SaleToPOIRequest":{
            "MessageHeader":{
                "ProtocolVersion":"3.0",
                "MessageClass":"Service",
                "MessageCategory":"CardAcquisition",
                "MessageType":"Request",
                "SaleID":"POSSystemID12345",
                "ServiceID":"1020711110",
                "POIID":"V400m-346403161"
            },
            "CardAcquisitionRequest":{
                "SaleData":{
                    "SaleTransactionID":{
                        "TransactionID":"02072",
                        "TimeStamp":"2020-01-07T14:14:04+00:00"
                    },
                    "TokenRequestedType":"Customer"
                },
                "CardAcquisitionTransaction":{
                    "TotalAmount":24.98
                }
            }
        }
    }
    {
        "SaleToPOIResponse": {
            "CardAcquisitionResponse": {
                "POIData": {
                    "POITransactionID": {
                        "TimeStamp": "2020-01-07T14:14:05+00:00",
                        "TransactionID": "8ha5001578501273000"
                },
                "SaleData": {...}
                },
                "PaymentInstrumentData": {
                    "CardData": {
                        "PaymentToken": {
                            "TokenRequestedType": "Customer",
                            "TokenValue": "M469509594859802"
                        },
                        "PaymentBrand": "mc",
                        "MaskedPan": "541333 **** 9999",
                        "SensitiveCardData": {
                            "ExpiryDate": "0228"
                        }
                    },
                    "PaymentInstrumentType": "Card"
                },
                "Response": {
                    "Result": "Success",
                    "AdditionalResponse": "tid=46403161&transactionType=GOODS_SERVICES&backendGiftcardIndicator=false&posadditionalamounts.originalAmountValue=2370&expiryYear=2028&alias=M469509594859802&posAmountGratuityValue=0&giftcardIndicator=false&paymentMethodVariant=mc&txtime=17%3a34%3a33&iso8601TxDate=2020-01-08T16%3a34%3a33.0000000%2b0000&cardType=mc&posOriginalAmountValue=2370&aliasType=Default&txdate=08-01-2020&paymentMethod=mc&merchantReference=02076&expiryMonth=02&cardSummary=9999&posadditionalamounts.originalAmountCurrency=EUR&posAuthAmountCurrency=EUR&posAmountCashbackValue=0&posEntryMode=CLESS_CHIP&fundingSource=CREDIT&cardScheme=mc&cardBin=541333&posAuthAmountValue=2370"
                }
            },
            "MessageHeader": {...}
        }
    }
    String serviceID = "YOUR_UNIQUE_ATTEMPT_ID";
    String saleID = "YOUR_CASH_REGISTER_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.setServiceID(serviceID);
    messageHeader.setSaleID(saleID);
    messageHeader.setPOIID(POIID);
    saleToPOIRequest.setMessageHeader(messageHeader);
    
    CardAcquisitionRequest cardAcquisitionRequest = new CardAcquisitionRequest();
    SaleData saleData = new SaleData();
    TransactionIdentification saleTransactionID = new TransactionIdentification();
    saleTransactionID.setTransactionID(transactionID);
    saleTransactionID.setTimeStamp(DatatypeFactory.newInstance().newXMLGregorianCalendar(new GregorianCalendar()));
    saleData.setSaleTransactionID(saleTransactionID);
    saleData.setTokenRequestedType( TokenRequestedType.CUSTOMER );
    cardAcquisitionRequest.setSaleData(saleData);
    
    CardAcquisitionTransaction cardAcquisitionTransaction = new CardAcquisitionTransaction();
    cardAcquisitionTransaction.setTotalAmount( BigDecimal.valueOf(24.98) );
    cardAcquisitionRequest.setCardAcquisitionTransaction(cardAcquisitionTransaction);
    saleToPOIRequest.setCardAcquisitionRequest(cardAcquisitionRequest);
    terminalAPIRequest.setSaleToPOIRequest(saleToPOIRequest);
  2. In the CardAcquisitionResponse, note the following:
    • POIData.POITransactionID: The TimeStamp and TransactionID of this card acquisition request. You will need these data later when you continue with a payment.
    • PaymentInstrumentData.CardData: The card details that are available on the card. As a minimum it includes the masked PAN and the expiry date. If you specified a TokenRequestedType of Customer in your request, this also includes:
      • PaymentToken.TokenValue: The card alias.
    • Response.AdditionalResponse: A base64 string. When decoded, this is a JSON object with additional data that you may need in your business logic, including:
      • alias: The card alias.
      • cardIssuerCountryId and cardBin: Data needed to determine eligibility for tax free shopping.
      • shopperReference and shopperEmail: For use in shopper recognition. If included, this means you already created a profile for this shopper in your database.

Step 2: Continue with the payment

After you have applied your business logic, you are ready to follow up the card acquisition with a payment request:

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

    • MessageHeader: This follows the standard MessageHeader structure, explained in Terminal API fundamentals, which includes:

      • ProtocolVersion: 3.0
      • MessageClass: Service
      • MessageCategory: Payment.
      • MessageType: Request
      • SaleID: Your unique ID for the cash register.
      • ServiceID: Your unique ID for this transaction attempt, consisting of 1-10 alphanumeric characters. This value needs to be unique within the last 48 hours.
      • POIID: Unique ID of the terminal. This should be the same payment terminal that you routed the card acquisition request to.

    • PaymentRequest: The request body for the payment request must include:

      • SaleData.SaleTransactionID.TransactionID: Your unique reference for this payment request.
      • SaleData.SaleTransactionID.TimeStamp: Date and time of the payment request, in UTC format.
      • SaleData.SaleToAcquirerData: You may need to specify tender options or additional data here, depending on your business logic. For example, taxfree.indicator=true for tax free shopping in the fast refund flow, or shopper recognition data.
      • PaymentTransaction.AmountsReq.Currency: The currency of the transaction.
      • PaymentTransaction.AmountsReq.RequestedAmount: The transaction amount.
      • PaymentData.CardAcquisitionReference: The Timestamp and TransactionID of the card acquisition request. You received this data in the POIData.POITransactionID object of the CardAcquisitionResponse.

    {
       "SaleToPOIRequest":{
          "MessageHeader":{
             "ProtocolVersion":"3.0",
             "MessageClass":"Service",
             "MessageCategory":"Payment",
             "MessageType":"Request",
             "SaleID":"POSSystemID12345",
             "ServiceID":"2020711110",
             "POIID":"V400m-346403161"
          },
          "PaymentRequest":{
             "SaleData":{
                "SaleTransactionID":{
                   "TransactionID":"15887",
                   "TimeStamp":"2020-01-07T14:14:09+00:00"
                }
             },
             "PaymentTransaction":{
                "AmountsReq":{
                   "Currency":"EUR",
                   "RequestedAmount":24.98
                }
             },
             "PaymentData":{
                "CardAcquisitionReference":{
                   "TimeStamp":"2020-01-07T14:14:05+00:00",
                   "TransactionID":"8ha5001578501273000"
                }
             }
          }
       }
    }
    {
      "SaleToPOIResponse": {
        "PaymentResponse": {
          "POIData": {...},
          "SaleData": {...},
          "PaymentReceipt": [...],
          "PaymentResult": {
            ...
            "PaymentInstrumentData": {
              "CardData": {
                "EntryMode": [
                  "Contactless"
                ],
                "PaymentBrand": "mc",
                "MaskedPan": "541333 **** 9999",
                "SensitiveCardData": {
                  "CardSeqNumb": "83",
                  "ExpiryDate": "0228"
                }
              },
              "PaymentInstrumentType": "Card"
            },
            "AmountsResp": {
              "AuthorizedAmount": 24.98,
               "Currency": "EUR"
            }
          },
          "Response": {
            "Result": "Success",
            "AdditionalResponse": "tid=46403161&AID=A000000004101001&transactionType=GOODS_SERVICES&backendGiftcardIndicator=false&posadditionalamounts.originalAmountValue=2498&expiryYear=2028&acquirerAccountCode=TestPmmAcquirerAccount&alias=M469509594859802&posAmountGratuityValue=0&giftcardIndicator=false&authorisedAmountValue=2498&retry.attempt1.shopperInteraction=POS&pspReference=8815785819310975&paymentMethodVariant=mc&refusalReasonRaw=APPROVED&authorisationMid=1000&applicationPreferredName=mc%20nl&acquirerCode=TestPmmAcquirer&store=StoreOne&txtime=15%3a58%3a52&iso8601TxDate=2020-01-09T14%3a58%3a52.0000000%2b0000&cardType=mc&posOriginalAmountValue=2498&offline=false&aliasType=Default&txdate=09-01-2020&paymentMethod=mc&cvcResult=0%20Unknown&authorisedAmountCurrency=EUR&startYear=2017&tc=D033D4E16A037E56&avsResult=0%20Unknown&cardIssueNumber=83&mid=1000&merchantReference=1240&transactionReferenceNumber=8815785819310975&expiryMonth=02&cardSummary=9999&posadditionalamounts.originalAmountCurrency=EUR&posAuthAmountCurrency=EUR&cardHolderVerificationMethodResults=1F0302&authCode=123456&adjustAuthorisationData=BQABAQA3ndroYgD7rXyM5pOhapxBPbdY4i3R%2bywOjOvdiGNbMXz9TD6X%2bX2itmBfHfL2b0KV6tBMktrmlxR%2bHq8GDkMckP2dYebHejrHrrq81zP1KuneRLa89eB%2fuNBmBg8taqOdiJOFW0cTqtAnlpCNbcudthcvBGAgbCl90Uu6Y6oqTtZzhWBCAZ%2b%2fBddOud6zY%2bV6LIv8p9YRH3uZ%2b%2bAYWA3fIEfyGygTS1t%2f2XZgLtY3T4EYFnXaPOZ8JyD1vxwC6Muai2ZsQKpQyuK1IGM%2bkow46rc5HP%2bE%2bByPNhJJGDOhUOREI2uBrjmVe9zN6OsYyVDQtgFizOMM5XbSTXGrAAZ2EG8ESm0SgEXrb9iGmqcJzVcAAB%2f7vq5ybXBAznSAwXzxpR0cqqs7VJP2PlqSWkooHcs46lrUyaHawGYA7XGxbroCJubfE1bQXkKjj5dk4fXgkY8w0sp8MDbpFjBvaGOm3ywP0c7kwgE8JBuulIlhwNtXEyEWWAUaN%2bMjs99ZplaCR0rxcYQNQCuNPIx%2b%2fr1z2J8TOxjTINuD%2bV9PvNDRn0rn8WDk4h%2f0g%2fONFpJaXw3faFT6SPzS6wRT8OX4Rlskor%2fo%2f9WKBi4YPoGy5ERIKqCLkTPRd%2fbhMo9IVeXGDgnQAuWnUcqyD%2brbprYhFcJbqGtyPrrR%2fXE9%2b2E7uabrseh%2bswiEpyGAvbeE%2fDuHCULRbT80bBLb9NfrxywiQeBsDBBtaEp8VNP0VGwFYiL%2fltm9aUbf5pTJgaEpYb5cSuVUfiWetS1ZxpsHjx3Lvn7TTdyG8w0LztGs5ob1V72DPEM8xW58GZ9FJA%3d%3d&posAmountCashbackValue=0&posEntryMode=CLESS_CHIP&startMonth=01&fundingSource=CREDIT&cardScheme=mc&cardBin=541333&posAuthAmountValue=2498"
          }
        },
        "MessageHeader": {...}
      }
    }
    String serviceID = "YOUR_UNIQUE_ATTEMPT_ID";
    String saleID = "YOUR_CASH_REGISTER_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.setServiceID(serviceID);
    messageHeader.setSaleID(saleID);
    messageHeader.setPOIID(POIID);
    saleToPOIRequest.setMessageHeader(messageHeader);
    
    PaymentRequest paymentRequest = new PaymentRequest();
    SaleData saleData = new SaleData();
    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(24.98) );
    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);
  2. In the PaymentResponse note the following:
    • PaymentInstrumentData.CardData: The same card details that you received in the CardAcquisitionResponse.
    • Response.AdditionalResponse: A base64 string. When decoded, this is a JSON object with additional data, including:
      • alias: The card alias.

Canceling the card acquisition

If the CardData you obtain in the CardAcquisitionResponse indicates that the card can't be used for the subsequent payment, you can cancel the card acquisition with an EnableServiceRequest:

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

    • MessageHeader: This follows the standard MessageHeader structure, explained in Terminal API fundamentals, which includes:

      • ProtocolVersion: 3.0
      • MessageClass: Service
      • MessageCategory: EnableService
      • MessageType: Request
      • SaleID: Your unique ID for the cash register.
      • ServiceID: Your unique ID for this transaction attempt, consisting of 1-10 alphanumeric characters. This value needs to be unique within the last 48 hours.
      • POIID: Unique ID of the terminal. This indicates which terminal the request will be routed to.

    • EnableServiceRequest:

      • TransactionAction: AbortTransaction. This cancels the current transaction.
      • DisplayOutput: Optional object to display a message on the terminal. This is the same as the DisplayOutput object in a display request.

    For a complete list of fields you can pass in an enable service request and receive in the response, see the EnableServiceRequest API reference and the EnableServiceResponse API reference.

    {
       "SaleToPOIRequest":{
          "MessageHeader":{
             "ProtocolVersion":"3.0",
             "MessageClass":"Service",
             "MessageCategory":"EnableService",
             "MessageType":"Request",
             "SaleID":"POSSystemID12345",
             "ServiceID":"3020711110",
             "POIID":"V400m-346403161"
          },
          "EnableServiceRequest":{
             "TransactionAction":"AbortTransaction"
          }
       }
    }
    {
      "SaleToPOIResponse":{
        "EnableServiceResponse":{
          "Response":{
            "Result":"Success"
          }
        },
        "MessageHeader":{
          "ProtocolVersion":"3.0",
          "SaleID":"POSSystemID12345",
          "MessageClass":"Service",
          "MessageCategory":"EnableService",
          "ServiceID":"3020711110",
          "POIID":"V400m-346403161",
          "MessageType":"Response"
        }
      }
    }
    String serviceID = "YOUR_UNIQUE_ATTEMPT_ID";
    String saleID = "YOUR_CASH_REGISTER_ID";
    String POIID = "YOUR_TERMINAL_ID";
    
    SaleToPOIRequest saleToPOIRequest = new SaleToPOIRequest();
    MessageHeader messageHeader = new MessageHeader();
    messageHeader.setProtocolVersion("3.0");
    messageHeader.setMessageClass( MessageClassType.SERVICE );
    messageHeader.setMessageCategory( MessageCategoryType.ENABLE_SERVICE );
    messageHeader.setMessageType( MessageType.REQUEST );
    messageHeader.setServiceID(serviceID);
    messageHeader.setSaleID(saleID);
    messageHeader.setPOIID(POIID);
    saleToPOIRequest.setMessageHeader(messageHeader);
    
    EnableServiceRequest enableServiceRequest = new EnableServiceRequest();
    enableServiceRequest.setTransactionAction( TransactionActionType.ABORT_TRANSACTION );
    saleToPOIRequest.setEnableServiceRequest(enableServiceRequest);
    terminalAPIRequest.setSaleToPOIRequest(saleToPOIRequest);

    If the card acquisition is successfully cancelled, you receive an EnableServiceResponse that contains:

    • Response.Result: Success

  2. Continue as applicable, for example with a new card acquisition request or a payment request.

Next steps

See also