Search

Are you looking for test card numbers?

Would you like to contact support?

Point-of-sale icon

Make a payment

Make a point of sale card payment.

After you have designed your integration and boarded your terminal, you are ready to make card payments on the Adyen payments platform.

To initiate a payment, you make a Terminal API call from your cash register. This routes the transaction to the terminal, which prompts the shopper to present their card and verify the payment. The terminal then sends the payment to Adyen for processing.

Once processed, your integration receives the result of the payment.

Before you begin

Before you make a payment with our Terminal API, make sure you have designed your Adyen point of sale integration. This includes:

  1. Signing up for an Adyen test account, and creating a store.
  2. Ordering a terminal and boarding it to a store.
  3. Determining whether your integration will use a local or cloud-based architecture.
  4. Reading and understanding the Terminal API fundamentals.
  5. If you are building a integration that uses asynchronous cloud communications, make sure you have set up display notifications. This is how your integration will receive the payment result.

Make a payment request

The first step in making a card payment is to initiate it, with an API request from your cash register. Once you make this request, the terminal will prompt the shopper to present their card by swiping, inserting, or tapping it on the terminal. If required, the shopper then verifies the payment by entering their PIN or signature.

To initiate the payment:

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

    • MessageHeader: The standard SaleToPOIRequest.MessageHeader object, explained in Terminal API fundamentals:
      Parameter Required Description
      ProtocolVersion -white_check_mark- 3.0
      MessageClass -white_check_mark- Service
      MessageCategory -white_check_mark- Payment
      MessageType -white_check_mark- Request
      SaleID -white_check_mark- Your unique ID for the cash register.
      ServiceID -white_check_mark- Your unique ID for this request, consisting of 1-10 alphanumeric characters. Must be unique within the last 48 hours.
      POIID -white_check_mark- Unique ID of the terminal that you want to route this request to. Format: [device model]-[serial number].
    • PaymentRequest: The request body. This must include:

      Parameter Required Description
      SaleData.SaleTransactionID -white_check_mark- An object with:
      • TransactionID: Your unique reference for this request. In your Customer Area and Adyen reports, this will show as the merchant reference for the transaction.
      • TimeStamp: Date and time of the request in UTC format.
      PaymentTransaction.AmountsReq -white_check_mark- An object with:
      • Currency: The transaction currency.
      • RequestedAmount: The final transaction amount.

    The example below shows how you would initiate a 10.99 EUR payment on the terminal with the POIID V400m-324688179

    For more information on the Terminal API request structure, refer to the Terminal API fundamentals.

    {
        "SaleToPOIRequest":{
            "MessageHeader":{
                "ProtocolVersion":"3.0",
                "MessageClass":"Service",
                "MessageCategory":"Payment",
                "MessageType":"Request",
                "SaleID":"POSSystemID12345",
                "ServiceID":"0207111104",
                "POIID":"V400m-324688179"
            },
            "PaymentRequest":{
                "SaleData":{
                    "SaleTransactionID":{
                        "TransactionID":"27908",
                        "TimeStamp":"2019-03-07T10:11:04+00:00"
                    }
                },
                "PaymentTransaction":{
                    "AmountsReq":{
                        "Currency":"EUR",
                        "RequestedAmount":10.99
                    }
                }
            }
        }
    }
    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.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(10.99) );
    paymentTransaction.setAmountsReq(amountsReq);
    paymentRequest.setPaymentTransaction(paymentTransaction);
    saleToPOIRequest.setPaymentRequest(paymentRequest);
    terminalAPIRequest.setSaleToPOIRequest(saleToPOIRequest);
  2. The payment request is routed to the terminal, for the shopper to present their card and verify the payment.

    If you are building a test integration, you can use an Adyen test card (that you ordered with your test terminal).

  3. The payment is then sent to the Adyen payments platform for processing. Once processed, your integration receives the payment result.

Keeping your staff informed with webhooks

