~learn.

FASTag Electronic Tolling, the whole design.

India's electronic toll network (~120 lakh crossings a day through 40 issuer and 12 acquirer banks) works because the lane decides with what it already holds, signed tags and a local list of bad tags, while one transaction number per crossing and written liability windows let the banks settle correctly afterwards, even when a plaza was offline for hours.

6 diagrams · 8 sections · revise in ~10 min · Download PDF prints it in the light theme, diagrams included

SQ-35 · FASTag Electronic Tolling · design sheethimanshukukreja.in/learn/sheets/bonus-35-fastag-electronic-tolling

At a glance#

Number Value What it drives
ETC crossings, NH plazas ~120 lakh a day · ~139 / s average the switch is small; the edges are hard
Collection via FASTag ~₹184 crore a day · ~₹153 a crossing settlement netting, not throughput
Tags · issuers · acquirers 11.73 crore · 40 · 12 one shared registry, the Mapper
Fee plazas ~1,150 list fan-out; offline sites
Online · late window 15 min · 3 days who carries balance risk when late
Exception list refresh diff every 10 min · full daily staleness at the lane
Issuer grace · decline rule 20 min · 60 min before read (code 176) who pays for a stale list
Settlement 3 cycles a day, RTGS · plaza paid T+1 scheduled netting job

Architecture#

DiagramLanes decide locally; banks settle centrally
%% title: Lanes decide locally; banks settle centrally
flowchart TD
  V@{ icon: "sd:truck", label: "Vehicle with FASTag<br/>signed TID · EPC" }
  RDR@{ icon: "sd:scan", label: "RFID reader<br/>dozens of reads" }
  LC["Lane controller<br/>passage · signature · local list"]:::hot
  PS@{ icon: "sd:server", label: "Plaza server<br/>outbox · store and forward" }
  ACQ["Acquirer host<br/>fare from Mapper class"]:::core
  MAP@{ icon: "sd:database", label: "NETC Mapper<br/>tags · class · exception lists" }
  SW["NETC Switch<br/>acquirer to issuer"]:::core
  ISS["Issuer host<br/>debit · low balance · hotlist"]:::core
  NRCS@{ icon: "sd:bank", label: "NRCS<br/>3 cycles · net · disputes" }
  USR@{ icon: "sd:phone", label: "Tag holder<br/>SMS · UPI top-up" }
  V ==> RDR ==> LC
  LC ==> PS ==> ACQ
  ACQ -->|"request details"| MAP
  ACQ ==>|"request pay"| SW
  MAP -.->|"diff every 10 min"| PS
  SW ==> ISS
  SW --> NRCS
  ISS -.->|"status changes"| MAP
  ISS --> USR
  class V client
  class RDR edge
  class PS service
  class MAP store
  class NRCS store
  class USR client
DiagramThe lane's decision in about a second
%% title: The lane's decision in about a second
flowchart TD
  READ@{ icon: "sd:scan", label: "Passage formed<br/>one txn number" }
  FMT{"Known issuer ID?"}
  LIST@{ icon: "sd:file", label: "Local exception list<br/>INIT + diffs" }
  SIG["Verify issuer signature<br/>over TID + EPC"]:::core
  ONL{"Request details<br/>answers in budget?"}
  PASS["Store crossing, then<br/>lift barrier"]:::core
  OTHER["Other payment mode"]:::bad
  READ ==> FMT
  FMT ==>|"yes"| LIST
  FMT -->|"no"| OTHER
  LIST ==>|"clean"| SIG
  LIST -->|"blocked"| OTHER
  SIG ==>|"valid"| ONL
  SIG -->|"invalid"| OTHER
  ONL ==>|"active or no answer"| PASS
  ONL -->|"blocked"| OTHER
  class READ edge
  class LIST cache

Key flows#

DiagramAn online crossing, read to SMS
%% title: An online crossing, read to SMS
sequenceDiagram
  autonumber
  participant L as Lane
  participant A as Acquirer
  participant M as Mapper
  participant S as Switch
  participant I as Issuer
  L->>L: 31 reads · one passage · txn number
  L->>A: request details for tag T
  A->>M: get tag details
  M-->>A: class · active · issuer
  A-->>L: OK · barrier lifts
  A->>S: request pay · same txn number
  S->>I: debit request
  I-->>S: debited · SMS sent
  S-->>A: response pay OK
  I->>M: add T to low balance
