Terminal-2 icon

NFC tags reading and writing

Read and write data on NFC tags using Adyen payment terminals.

Near Field Communication (NFC) tags can be cards, phones, bracelets, or similar. They can store data and are commonly used for contactless payments, loyalty programs, festival entrance, and more. By sending a Terminal API card acquisition request to your Adyen payment terminal, you can identify the type of NFC tag, or read and write data to it. If you prefer to use a dedicated Android app to process NFC operations for stored value cards and identity cards, it is possible to hide the Adyen UI and keep your app's UI in the foreground.

You can also create a session to perform multiple requests as a single user interaction.

To understand how you can use this, here are some examples:

  • Enroll shoppers in a loyalty program.
  • Identify a customer when entering an area such as festival grounds or a parking garage.
  • Check the balance and top up NFC tags such as loyalty and transport cards, or festival tags used to pay for drinks.
  • Define multiple behaviours of the NFC tag. For example, use the tag to enter one event and reuse it to pay for drinks at a different event.

Requirements

Requirement Description
Integration type A Terminal API integration.
Hardware An Adyen payment terminal that supports the NFC tags that you want to use.
Limitations Hiding the Adyen UI for stored value cards and identity cards is only supported for terminal models S1E, S1E2L, S1F2, and S1U2 on software version V1.114 or later.
Setup steps Before you begin, provide our Support Team with the following information so that the team can create your NFC configuration:
  • The type of NFC tag you want to use.
  • If your NFC tags have cryptographic keys: the keys you want to use to access data.
  • Whether you want to hide the Adyen UI and instead keep your own UI in the foreground if you use a dedicated Android app for NFC operations.

Supported products

The following table shows the payment terminal types that support NFC tags:

Models MIFARE Classic MIFARE DESFire MIFARE Ultralight MIFARE Ultralight C MIFARE Ultralight AES
AMS1 -white_check_mark- -white_check_mark- -white_check_mark- -white_check_mark- -white_check_mark-
e285p -white_check_mark- -white_check_mark- -white_check_mark- -white_check_mark- -x-
M400 -white_check_mark- -x- -white_check_mark- -white_check_mark- -x-
M450 -x- -x- -x- -x- -x-
P400 PLus -white_check_mark- -x- -white_check_mark- -x- -x-
P360 -x- -x- -x- -x- -x-
S1E -white_check_mark- -white_check_mark- -white_check_mark- -white_check_mark- -white_check_mark-
S1E2L -white_check_mark- -white_check_mark- -white_check_mark- -white_check_mark- -white_check_mark-
S1F2 -white_check_mark- -white_check_mark- -white_check_mark- -white_check_mark- -white_check_mark-
S1U2 -white_check_mark- -white_check_mark- -white_check_mark- -white_check_mark- -white_check_mark-
SFO1 -x- -x- -x- -x- -x-
UX300 -x- -x- -x- -x- -x-
UX410 -x- -x- -x- -x- -x-
V240m Plus -white_check_mark- -x- -white_check_mark- -white_check_mark- -x-
V400c Plus -white_check_mark- -x- -white_check_mark- -white_check_mark- -x-
V400m -white_check_mark- -x- -white_check_mark- -white_check_mark- -x-

How it works

To use NFC tags on Adyen payment terminals:

  1. Make a card acquisition request to identify, read, or write to an NFC tag.

    For more complex use cases that require multiple requests, see Create a session.

  2. The terminal prompts the user to present their NFC tag or NFC-enabled card.
  3. The user presents their NFC tag by tapping, inserting, or swiping.
  4. The terminal makes one or multiple read/write requests to the NFC tag.
    While this is going on, the terminal shows the One moment loading screen.

    If you want to use a dedicated Android app to process NFC operations, it is possible to hide the Adyen UI and keep your app's UI in the foreground.

Hide Adyen UI during NFC operations

Optionally, if you want to use a dedicated Android app to process NFC operations for stored value cards or identity cards, you can show your own UI on the payment terminal display instead of the Adyen UI. This can be useful for example, for a loyalty card or transport card.

With this feature enabled you make a card acquisition request to identify, read, or write to an NFC tag. If the payment terminal detects a stored value or identity card, it hides the Adyen UI.

If the terminal detects a regular payment card during any of the NFC card acquisition flows, the response returns a BLOCK_CARD error. This does not mean that the card itself is blocked, but that it can not be used for operations with your Android app. We recommend that your system returns a message that instructs the terminal operator to ask the shopper to present a card or tag that can be used with your app.

