Module 4: Key Data Elements Deep Dive

Profile boundary: The worked messages and code below use explicit teaching profiles. Field widths, mandatory fields, response actions, timers, and matching keys must come from the selected exercise or a versioned endpoint agreement. Schematic dumps and scenarios are synthetic; they are not network certification fixtures. Diagnostic snippets illustrate mechanisms and are not a complete production library.

1 / 24

Slide 1: The Heart of the Message

You've parsed the structure. Now understand the meaning.

Field  Name                    What It Tells You
─────  ────                    ─────────────────
DE2    Primary Account Number  Which card
DE3    Processing Code         What type of transaction
DE4    Amount                  How much money
DE7    Transmission DateTime   When (UTC)
DE11   STAN                    Unique transaction ID
DE35   Track 2 Data            Swipe data (PAN + expiry + more)
DE37   RRN                     Network reference number
DE39   Response Code           Approved or why not

These fields appear in 90% of authorization messages.

2 / 24

Slide 2: DE2 - Primary Account Number (PAN)

PAN: 4532015112830366
     ├──────┤├──────────┤├┤
     IIN/BIN  Account    Check
              Number     Digit

IIN First Digits:
4...       = Visa
51-55...   = Mastercard
34, 37...  = American Express
6011, 65.. = Discover

Key facts:

  • LLVAR n..19 (variable length, 13-19 digits)
  • Last digit is Luhn check digit
  • First 6-8 digits identify the issuer
  • Never log full PAN - mask as 453201******0366
3 / 24

Slide 3: Luhn Algorithm

Validate PAN integrity - catches typos and transmission errors.

PAN: 4 5 3 2 0 1 5 1 1 2 8 3 0 3 6 6

Step 1: From right, double every second digit
        8 5 6 2 0 1 10 1 2 2 16 3 0 3 12 6

Step 2: If result > 9, subtract 9
        8 5 6 2 0 1 1 1 2 2 7 3 0 3 3 6

Step 3: Sum all digits
        8+5+6+2+0+1+1+1+2+2+7+3+0+3+3+6 = 50

Step 4: Check: sum % 10 == 0?
        50 % 10 = 0 ✓ Valid!
4 / 24

Slide 4: Luhn in Go

func ValidateLuhn(pan string) bool {
    if len(pan) == 0 { return false }
    sum := 0
    double := false

    // Process right-to-left
    for i := len(pan) - 1; i >= 0; i-- {
        digit := int(pan[i] - '0')
        if digit < 0 || digit > 9 {
            return false
        }

        if double {
            digit *= 2
            if digit > 9 {
                digit -= 9
            }
        }
        sum += digit
        double = !double
    }

    return sum%10 == 0
}
5 / 24

Slide 5: DE3 - Processing Code Structure

DE3: 00 00 00
     ├┤ ├┤ ├┤
     │  │  └─ To Account Type
     │  └─ From Account Type
     └─ Transaction Type

Transaction Type (first 2 digits):
00 = Purchase
01 = Cash Advance
09 = Purchase with Cash Back
20 = Refund
30 = Balance Inquiry

Account Type (digits 3-6):
00 = Default
10 = Savings
20 = Checking
30 = Credit

Example: 010020 = Cash Advance from Default account to Checking (01|00|20)

6 / 24

Slide 6: DE4 - Amount Field

Field: DE4 (Transaction Amount)
Type:  Fixed n 12
Value: "000000010000"  = ???

The answer depends on currency!

Currency Exponents (DE49):

Currency Code Exponent "000000010000" means
USD 840 2 $100.00
EUR 978 2 €100.00
JPY 392 0 ¥10000
KWD 414 3 10.000 KWD

Always pair DE4 with DE49!

7 / 24

Slide 7: The Three Amount Fields

Cross-border transaction: US cardholder in Japan

╔═══════════════════════════════════════════════════════╗
║  Merchant (Tokyo)    Acquirer       Cardholder (US)   ║
║     ¥5000              $33.00          $33.00         ║
╚═══════════════════════════════════════════════════════╝
     ↓                    ↓               ↓
   DE4                  DE5             DE6
   "000000005000"       "000000003300"  "000000003300"
   DE49="392"           DE50="840"      DE51="840"
   (JPY)                (USD)           (USD)
  • DE4: Transaction currency (what merchant charged)
  • DE5: Settlement currency (acquirer receives)
  • DE6: Billing currency (cardholder sees)
8 / 24

Slide 8: Date/Time Fields - The Timezone Trap

DE7:  Transmission Date/Time - n 10 (MMDDhhmmss) - UTC
DE12: Local Time - n 6 (hhmmss) - Terminal timezone
DE13: Local Date - n 4 (MMDD) - Terminal timezone

Example: Transaction in New York at 2:30 PM EST
DE7  = "0315193045"  (UTC: 19:30:45)
DE12 = "143045"      (Local: 14:30:45)
DE13 = "0315"        (Local: March 15)

Critical issues:

  1. No year in any date field!
  2. DE7 is UTC, DE12+DE13 are local
  3. Year boundary bugs at Dec 31 → Jan 1
9 / 24