DiagramLate and failed paths, each with a written rule
%% title: Late and failed paths, each with a written rule
sequenceDiagram
  autonumber
  participant P as Plaza
  participant A as Acquirer
  participant S as Switch
  participant I as Issuer
  Note over P: link down · crossings wait in the outbox
  P->>A: crossings, oldest first, on reconnect
  A->>A: drop duplicates · plaza, txn number, read time
  A->>S: request pay
  alt within 15 min
    S->>I: debit · normal liability
  else 15 min to 3 days
    S->>I: debit · issuer may charge back if balance short
  else over 3 days
    S-->>A: declined
  end
  alt issuer unreachable
    S->>I: debit advice until ACK or cut-off
    S-->>A: deemed accepted
  else no final answer at acquirer
    Note over A: wait 60 to 180 s · check transaction before any resend
  end

Data model#

DiagramCore entities across NPCI and the banks
%% title: Core entities across NPCI and the banks
classDiagram
  class Tag {
    +epc : 96 bits · issuer ID, key index, vehicle ID
    +tid : chip ID from manufacturer
    +signature : issuer key over TID + EPC
    +vrn : string · validated on VAHAN
    +vehicleClass : string · overrides AVC for fare
    +status : active, low balance, hotlist, blacklist, closed
  }
  class Issuer {
    +issuerId : 20 bits
    +keys : up to 256 · certified by NPCI
  }
  class Plaza {
    +plazaId : string
    +acquirer : one bank at a time
    +listVersion : last diff applied
  }
  class Crossing {
    +txnNumber : minted in the lane
    +readerTime : time
    +fare : rupees · from Mapper class
    +state : stored, presented, settled, declined
  }
  class SettlementWindow {
    +cycle : one of three a day
    +netByBank : one amount per bank · sums to zero
  }
  class Dispute {
    +type : adjustment, chargeback, arbitration
    +deadline : days
  }
  Issuer "1" --> "many" Tag : issues
  Tag "1" --> "many" Crossing : charged by
  Plaza "1" --> "many" Crossing : records
  Crossing "many" --> "1" SettlementWindow : netted in
  Crossing "1" --> "0..1" Dispute : contested by

Lifecycle#

DiagramA crossing, from read to settlement
%% title: A crossing, from read to settlement
stateDiagram-v2
  [*] --> READ: passage formed
  READ --> STORED: written to lane outbox
  STORED --> PRESENTED_ONTIME: at switch within 15 min
  STORED --> PRESENTED_LATE: 15 min to 3 days
  STORED --> EXPIRED: not presented in 3 days
  PRESENTED_ONTIME --> SETTLED: next NRCS cycle
  PRESENTED_LATE --> SETTLED: next NRCS cycle
  PRESENTED_ONTIME --> DECLINED: code 176
  PRESENTED_LATE --> DECLINED: code 176
  SETTLED --> DISPUTED: chargeback or adjustment
  DISPUTED --> SETTLED: resolved
  SETTLED --> [*]
  DECLINED --> [*]
  EXPIRED --> [*]
  class SETTLED ok
  class EXPIRED bad
  class DECLINED bad
  class PRESENTED_LATE queue

Decisions#

Decision Chose Over Because
Barrier decision Local: signature + local list Real-time issuer check lane can't wait or trust its link
Tag trust Issuer signature over TID + EPC Online lookup only works offline; copies fail on TID
List delivery 10-min diffs + daily full list Full list every few minutes full list large, changes small
Duplicates Txn number minted in the lane Dedupe at the issuer only retries harmless at every hop
Late crossings Accept to 3 days, shift risk Reject after 15 min a fibre cut isn't a revenue loss
Issuer outage Deemed accepted, issuer catches up Decline at the switch vehicle already through
One tag per vehicle Check at the shared Mapper Each issuer checks alone no issuer sees the others

When it breaks#

Failure What users see Contain it with
Plaza link down nothing; SMS hours later lane outbox; 3-day window; outbox-age alerts
Stale list after top-up sent to pay another way online check first; 10-min diffs
Issuer down normal crossing debit advice; deemed accepted; catch up by cut-off
Cloned tag charge at a far plaza 120 km/h near-time rule; chargeback; compensation fund
Tag not read, ETC fault passes free 2018 gazette rule; handheld reader; replace tag
Wrong class in Mapper car fare for a truck debit adjustment; issuer fixes class

Say it in the interview#