The code sample below shows the response for a card acquisition to identify the NFC tag, when a regular payment card was presented.

Regular card acquisitions are not affected by this feature and show the Adyen UI as expected.

Identify the type of NFC tag

You can use the card acquisition request to get the unique identifier and the type of the NFC tag. You can use this identifier, for example, to check if the NFC tag exists in your system or if it is still valid.

  1. Create an Operation JSON object with Operation.Type: NFCReadUID:

  2. Encode the Operation JSON object to Base64. You will pass the resulting string in SaleData.SaleToPOIData.

  3. Make a card acquisition request to a Terminal API endpoint, specifying:

    • The standard SaleToPOIRequest.MessageHeader object, with MessageClass set to Service and MessageCategory set to CardAcquisition.

      Parameter Required Description
      ProtocolVersion -white_check_mark- 3.0
      MessageClass -white_check_mark- Service
      MessageCategory -white_check_mark- CardAcquisition
      MessageType -white_check_mark- Request
      ServiceID -white_check_mark- Your unique ID for this request, consisting of 1-10 alphanumeric characters. Must be unique within the last 48 hours for the terminal (POIID) being used.
      SaleID -white_check_mark- Your unique ID for the POS system component to send this request from.
      POIID -white_check_mark- The unique ID of the terminal to send this request to. Format: [device model]-[serial number].
    • CardAcquisitionRequest.SaleData:

      Parameter Required Description
      SaleTransactionID -white_check_mark- An object with:
      • TransactionID: your reference to identify the transaction. We recommend using a unique value.
      • TimeStamp: date and time of the request in UTC format.
      SaleToPOIData The Base64-encoded Operation JSON object.
    • CardAcquisitionRequest.CardAcquisitionTransaction:

      Parameter Required Description
      TotalAmount The transaction amount. You can omit the TotalAmount field when getting the UID of the NFC tag.
      If you omit TotalAmount, you still have to include an empty CardAcquisitionTransaction field in the request.

    The example below shows a card acquisition request to identify the NFC tag:

  4. In the AdditionalResponse of the CardAcquisitionResponse note:

    • NFC.uid: the unique identifier of the NFC tag.
    • NFC.variant: the type of the NFC tag, for example mf_classic for MIFARE Classic.

    After you have identified the NFC tag, the loading screen continues to show until you send an enable service request` (see the next step).

  5. To stop the loading screen, make a POST request to a Terminal API endpoint, specifying:

    • The standard SaleToPOIRequest.MessageHeader object, with MessageClass set to Service and MessageCategory set to EnableService.

      Parameter Required Description
      ProtocolVersion -white_check_mark- 3.0
      MessageClass -white_check_mark- Service
      MessageCategory -white_check_mark- EnableService
      MessageType -white_check_mark- Request
      ServiceID -white_check_mark- Your unique ID for this request, consisting of 1-10 alphanumeric characters. Must be unique within the last 48 hours for the terminal (POIID) being used.
      SaleID -white_check_mark- Your unique ID for the POS system component to send this request from.
      POIID -white_check_mark- The unique ID of the terminal to send this request to. Format: [device model]-[serial number].
    • EnableServiceRequest with:

      Parameter Required Description
      TransactionAction -white_check_mark- AbortTransaction.
      DisplayOutput Optional object to show your own message and an 'Approved' icon (green check mark) or a 'Declined' icon (red cross).
      If you omit DisplayOutput, the terminal shows Canceled, a red cross , and Transaction canceled. Omit if you have a NFC configuration that hides the Adyen UI while using a dedicated Android app for NFC operations. Otherwise the Adyen UI will be brought to the foreground.

    The following example is the basic request, without the DisplayOutput object, to stop the card acquisition flow.

Read data

NFC tags have multiple parts that can store data. Because the data structure is different for every NFC tag type, the request needs to specify where to read the data from. For some tags, you need to include the key to read data from a sector, aid, orpage.
Select a tab to see the parameters that you need to specify to read data from MIFARE Classic, MIFARE DESFire, or MIFARE Ultralight.

Write data

NFC tags have multiple parts that can store data. Because the data structure is different for every NFC tag type, the request needs to specify the sector, aid, or page where to write the data to.
Select a tab to see the parameters that you need to specify to write data to MIFARE Classic, MIFARE DESFire, or MIFARE Ultralight.

Create a session

If your use case requires multiple read/write actions on an NFC tag, you can create a session to make multiple requests part of the same user interaction. While the session is in progress, the terminal shows the One moment screen.

To start the session you need to add Session.Type: Begin in the SaleToPOIData of your first identify, read, or write request. You then send multiple requests and, to finish the session, you add Session.Type: End in the SaleToPOIData of the last request. All requests that belong to the session must contain the same Session.Id in the SaleToPOIData.
When the session ends, the terminal continues to show the loading screen until you send an enable service request.

Here's an example of a session that consists of three card acquisition requests:

Step 1: Start a session and identify the NFC tag type

When starting the session, you need specify the Id to connect the requests into a single session. Here's example of how identify the tag and start the session:

  1. Create a JSON object with:

    Parameter Required Description
    Session.Type -white_check_mark- Begin: starts the session.
    Session.Id -white_check_mark- Your unique reference of the session.
    Session.Timeout -white_check_mark-
    • How long the One moment screen is shown on the terminal display, in milliseconds.
    • If there is no end session request, how long before the session data is deleted and new requests can be sent.
    Operation.Type -white_check_mark- NFCReadUID: returns the NFC tag identifier and type.
  2. Encode the JSON object to Base64. You will pass the resulting string in SaleData.SaleToPOIData.

  3. Make a card acquisition request with the Base64-encoded string in the SaleToPOIData.

Step 2: Send read data request with Session.Id

Make sure to include the Session.Id specified in the SaleToPOIData of the first request. Here's example of how to read data from MIFARE Classic as part of the session:

  1. Create a JSON object with:

    Parameter Required Description
    Session.Id -white_check_mark- Your unique reference of the session, specified in the first request.
    Operation.Type -white_check_mark- NFCRead: reads data from the specified sector.
    Operation.Variant -white_check_mark- MifareClassic: the type of NFC tag.
    Operation.NFCData -white_check_mark-
    If you leave the NFCData array empty, the terminal will try to read all sectors.
    An array with:
    • sector: specifies what sector on MifareClassic to read from.
    • keyType: specifies what key is used to access a sector, a (default) or b.
      You cannot use keyType: b on Android terminals due to a limitation from Castles.
  2. Encode the JSON object to Base64. You will pass the resulting string in SaleData.SaleToPOIData.

  3. Make a card acquisition request with the Base64-encoded string in the SaleToPOIData.
    The example below shows how to read data from MifareClassic NFC tag as part of the session:

Step 3: Write data to the NFC tag and end the session

In the final request of the interaction, make sure to include the same Session.Id and Session.Type: End. Here's example of how to write data to MIFARE Classic and end the session:

  1. Create a JSON object with:

    Parameter Required Description
    Session.Type -white_check_mark- End: ends the session.
    Session.Id -white_check_mark- Your unique reference of the session.
    Operation.Type -white_check_mark- NFCWrite: reads data from the specified sector.
    Operation.Variant -white_check_mark- MifareClassic: the type of NFC tag.
    Operation.NFCData -white_check_mark-
    If you leave the NFCData array empty when trying to write, the response will return the UID and the variant but will not write to the card.
    An array with:
    • sector: specifies what sector on MifareClassic to read from.
    • keyType: specifies what key is used to access a sector, a (default) or b.
      You cannot use keyType: b on Android terminals due to a limitation from Castles.
  2. Encode the JSON object to Base64. You will pass the resulting string in SaleData.SaleToPOIData.

  3. Make a card acquisition request with the Base64-encoded string in the SaleToPOIData.
    The example below shows how to write data MifareClassic NFC tag and end the session:

    After you end the session, the loading screen continues to show until you send an enable service request (see the
    next step).

  4. To stop the loading screen, make an enable service request to a Terminal API endpoint, specifying:

    • The standard SaleToPOIRequest.MessageHeader object, with MessageClass set to Service and MessageCategory set to EnableService.

    • EnableServiceRequest with:

      Parameter Required Description
      TransactionAction -white_check_mark- AbortTransaction.
      DisplayOutput Optional object to show your own message and an 'Approved' icon (green check mark) or a 'Declined' icon (red cross).
      If you omit DisplayOutput, the terminal shows Canceled, a red cross , and Transaction canceled. Omit if you have a NFC configuration that hides the Adyen UI to make sure the UI does not show.

    The following example is the basic request, without the DisplayOutput object, to stop the card acquisition flow.

See also