While your shopper is interacting with the terminal, you may want to present progress messages on your cash register. These can keep your staff informed when:

  • The terminal is waiting for the shopper's PIN or signature.
  • The shopper's signature is ready for checking.

These messages are delivered using display notifications, which are webhooks that are sent to an endpoint that you specify. For information on how to set up and use display notifications, refer to our display notifications documentation.

Payment response

When your payment has been processed by the terminal you receive the payment result. This is provided either in a synchronous API response or via a webhook when your integration uses asynchronous cloud communications.

For synchronous communications, local or cloud, you receive the result in the API response.
The main payment result is provided in the element PaymentResponse.Response.Result

For asynchronous cloud communications you receive the result in a TENDER_FINAL display notification.

If the payment is successful:

  • Approved is shown on the terminal display.
  • You receive the payment result. This contains:

    • POIData.POITransactionID.TransactionID: Transaction identifier for the payment.
    • PaymentResponse.Response.Result: Success
    • PaymentResponse.Response.AdditionalResponse: Additional transaction data. You'll receive either a string of form-encoded key-value pairs or a Base64 string that you need to decode to get a JSON object. For example, data relating to features such as shopper recognition, shopper input like an email address, or tax free shopping eligibility.
    • PaymentReceipt: Object containing data you can use to generate a receipt.

    The example result below indicates that the payment was successful. The transaction identifier for this payment is oLkO0012498220087000.981517998282382C

    {
      "SaleToPOIResponse":{
        "MessageHeader":{...},
        "PaymentResponse":{
          "POIData":{
            "POITransactionID":{
              "TransactionID": "oLkO0012498220087000.981517998282382C"
            },
            ...
          },
          "Response":{
            "Result":"Success",
            "AdditionalResponse":"...shopperEmail=shoppersemail%40address.com..."
          },
          ...
        },
        "PaymentReceipt":{...}
      }
    }

You can also view the details of a payment in your Customer Area, under Transactions > Payments.

Handling failed payments

If a payment fails, the payment result includes the Result Failure, as well as information on why the payment failed.

While building a test integration, you can simulate payment failure scenarios. For example, if you specify a RequestedAmount with 123 as the last three digits, such as 101.23 or 41.23, the payment will be Declined.

For more information on the payment scenarios you can test, see testing your integration.

When a payment fails:

  • Declined is shown on the terminal display.
  • You receive a payment result containing:

    • POIData.POITransactionID.TransactionID: Transaction identifier for the failed payment.
    • PaymentResponse.Response.Result: Failure
    • PaymentResponse.Response.ErrorCondition: Indicates why the payment failed.
      For example, Refused indicates the card issuer refused the transaction, and Cancel indicates the transaction was cancelled on the terminal. You can check our refusal reasons documentation for a list of failure reasons and what these mean.

    The example result below indicates that the payment failed because it was refused by the card issuer. The transaction identifier for this payment attempt is oLkO0012498700082200.982823828151799C

    {
      "SaleToPOIResponse":{
        "MessageHeader":{...},
        "PaymentResponse":{
          "POIData":{
            "POITransactionID":{
              "TransactionID": "oLkO0012498700082200.982823828151799C"
            },
            ...
          },
          "Response":{
            "AdditionalResponse":"...pspReference=982823828151799C...",
            "Result":"Failure",
            "ErrorCondition":"Refused"
          },
          ...
        }
      }
    }

You can also view the details of failed payments in your Customer Area, under Transactions > Payments.


After you've made a test payment, you can continue building your integration. You may want to learn how to issue refunds, accept other payment methods, or enable tipping and gratuities.

Alternatively, you can learn what to do when you do not receive a payment result (for example, due to a technical or connection issue). We strongly recommend that your integration is able to automatically verify the status of a payment in this scenario. This can help reduce the risk of your store staff unnecessarily refunding the transaction, or making a duplicate payment.

Next steps