API Reference

Payment (CP) - Adyen: P5

Card-Present payments done using P5 terminal/reader hardware.

Overview

This document will outline how to collect card-present (CP) payments from using Adyen as the processor and the P5 as the hardware. Please note that the big difference here is that the P5 hardware is asynchronous whereas the Adyen hardware is synchronous when using the API calls.

Selecting the P5 hardware

Before the P5 can be used, the merchant will first need to associate the P5 to their account. This can be done through the payment portal Adding P5 Hardware in the Portal or through the endpoint (POST /v2/hardware). If added through the API, it will be good to track the terminal_id as this will be required for the API calls to make a payment. If the P5 was added through the portal or you didn't keep track of the ID, you can always get a list of all terminals associated with the merchants account with the following endpoint (GET /v2/hardware).

Collecting payment

A basic example of collecting payment requires 3 types of API calls:

  • Payment Intent (describes how we intend to collect payment and the initial properties for the payment)
  • Auth (initiates the collection of a card payment from the terminal)
  • Status Get (gets the status of the payment)

Creating the Payment Intent

You will need to create a payment intent either server side or client-side by calling the Payment CREATE API endpoint (POST /v2/payment/intent).

// POST /v2/payment/intent
{
    "external_account_id": "account_123456",
    "amount": 12.99,
    "payment_method_types": "card_present",
    "capture_method": "automatic",
    "external_payment_id": "transaction_123456"
}

This will return a result that has a payment_id and you'll need this id to authorize the payment.

Collect Payment (asynchronous)

To request a payment from a specific terminal, call the following endpoint (POST /v2/payment/auth). Please note that in this case terminal_id and payment_id are required. Also note that this call is asynchronous. This means the call will return immediately even though the terminal has not collected payment yet. This call will return with a status of payment_method_requested.

// POST /v2/payment/auth
{
    "external_account_id": "account_123456",
    "payment_id": "pi_12345",
    "external_payment_id", "transaction_123456",  
    "terminal_id": "S1F2-1234567890",
}

Poll Payment Status (asynchronous)

You will need to poll the API for the payment status. We suggest you have a polling cycle of around 1 second. If you need more responsiveness in you UI, you could poll every half second if necessary. This is done through the following endpoint (GET /v2/payment/intent/[ID]) and will return a result like the following:

// GET /v2/payment/intent/pi_12345?external_account_id=account_123456
{
  "payment_id": "pi_12345",
  "date_created": "2023-05-08T20:53:36+00:00",
  "external_transaction_id": "05245bd0-36a3-4c23-fb35-d046fc8b339c",
  "status": "payment_method_requested",
  "amount": "14.84",
  "amount_authorized": "0.00",
  "amount_captured": "0.00",
  "amount_capturable": 0,
  "amount_refunded": "0.00",
  "amount_refundable": 0,
  "tip_amount": 0,
  "donation_amount": 0,
  "currency": "USD",
  "card_present": true,
  "payment_method_id": null,
  "notes": null,
  "authorization_code": "123456",
  "processor": "Adyen"
}

While you are polling, the status will change depending on what has happened. Here are status changes to look for:

  • payment_method_requested means we are still waiting on the terminal. Keep polling.
  • succeeded or capture_requested means the payment has been collected and auto-captured. Stop polling.
  • requires_capture means the payment has been collected and authorized. If you had specified manual capture, then you can stop polling, but if you had specified automatic capture, then you will need to continue polling you get another status.
  • requires_payment_method means one of many possible things. It may have time out or it may have been canceled. Stop polling. In this case you could retry the the auth above if needed. See Error Responses below.
  • error likely means it was declined for one of many reasons a card can be declined. Stop polling. In this case you can retry if the customer decides to either use a different card or wants to retry the same card again. See Error Responses below.

Once you have either a succeeded, capture_requested or requires_capture you can complete collecting payment in your POS app. If the status was requires_capture you will still need to capture the payment yourself through the following endpoint (POST /v2/payment/capture).

Handling your own timeout

While polling, you will eventually want to give up if you don't get a status change after a certain amount of time. Because of different events that can happen at the terminal (payment, signature, tips, donations, etc.). We recommend polling for at least 3 minutes before you timeout on your side.

Error Responses

When polling after calling auth, there are a variety of possible outcomes that are not successful. With each attempt to auth a payment, the latest response is attached to the payment and is returned with a GET on that payment. When possible, last_error will contain English description describing the reason that it was not successful. This response may come from Adyen or the Application on the P5. In some cases last_error_code will also be returned. When parsing the response, when possible last_error_codeshould be used as the description could change. Description may be shown to the clerk.

// GET /v2/payment/intent/pi_12345?external_account_id=account_123456
{
  "payment_id": "pi_12345",
  "date_created": "2023-05-08T20:54:36+00:00",
  "external_transaction_id": "05245bd0-36a3-4c23-fb35-d046fc8b339c",
  "status": "requires_payment_method",
  "amount": "14.84",
  "amount_authorized": "0.00",
  "amount_captured": "0.00",
  "amount_capturable": 0,
  "amount_refunded": "0.00",
  "amount_refundable": 0,
  "tip_amount": 0,
  "donation_amount": 0,
  "currency": "USD",
  "card_present": true,
  "payment_method_id": null,
  "notes": null,
  "authorization_code": "123456",
  "processor": "Adyen",
  "last_error": "Canceled by shopper",
  "last_error_code": "USER_CANCEL"
}

Possible codes and descriptions

Error CodeDescription
API_ERRORAPI Error. Please try again (insert card if possible).
APP_ERRORApplication error. Please try again (insert card if possible).
EMV_ERRORSomething went wrong while processing the transaction. Please try again (insert card if possible).
OFFLINE_DECLINEDeclined.
ONLINE_DECLINEThe processor declined the card.
POS_CANCELCanceled by clerk.
REVERSALPayment declined.
USER_CANCELCanceled by shopper.
USER_TIMEOUTTimed out waiting for shopper.
WEB_TIMEOUTConnection issue. Please check your network and try again.

This table of error codes above applies only to Application version 1.265 and higher.