Understanding APDU: How Terminals Talk to Smart Cards

ASSI Avatar

When I first worked on a smart card integration project years ago, I came across logs filed with hexadecimal codes. My instinct was to skim through them but as I would soon learn, those hex values were the hearth of the transaction. They were APDUs the way the terminal and the smart card talk.

One common questions I often hear is “Are APDU and ISO 8583 both used to transmit messages?” The answer is yes, but they serve very different purposes at different layers of the transaction:

  • APDU is used to send low-level commands to the smart card chip, like selecting an application or reading data.
  • ISO 8583 is used to send high-level transaction messages to the bank or issuer, like a purchase request for authorization.

Think of it this way:

APDU is how the terminal talks to the chip. ISO 8583 is how the terminal talks to the bank.

Understanding this distinction is key to mastering the full flow of EMV transactions.

APDU operates on the physical and data link layers of the communication stack. When you insert a card, APDUs are exchanged directly with the chip inside the card. This interaction is part of the EMV specification and happens even before any network transaction takes place.

ISO 8583, on the other hand, is used once all the card data (like PAN, expiry, cryptograms, etc.) is collected. The terminal then formats this into an ISO 8583 message and sends it over the network to the issuer for approval. These two formats never directly talk to each other but the success of one relies on the success of the other.


What is APDU?

APDU stands for Application Protocol Data Unit. It is a message format defined by ISO/IEC 7816-4, a standard for electronic identification cards (smart cards).

In practice, APDUs are the commands and responses exchanged between the terminal and the smart card chip. The terminal sends a command (Command APDU), and the card replies with a response (Response APDU). These communications happen byte by byte, often in hexadecimal format.

Imagine this like a conversation:

  • Terminal: “Please select your main application.”
  • Card: “Sure, selected. Here is some extra info about the app.”

That back-and-forth is made possible through APDUs.

Each APDU has a strict structure and length, and incorrect formatting (even by one byte) can cause the card to reject the command. This is why it’s so important to understand how to read, write, and debug APDUs correctly.

There are two primary types of APDUs:

  1. Command APDU: Sent from the terminal to the smart card. It tells the card to do something like read a file or compute a cryptogram.
  2. Response APDU: Sent by the smart card to respond to the command. It either includes the requested data or returns a status word showing success or error.

Coming up next, we’ll break down the exact structure of APDUs byte by byte and walk through real examples you might encounter in actual EMV transactions.


APDU Command Structure

A typical Command APDU has this layout:

Plaintext
CLA | INS | P1 | P2 | [Lc | Data] | [Le]
  • CLA: Class byte
  • INS: Instruction byte (e.g., SELECT READ RECORD)
  • P1, P2: Parameters
  • Lc: Length of data
  • Data: Actual Data
  • Le: Expected response length

Example:

Plaintext
00 A4 04 00 07 A0 00 00 00 03 10 10 00

This is a SELECT command asking the card to select an application with AID: A0000000031010


Response APDU Structure

Plaintext
[Response Data] SW1 SW2

The last two bytes are the status words.

Common examples:

  • 90 00 – Success
  • 6A 83 – File/Application not found
  • 6D 00 – Instruction not supported

SELECT Command Explained

The SELECT command tells the card: “I want to use the application. Please load it”.

Command Breakdown:

Plaintext
00 A4 04 00 07 A0 00 00 00 03 10 10 00
  • A4 – Means “SELECT”
  • 04 – Select by name (AID)
  • 07 – Length of AID
  • A0000000031010 – The AID
  • 00 – We expect a full response

Typical Response:

Plaintext
6F 23  
   84 07 A0 00 00 00 03 10 10  
   A5 18  
      50 0A 4D 41 53 54 45 52 43 41 52 44

This is a TLV structure:

  • 6F: File Control Info template
  • 84: AID
  • A5: Propriety data
  • 50: App label “MASTERCARD”

GET PROCESSING OPTIONS (GPO)

After selecting the app, the terminal says: “How should I process this transaction?”

Command:

Plaintext
80 A8 00 00 02 83 00
  • A8 – GPO instruction
  • 83 00 – Tag 83 means empty PDOL (we’re not sending terminal data)

Sample Response:

Plaintext
77 0E  
   82 02 38 00  // AIP – card capabilities  
   94 08 08 01 01 00 10 01 01 00  // AFL – where to read records  
   90 00

This tells the terminal:

  • What the card can do (e.g., offline/online auth)
  • Which records to read

READ RECORD Command

After getting the Application File Locator (AFL) from the GPO response, the terminal knows which files (records) it needs to read from the card to extract transaction-relevant data like PAN (card number), expiry date, etc.

Format:

Plaintext
00 B2 <RecordNumber> <SFI*8 + 4> Le
  • B2 = READ RECORD instruction
  • <RecordNumber> = 01, 02, etc.
  • <SFI*8 + 4> = Short File Identifier with read flag
  • Le = Expected length (commonly 00 to get full data)