Slide 9: DE11 (STAN) vs DE37 (RRN)

┌────────────────────────────────────────────────────────┐
│                                                        │
│  DE11 (STAN)              DE37 (RRN)                  │
│  ──────────               ──────────                  │
│  6 digits                 12 alphanumeric             │
│  Terminal-assigned        Network-assigned            │
│  Unique per terminal/day  Unique network-wide         │
│  For message matching     For customer service lookup │
│                                                        │
│  Example: "123456"        Example: "240315123456"     │
│                                                        │
└────────────────────────────────────────────────────────┘

STAN links request↔response RRN appears on receipts and statements

10 / 24

Slide 10: DE35 - Track 2 Data Structure

Track 2: 4532015112830366D2512101DDDDDDDDDDDDD
         ├──────PAN──────┤│├──┤├─┤├──────────┤
                         │ │   │  │
                         │ │   │  └ Discretionary data
                         │ │   └ Service code (3 digits)
                         │ └ Expiry YYMM
                         └ Separator (= or D)

Components:
- PAN:           4532015112830366
- Separator:     D
- Expiry:        2512 (December 2025)
- Service Code:  101
- Discretionary: DDDDDDDDDDDDD

Type: LLVAR z..37 (z = Track 2 code set)

11 / 24

Slide 11: Parse Before Applying Policy

Preserve all three service-code digits and consult the selected acceptance specification. Historical public examples use 101 for a stripe card and 201 for a chip card; the old reversed mapping was incorrect.

DE22 describes entry mode and, in these examples, PIN capability. It does not prove that PIN verification succeeded. Track data remains sensitive authentication data even without a cardholder name.

Slide 12: Parsing Track 2 in Go

type Track2Data struct {
    PAN           string
    ExpiryYYMM    string
    ServiceCode   string
    Discretionary string
}

func ParseTrack2(track2 string) (Track2Data, error) {
    // Find separator (= or D)
    sepIdx := strings.IndexAny(track2, "=D")
    if sepIdx == -1 {
        return Track2Data{}, fmt.Errorf("no separator")
    }

    pan := track2[:sepIdx]
    rest := track2[sepIdx+1:]

    // Expiry (4) + Service code (3) + Discretionary
    return Track2Data{
        PAN:           pan,
        ExpiryYYMM:    rest[0:4],
        ServiceCode:   rest[4:7],
        Discretionary: rest[7:],
    }, nil
}
12 / 24

Slide 13: DE39 - Response Codes

Code  Meaning                 Category
────  ───────                 ────────
00    Approved                ✓ Success
01    Refer to issuer         ⚠ Referral
05    Do not honor            ✗ Decline
12    Invalid transaction     ✗ Decline
14    Invalid card number     ✗ Decline (Luhn fail?)
41    Lost card - pick up     ✗ Decline (retain card)
51    Insufficient funds      ✗ Decline
54    Expired card            ✗ Decline
55    Incorrect PIN           ✗ Decline
91    Issuer unavailable      Apply configured recovery policy
96    System malfunction      Apply configured recovery policy

Teaching profile: 00 is the simple success code here. Other endpoints can define additional outcomes; use the actual codebook and transaction state.

13 / 24

Slide 14: Response Code Categorization

type ResponseCategory string

const (
    Approved    ResponseCategory = "approved"
    Declined    ResponseCategory = "declined"
    Referral    ResponseCategory = "referral"
    SystemError ResponseCategory = "system_error"
    PickUp      ResponseCategory = "pick_up"
)

func Categorize(code string) ResponseCategory {
    switch code {
    case "00":
        return Approved
    case "01", "02":
        return Referral
    case "41", "43":
        return PickUp
    case "91", "96":
        return SystemError
    default:
        return Declined
    }
}
14 / 24

Slide 15: DE54 - Additional Amounts

For balance inquiries and complex transactions:

DE54: "0001840C000000150000"
      ├┤├┤├──┤│├────────────┤
      00 01 840 C  000000150000

Structure (20 bytes per record):
- Bytes 1-2:  Account type (00 = default)
- Bytes 3-4:  Amount type (01 = ledger balance)
- Bytes 5-7:  Currency (840 = USD)
- Byte 8:     Sign (C = credit, D = debit)
- Bytes 9-20: Amount (000000150000 = $1500.00)

Multiple records can be concatenated.

15 / 24

Slide 16: Authorization Request Field Map

0100 Message - Typical Fields
═══════════════════════════════════════════════════════
MTI    "0100"                   Auth request
DE2    "4532015112830366"       PAN (LLVAR)
DE3    "000000"                 Purchase
DE4    "000000010000"           $100.00
DE7    "0315143045"             Mar 15, 14:30:45 UTC
DE11   "123456"                 STAN
DE12   "143045"                 Local time
DE13   "0315"                   Local date
DE14   "2512"                   Card expiry Dec 2025
DE22   "051"                    Chip read
DE35   "4532...D2512101..."     Track 2
DE37   "240315123456"           RRN
DE41   "TERM0001"               Terminal ID
DE42   "MERCH00001"             Merchant ID
DE49   "840"                    USD
═══════════════════════════════════════════════════════
16 / 24

