I’ve spent a good part of my career dealing with EMV transactions. When I first got into this space, I thought EMV was just about encrypting card data and making sure the chip was harder to copy than a magnetic stripe. But the more I worked with terminals, kernels, and card profiles, the more I realized that EMV is full of decision points. It’s not just “tap card, approve, done.” The terminal and the card are constantly negotiating, and sometimes it feels like they’re having a secret conversation in the background.
Two areas where this really comes to life are processing restrictions and terminal action analysis. If you’re new to EMV, those might sound like textbook terms. But in practice, they’re the rules and the decision flow that determine if a transaction is allowed, declined, or passed to the issuer online.
In this post, I’ll share how I learned to understand these pieces step by step. We’ll walk through what processing restrictions are, what the terminal action analysis does, and how all this connects to the final decision you see as a cardholder or as a developer building payments software.
Processing Restrictions: What Are They and Why Do They Matter?
When the terminal reads data from the card, it doesn’t just jump into authorizing a payment. It first checks if the card is even valid for this type of transaction. Think of it as basic gatekeeping.
Some examples I’ve encountered in real projects:
- The card might say “domestic use only”. If you try to use it abroad, the terminal should stop you.
- A card may be expired, but if your logic doesn’t check for it properly, you might allow a transaction that should have failed at the start.
- Some cards only allow contactless up to a certain limit. If the amount is higher, the processing restrictions will trigger a fallback to chip-and-PIN.
These checks are mostly based on EMV data elements that come from the card. A few important tags:
- 5F24 (Application Expiration Date)
- 5F25 (Application Effective Date)
- 9F07 (Application Usage Control)
- 9F08 (Application Version Number)
When I worked on one project integrating with a kernel, we had a recurring issue where transactions kept failing for foreign-issued cards. After digging into logs, we realized the kernel was rejecting them because of Application Usage Control (9F07). It basically said the card wasn’t valid for international cash transactions. At first, it felt like black magic, but once I mapped the tags to the rules, it made perfect sense.
Here’s a simplified way of thinking about processing restrictions in code (not production-ready, just to illustrate):
bool CheckProcessingRestrictions(CardData card, Transaction txn)
{
if (DateTime.Now > card.ExpirationDate)
return false; // Card expired
if (DateTime.Now < card.EffectiveDate)
return false; // Card not yet valid
if (txn.Type == TransactionType.CashWithdrawal && !card.UsageControl.AllowsCash)
return false; // Not allowed
if (txn.IsInternational && !card.UsageControl.AllowsInternational)
return false; // Card restricted
return true; // Pass processing restrictions
}
In real EMV kernels, these are not hardcoded like this, but the idea is the same. It’s rule checking based on card and terminal data.
Terminal Action Analysis: Who Decides What Happens Next
Once the card passes processing restrictions, the next step is what EMV calls Terminal Action Analysis. This is where the terminal decides what action to take with the transaction. Should it approve offline, decline offline, or send it online to the issuer?
- Decline offline (no need to ask issuer, the rules are clear)
- Approve offline (issuer is not needed, terminal is confident)
- Go online (let issuer decide)
The terminal decides using a mix of three main inputs:
- Terminal Action Codes (TACs): These are like the terminal’s preferences or rules. The acquirer sets them based on risk appetite.
- Issuer Action Codes (IACs): These come from the card, representing what the issuer wants.
- Card and transaction conditions: Things like “amount exceeds floor limit”, “cardholder verification failed”, or “transaction is not allowed offline”.
In one of my past projects, we spent hours debugging why some low-value contactless transactions were still going online when they should have been approved offline. The culprit? The TACs were not aligned with the issuer’s IACs. Our terminal was configured to send everything online “just to be safe”, but that annoyed merchants who expected faster approvals.
Here’s a conceptual pseudo-code for Terminal Action Analysis:
Decision DoTerminalActionAnalysis(TAC tac, IAC iac, Transaction txn)
{
if (txn.Amount > tac.FloorLimit)
return Decision.GoOnline;
if (txn.CVMFailed && tac.DeclineIfCVMFails)
return Decision.DeclineOffline;
if (!txn.ProcessingRestrictionsPassed)
return Decision.DeclineOffline;
// Combine terminal and issuer rules
if (iac.ForceOnline || tac.ForceOnline)
return Decision.GoOnline;
return Decision.ApproveOffline; // Default if no issues
}
Of course, actual kernels do this with bitwise operations on TAC/IAC fields, not simple booleans like above. But this way it’s easier to visualize.
How They Work Together in the Transaction Flow
Let’s connect the dots.
- Card is read. Terminal fetches application data (AIDs, AFL, tags).
- Processing restrictions. Quick validation: is the card valid, allowed, and supported here?
- Cardholder verification. PIN, signature, or contactless no-CVM.
- Risk management checks. Is the amount over the floor limit? Is it random-selected for online authorization?
- Terminal action analysis. Terminal compares TACs and IACs, then picks the decision bucket.
- Final decision
- If declined offline: transaction ends.
- If approved offline: terminal completes it locally.
- If online: authorization request goes to issuer.
What surprised me early in my career was that the card isn’t just a dumb storage device. It actively participates in these decisions. Sometimes the card pushes back, and you see “Card forces online” in the logs. That means even if the terminal wanted to approve offline, the issuer (through the card) wanted to check the transaction.
Why This Matters in Real Projects
If you’re a developer working on payment systems, knowing these flows will save you headaches. I’ve seen teams spend weeks trying to fix “random declines” that turned out to be processing restrictions doing their job correctly.
For example, one merchant kept complaining their terminal was rejecting certain corporate cards. After reviewing the EMV logs, we saw that the IAC told the terminal “Decline if used for cash advance”. The merchant was a service provider that had MCC coded as quasi-cash. The terminal was actually behaving exactly as configured, but the business side thought it was a bug.
So when you build or debug payment apps, always check:
- Did processing restrictions pass?
- What were the TAC and IAC values?
- Which path did the terminal action analysis follow?
Having that understanding makes you more confident when explaining to stakeholders why a transaction was declined or sent online.
Wrapping Up
Processing restrictions and terminal action analysis are not just boring EMV textbook terms. They are the heart of decision-making in every chip transaction.
When I think back to my early days in EMV, I used to treat the terminal like a black box. Card goes in, result comes out. But the more I dug into logs, tags, and kernel code, the more I saw the logic behind those decisions.
If you’re building payment software, don’t ignore these parts. Learn the flow, understand the tags, and you’ll save yourself (and your clients) a lot of frustration.
Sources & References
- EMVCo. EMV Integrated Circuit Card Specifications for Payment Systems (Books 1–4).
- Visa. EMV Chip Transaction Flow (developer guides).