Example:

Plaintext
00 B2 01 0C 00
  • Record: 01
  • SFI: 01 -> 01 * 8 = 08, then add 4 → 0C
  • Le: 00 -> fetch all data

Sample Response:

Plaintext
70 1E  
   5A 08 525478XXXXXX1337  
   5F24 03 250731  
   5F34 01 01  
   9F10 07 06 01 1A 03 A0 00 00  
   90 00

This includes:

  • 5A: PAN
  • 5F2A: Expiry date
  • 5F34: PAN sequence number
  • 9F10: Issuer Authentication data

Each record may contain different tags depending on card configuration.


GENERATE AC (Application Cryptogram)

After reading the required records, the terminal prepares to ask the card to generate a cryptogram, which is used to prove transaction authenticity.

  1. ARQC (Authorization Request Cryptogram) — for online auth
  2. TC (Transaction Certificate) — for offline approval

Format:

Plaintext
80 AE P1 P2 Lc Data Le
  • AE: Instruction for Generate AC
  • P1: Cryptogram type request (e.g., 80 = ARQC request)
  • P2: Cryptogram info data (usually 00)
  • Lc: Length of the CDOL1 data
  • Data: Formatted based on CDOL1
  • Le: Expected length of response

CDOL1 = Card Data Object List – tells the terminal what tags to send in this command (like amount, date, terminal type, etc.)

Example:

Plaintext
80 AE 80 00 1A <Data> 00

The response contains:

  • 77 – Response template
  • 9F27 – Cryptogram Information Data
  • 9F36 – Application Transaction Counter
  • 9F26 – Application Cryptogram (the actual result)
  • 9F10 – Issuer App Data

How DE55 is Built (For ISO 8583)

Once the terminal gets these TLVs (from GPO, READ RECORD, and GENERATE AC), it constructs DE55, a field in ISO 8583 that carries ICC data.

DE55 = Concatenation of specific EMV tags, encoded in BER-TLV format

Common Tags in DE55:

  • 9F26: Application cryptogram
  • 9F27: Cryptogram Information Data
  • 9F10: Issuer Application Data
  • 9F37: Unpredictable number
  • 9F36: Application Transaction Counter
  • 95: Terminal Verification Results
  • 9A: Transaction Date
  • 9C: Transaction Type
  • 9F02: Amount, Authorised
  • 5F2A: Transaction Currency Code
  • 82: AIP
  • 84: Dedicated File (DF) Name
  • 9F1A: Terminal Country Code
  • 9F03, 9F33, 9F34, 9F35, 9F09, 9F41 (if required)

All these TLVs are collected and then concatenated in order to form DE55.

Sample DE55 (Hex):

Plaintext
9F2608B6A89F7B03A8B5DE  
9F270180  
9F10120110A00003220000000000000000000000  
9F3704A1B2C3D4  
9F3602001C  
95050080000000  
...

Each tag follows TLV encoding: Tag | Length | Value


TLV Parsing

Most responses from the card are TLV (Tag-Length-Value) formatted. Let’s take this response:

Plaintext
6F 23  
   84 07 A0 00 00 00 03 10 10  
   A5 18  
      50 0A 4D 41 53 54 45 52 43 41 52 44
  • 6F: Template tag
    • Length: 23
  • Inside It:
    • 84: AID tag – value is A0000000031010
    • A5: Proprietary template
      • 50: App Label – “MASTERCARD”

You can parse this using logic like:

  • Read 1 or 2 bytes -> Tag
  • Read next byte -> Length
  • Read next N byte -> Value

This structure is used in SELECT, GPO, READ RECORD responses, and more.


Debugging Tips

  • Always inspect the SW1 SW2 status words.
  • Use APDU logs in hex to follow the conversation.
  • If 6A 88 appears, it usually means required data is missing (e.g., PDOL)
  • Build a small script to walk through TLVs, it helps a lot

Common APDU Commands Recap

CommandINS CodePurpose
SELECTA4Select AID or file
GPOA8Get processing options
READ RECORDB2Retrieve card data
GENERATE ACAEGenerate cryptogram
GET RESPONSEC0Fetch more data (when card says so)

Here’s the entire terminal flow:

  1. SELECT AID → Identify card application
  2. GPO → Get processing rules (AFL, AIP)
  3. READ RECORDS → Get static data like PAN
  4. GENERATE AC → Get cryptographic response
  5. Build DE55 → Populate ISO 8583 for host
  6. Send to Issuer → Wait for online auth decision

Final Thoughts

APDU is the language that a terminal uses to speak to the chip. It’s low-level, structured, and absolutely critical in EMV transactions.

If your app works with smart cards especially in payments, you need to understand how APDU commands are formed and interpreted.

From personal experience, once I understood SELECT, GPO, TLV, and status words, debugging transactions became much faster. It’s not just about what failed it’s about why, and APDU reveals that.