Slide 17: Common Pitfalls

1. PAN Length
   ✗ if len(pan) != 16  // Amex is 15!
   ✓ if len(pan) < 13 || len(pan) > 19

2. Amount Without Currency
   ✗ amount := 10000  // $100 or ¥10000?
   ✓ type Money struct { Amount int64; Currency string }

3. Track 2 Separator
   ✗ strings.Index(track2, "=")   // Misses 'D'
   ✓ strings.IndexAny(track2, "=D")

4. Response Code as Number
   ✗ if code == 0    // String "00" vs int 0
   ✓ if code == "00"

5. Year in Dates
   ✗ year := time.Now().Year()  // December edge case!
   ✓ Handle Dec→Jan transition explicitly
17 / 24

Slide 18: Field Dependencies

┌─────────────────────────────────────────────────────┐
│  POS Entry Mode (DE22) determines required fields   │
│                                                     │
│  DE22 = "051" (Chip)                               │
│    → DE55 (EMV data) REQUIRED                      │
│    → DE35 (Track 2) OPTIONAL                       │
│                                                     │
│  DE22 = "021" (Magnetic Stripe)                    │
│    → DE35 (Track 2) REQUIRED                       │
│    → DE55 ABSENT                                   │
│                                                     │
│  DE22 = "010" (Manual/Keyed)                       │
│    → DE2, DE14 from keyboard                       │
│    → No DE35, no DE55                              │
└─────────────────────────────────────────────────────┘
18 / 24

Slide 19: Quick Reference Card

┌──────────────────────────────────────────────────────┐
│  FIELD  │ TYPE        │ KEY POINTS                  │
├─────────┼─────────────┼─────────────────────────────┤
│  DE2    │ LLVAR n..19 │ Luhn, mask in logs          │
│  DE3    │ Fixed n 6   │ TxnType+FromAcct+ToAcct     │
│  DE4    │ Fixed n 12  │ Pair with DE49 for decimals │
│  DE7    │ Fixed n 10  │ MMDDhhmmss UTC, no year     │
│  DE11   │ Fixed n 6   │ STAN, unique per term/day   │
│  DE12   │ Fixed n 6   │ hhmmss local time           │
│  DE13   │ Fixed n 4   │ MMDD local date             │
│  DE35   │ LLVAR z..37 │ PAN=YYMMSSC+disc            │
│  DE37   │ Fixed an 12 │ RRN, on receipts            │
│  DE39   │ Fixed an 2  │ "00"=approved               │
│  DE49   │ Fixed n 3   │ ISO 4217 currency           │
│  DE54   │ LLLVAR      │ 20-byte balance records     │
└──────────────────────────────────────────────────────┘
19 / 24

Slide 20: Key Takeaways

  1. PAN is not a number - Keep as string, validate with Luhn

  2. Amounts need currency - DE4 is meaningless without DE49

  3. Dates have no year - Handle Dec 31 → Jan 1 carefully

  4. Track 2 is structured - PAN + Separator + Expiry + ServiceCode + Data

  5. Response "00" is special - Only code that means approved

  6. STAN vs RRN - STAN for matching, RRN for reference

  7. DE22 drives validation - Entry mode determines required fields

When debugging: Read fields like a story - who, what, how much, when, and what happened.

20 / 24

Slide 21: Integrity Rules for Field Pairs

IF DE2 + DE35 present -> full normalized PANs must match under the chosen tokenization rules
IF DE4 present -> DE49 required for exact value
IF DE22 starts with 0 -> manual mode -> expect terminal-entered DE2/DE14
IF DE22 = 051 -> EMV data (DE55) should be present
IF DE22 = 021 -> Track2 (DE35) should be present
IF DE39 != "00" -> do not map directly to customer messaging

Goal: Parse correctness + semantic correctness = protocol correctness.

21 / 24

Slide 22: Progressive Validation Ladder

  1. Field syntax stage

    • LLVAR length prefix validation
    • fixed-length shape checks
  2. Dependency stage

    • Required-field matrix by DE22/MTI
    • STAN/Date correlation
  3. Coherence stage

    • Cross-field consistency (PAN duplicates, timestamp alignment)
    • Currency-aware amount interpretation
  4. Action stage

    • Response decision
    • Error typing (FIELD_INVALID, DEPENDENCY_MISSING, SEMANTIC_MISMATCH)

This ordering prevents one bad field from corrupting every downstream decision.

22 / 24

Quick Reference Card

High-value checks:
- PAN as string, never numeric
- DE4 + DE49 for value
- DE22 dictates DE35/DE55 expectations
- DE11/DE12/DE13 correlation key
- DE54 length must be multiple of 20 bytes
23 / 24

Profile and time checks

Ledger amount type is 01; available balance is 02 in this teaching codebook. A DE54 record occupies exactly 20 characters; reject trailing partial records and invalid amounts.

DE7 has no year in this profile. Validate date components and choose a year only within a configured receipt window. Timezone and correlation keys come from the endpoint agreement. Display masking does not protect a separately stored raw PAN.

24 / 24
←/→ or click edges to navigate · ? help · N notes · F fullscreen