OCPP 2.0.1 Edition 4

Transaction Flows - CSMS Developer Guide

Based on OCPP 2.0.1 Edition 4 Specification (Part 2, Section E). This guide covers all transaction flows from the CSMS (Charging Station Management System) perspective.

5 Sections
15 Use Cases
E01 - E15

1. Overview & Core Concepts

Introduction

Transactions in OCPP 2.0.1 represent a portion of a charging session recorded by the CSMS — a single time frame with a start and stop time, used for billing. All transaction state changes are communicated via TransactionEventRequest.

1.1 Transaction Definition

One Transaction per EVSE

At most one transaction can be active on an EVSE at any point in time.

CS-Generated Transaction IDs

Transaction IDs are generated by the Charging Station (not the CSMS). Recommended format: UUIDs. A TransactionId MUST be unique for the lifetime of a Charging Station — it survives reboots and firmware updates.

Billing Unit

Each transaction is the billing unit — the CSMS calculates cost based on meter values provided within transaction events.

CSMS as Passive Receiver

The Charging Station drives transaction lifecycle. The CSMS receives events and responds; it cannot force-start a transaction without using RequestStartTransactionRequest.

1.2 Flexible Transaction Start/Stop

Two configuration variables control exactly when transactions start and stop, enabling different billing models:

Variable Possible Values Description
TxStartPoint ParkingBayOccupancy, EVConnected, Authorized, DataSigned, PowerPathClosed, EnergyTransfer Defines when a transaction starts
TxStopPoint ParkingBayOccupancy, EVConnected, Authorized, PowerPathClosed, EnergyTransfer Defines when a transaction ends

Common billing model configurations:

Billing Model TxStartPoint TxStopPoint
Connection time EVConnected EVConnected
Time of use EVConnected, Authorized EVConnected
Charging time PowerPathClosed PowerPathClosed
OCPP 1.6 compat PowerPathClosed EVConnected, Authorized

1.3 Core Message: TransactionEventRequest

All transaction state changes are communicated via TransactionEventRequest sent from CS to CSMS. The eventType field has three values:

Started

First event of a transaction

Updated

Intermediate events during a transaction

Ended

Last event of a transaction

1.4 Sequence Numbers

The CS maintains a per-EVSE counter (seqNo) for TransactionEventRequest messages. It starts at 0 for the first message of a transaction and increments by 1 for each subsequent message. The CSMS can verify completeness by checking that it received all integer values from start to end.

1.5 Optional Fields Behavior

Some optional fields in TransactionEventRequest are sent only once, not with every message:

Field When Sent
evse (id + connectorId) First TransactionEventRequest after EV connects (not repeated)
idToken Once after authorization is obtained; once when authorization ends
reservationId First TransactionEventRequest after authorization, if reservation exists
transactionInfo.remoteStartId In the next TransactionEventRequest after RequestStartTransactionRequest
transactionInfo.chargingState Whenever charging state changes (always present in eventType=Started)
transactionInfo.stoppedReason In the final eventType=Ended message (may be omitted if Local)
meterValue Based on meter value configuration; context = Transaction.Begin / Transaction.End / Sample.Periodic

2. Message Schemas Reference

Protocol

2.1 TransactionEventRequest (CS → CSMS)

Sent by the Charging Station to report all transaction lifecycle events — start, updates, and end.

Charging Station --> CSMS
TransactionEventRequest
{
  "eventType": "Started" | "Updated" | "Ended",        // Required
  "timestamp": "2024-01-15T10:30:00Z",                  // Required (ISO 8601)
  "triggerReason": "<TriggerReasonEnumType>",            // Required
  "seqNo": 0,                                           // Required (integer)
  "transactionInfo": {                                   // Required
    "transactionId": "string (max 36)",                  // Required
    "chargingState": "Charging" | "EVConnected" | "SuspendedEV" | "SuspendedEVSE" | "Idle",
    "timeSpentCharging": 3600,                           // seconds of actual energy flow
    "stoppedReason": "<ReasonEnumType>",                 // Only for eventType=Ended
    "remoteStartId": 123                                 // Links to RequestStartTransaction
  },
  "offline": false,                                      // default false
  "numberOfPhasesUsed": 3,
  "cableMaxCurrent": 32,                                 // Amperes
  "reservationId": 456,
  "evse": {
    "id": 1,                                             // Required (> 0)
    "connectorId": 1
  },
  "idToken": {
    "idToken": "string (max 36)",                        // Required
    "type": "<IdTokenEnumType>"                          // Required
  },
  "meterValue": [
    {
      "timestamp": "2024-01-15T10:30:00Z",               // Required
      "sampledValue": [
        {
          "value": 1234.5,                               // Required (number)
          "context": "Transaction.Begin" | "Transaction.End" | "Sample.Periodic" | ...,
          "measurand": "Energy.Active.Import.Register",  // default
          "phase": "L1" | "L2" | "L3" | ...,
          "location": "Outlet",                          // default
          "unitOfMeasure": {
            "unit": "Wh",                                // default
            "multiplier": 0                              // default (10^0 = 1)
          }
        }
      ]
    }
  ]
}
TriggerReasonEnumType values
Value Description
Authorized EV Driver authorized
CablePluggedIn Cable plugged in
ChargingRateChanged Charging rate changed
ChargingStateChanged Charging state changed
Deauthorized EV Driver deauthorized
EnergyLimitReached Energy limit reached
EVCommunicationLost Communication with EV lost
EVConnectTimeout EV connection timeout
EVDetected EV detected (parking bay)
EVDeparted EV departed (parking bay)
MeterValueClock Clock-aligned meter value
MeterValuePeriodic Periodic meter value
TimeLimitReached Time limit reached
Trigger Triggered by TriggerMessageRequest
UnlockCommand Unlock command received
StopAuthorized Stop authorization received
RemoteStop Remote stop received
RemoteStart Remote start received
AbnormalCondition Abnormal error or fault
SignedDataReceived Signed meter data received
ResetCommand Reset command received
ReasonEnumType (stoppedReason) values
DeAuthorizedEmergencyStopEnergyLimitReachedEVDisconnectedGroundFaultImmediateResetLocalLocalOutOfCreditMasterPassOtherOvercurrentFaultPowerLossPowerQualityRebootRemoteSOCLimitReachedStoppedByEVTimeLimitReachedTimeout
ChargingStateEnumType values
Value Description
Charging Energy is flowing to the EV
EVConnected EV is connected but not charging
SuspendedEV Charging suspended by the EV
SuspendedEVSE Charging suspended by the EVSE
Idle No EV connected
IdTokenEnumType values
CentraleMAIDISO14443ISO15693KeyCodeLocalMacAddressNoAuthorization

2.2 TransactionEventResponse (CSMS → CS)

The CSMS responds to acknowledge the transaction event. Must always be sent — even an empty response is valid.

CSMS --> Charging Station
TransactionEventResponse
{
  "totalCost": 12.50,                     // Only when eventType=Ended; omit = not free; 0.00 = free
  "chargingPriority": 0,                  // -9 to 9 (overrides IdTokenInfo priority temporarily)
  "idTokenInfo": {                         // Include when idToken was in request
    "status": "<AuthorizationStatusEnumType>",  // Required
    "cacheExpiryDateTime": "2024-02-01T00:00:00Z",
    "chargingPriority": 0,
    "language1": "en",
    "language2": "nl",
    "evseId": [1, 2],                     // Restrict token to specific EVSEs
    "groupIdToken": {
      "idToken": "group-token-123",
      "type": "Central"
    },
    "personalMessage": {
      "format": "UTF8",
      "content": "Welcome, John!"
    }
  },
  "updatedPersonalMessage": {
    "format": "UTF8",
    "content": "Updated message during transaction"
  }
}

CSMS implementation logic:

  1. Always acknowledge receipt — an empty {} is valid
  2. If idToken is present in the request: validate the token and return idTokenInfo
  3. On eventType=Ended: optionally include totalCost (omit = not free, 0.00 = free)
  4. If token has a groupIdToken: include it in the response
AuthorizationStatus Description
Accepted Token is valid, charging allowed
Blocked Token is blocked
ConcurrentTx Token already in use in another transaction
Expired Token has expired
Invalid Token is unknown/invalid
NoCredit Token has no credit
NotAllowedTypeEVSE Token not allowed on this EVSE type
NotAtThisLocation Token not valid at this location
NotAtThisTime Token not valid at this time
Unknown Token is unknown

2.3 RequestStartTransactionRequest (CSMS → CS)

The CSMS can remotely initiate a charging session on a specific EVSE.

CSMS --> Charging Station
RequestStartTransactionRequest
{
  "remoteStartId": 123,                   // Required (integer)
  "idToken": {                             // Required
    "idToken": "string (max 36)",
    "type": "<IdTokenEnumType>"
  },
  "evseId": 1,                            // Optional (> 0)
  "groupIdToken": {                        // Optional
    "idToken": "group-123",
    "type": "Central"
  },
  "chargingProfile": {                     // Optional (purpose MUST be TxProfile)
    "id": 1,
    "stackLevel": 0,
    "chargingProfilePurpose": "TxProfile",
    "chargingProfileKind": "Relative",
    "chargingSchedule": [ "..." ]
  }
}

2.4 RequestStartTransactionResponse (CS → CSMS)

Charging Station --> CSMS
RequestStartTransactionResponse
{
  "status": "Accepted" | "Rejected",       // Required
  "transactionId": "existing-tx-id-123",   // Optional: if transaction already started (e.g. cable first)
  "statusInfo": {
    "reasonCode": "string (max 20)",
    "additionalInfo": "string (max 512)"
  }
}

2.5 RequestStopTransactionRequest (CSMS → CS)

The CSMS can remotely stop an ongoing transaction by its transaction ID.

CSMS --> Charging Station
RequestStopTransactionRequest
{
  "transactionId": "string (max 36)"       // Required
}

2.6 RequestStopTransactionResponse (CS → CSMS)

Charging Station --> CSMS
RequestStopTransactionResponse
{
  "status": "Accepted" | "Rejected",       // Required
  "statusInfo": {
    "reasonCode": "string (max 20)",
    "additionalInfo": "string (max 512)"
  }
}

2.7 GetTransactionStatusRequest (CSMS → CS)

Allows the CSMS to query whether a specific transaction is still ongoing and whether there are pending messages. Omit transactionId to check for ANY pending transaction messages.

CSMS --> Charging Station
GetTransactionStatusRequest
{
  "transactionId": "string (max 36)"       // Optional: omit to check for any pending messages
}

2.8 GetTransactionStatusResponse (CS → CSMS)

Charging Station --> CSMS
GetTransactionStatusResponse
{
  "messagesInQueue": true,                 // Required: CS has pending transaction messages
  "ongoingIndicator": true                 // Optional: transaction is still active
}
Field Value Meaning
messagesInQueue = true CS still has messages to deliver — wait for them before finalizing billing
messagesInQueue = false All messages delivered — safe to finalize billing
ongoingIndicator = true Transaction is still active on the CS
ongoingIndicator = false Transaction has ended on the CS

3. Transaction Flows

Use Cases E01-E15
E01

Start Transaction Options

Understand the different moments a Charging Station can start a transaction based on its TxStartPoint configuration.

Start Triggers by TxStartPoint:

TxStartPoint Config Trigger triggerReason Notes
ParkingBayOccupancy Parking bay detector triggers EVDetected Driver may not be known yet
EVConnected Cable plugged in / EV connection established CablePluggedIn Driver may not be known yet
Authorized EV Driver authorized Authorized idToken always present
DataSigned Signed meter value retrieved SignedDataReceived Requires meter with signing capability
PowerPathClosed All preconditions met (authorized + connected) Authorized or CablePluggedIn Energy may not flow yet
EnergyTransfer Energy flow starts ChargingStateChanged chargingState = Charging

CSMS Implementation Steps:

  1. Store the transaction — Create a new transaction record using transactionInfo.transactionId. Record the timestamp, evse.id, evse.connectorId, and seqNo.
  2. Validate the IdToken (if present) — Look up the idToken in your authorization system.
  3. Respond with TransactionEventResponse containing idTokenInfo with status and groupIdToken if one exists.
  4. Track sequence numbers — Store seqNo to verify all messages are received.

Key Requirements:

ID Requirement
E01.FR.11 CSMS MUST verify the validity of the identifier
E01.FR.12 Response SHALL include idTokenInfo with authorization status and groupIdToken if one exists
Minimal response (acknowledge receipt)
{}
Response with authorization
{
  "idTokenInfo": {
    "status": "Accepted",
    "groupIdToken": {
      "idToken": "group-abc",
      "type": "Central"
    }
  }
}
E02

Start Transaction: Cable Plugin First

Handle the flow where the EV Driver plugs in the cable before authenticating.

Flow sequence (CS → CSMS perspective)
CS -> CSMS: StatusNotificationRequest (connectorStatus = Occupied)
CSMS -> CS: StatusNotificationResponse

CS -> CSMS: TransactionEventRequest(eventType=Started, triggerReason=CablePluggedIn,
            chargingState=EVConnected, transactionId=AB1234, evse.id=1,
            evse.connectorId=1, meterValues, seqNo=0)
CSMS -> CS: TransactionEventResponse()
     ... EV Driver authenticates ...
CS -> CSMS: TransactionEventRequest(eventType=Updated, triggerReason=Authorized,
            transactionId=AB1234, idToken={...}, seqNo=1)
CSMS -> CS: TransactionEventResponse(idTokenInfo={status: Accepted})
     ... Energy starts flowing ...
CS -> CSMS: TransactionEventRequest(eventType=Updated, triggerReason=ChargingStateChanged,
            chargingState=Charging, transactionId=AB1234, seqNo=2, meterValues)
CSMS -> CS: TransactionEventResponse()

CSMS Implementation Steps:

  1. On StatusNotificationRequest — Update connector status to Occupied. Respond with empty StatusNotificationResponse.
  2. On first TransactionEventRequest (Started) — Create transaction record. Note: idToken is NOT present yet. Store chargingState = EVConnected and meter values with context = Transaction.Begin.
  3. On Updated (triggerReason=Authorized) — Validate the idToken against your authorization system. Check for reservations if reservationId is present. Respond with idTokenInfo.
  4. On Updated (chargingState=Charging) — Update transaction state and store periodic meter values.

Key Requirements:

ID Requirement
E02.FR.02 CSMS SHALL send TransactionEventResponse with authorization status value
E02.FR.04 CSMS SHALL verify validity of identifier (might be authorized locally with outdated info)
E03

Start Transaction: IdToken First

Handle the flow where the EV Driver authenticates before plugging in the cable.

Flow sequence (CS → CSMS perspective)
     ... EV Driver authenticates first (via AuthorizeRequest or locally) ...
CS -> CSMS: TransactionEventRequest(eventType=Started, triggerReason=Authorized,
            transactionId=AB1234, idToken.id=1234, seqNo=N)
CSMS -> CS: TransactionEventResponse(idTokenInfo={status: Accepted})
     ... EV Driver plugs in cable ...
CS -> CSMS: StatusNotificationRequest(status=Occupied)
CSMS -> CS: StatusNotificationResponse()
CS -> CSMS: TransactionEventRequest(eventType=Updated, triggerReason=CablePluggedIn,
            chargingState=EVConnected, transactionId=AB1234, seqNo=N+1)
CSMS -> CS: TransactionEventResponse()
     ... Energy starts flowing ...
CS -> CSMS: TransactionEventRequest(eventType=Updated, triggerReason=ChargingStateChanged,
            chargingState=Charging, transactionId=AB1234, seqNo=N+2, meterValues)
CSMS -> CS: TransactionEventResponse()

CSMS Implementation Steps:

  1. On Started (triggerReason=Authorized)idToken IS present in this first message. Validate the token, respond with idTokenInfo. If reservationId is present, link the transaction to the reservation.
  2. On Updated (triggerReason=CablePluggedIn) — First time evse.id and evse.connectorId appear. Update transaction with EVSE assignment.
  3. Handle EVConnectionTimeout — If the driver does not plug in within EVConnectionTimeOut, the CS may send TransactionEventRequest(eventType=Ended, triggerReason=EVConnectTimeout, stoppedReason=Timeout). CSMS should close the transaction.

Key Requirements:

ID Requirement
E03.FR.01 TransactionEventRequest SHALL contain IdTokenType info
E03.FR.02 CSMS SHALL respond with TransactionEventResponse including authorization status
E03.FR.03 If transaction ends a reservation, TransactionEventRequest SHALL contain reservationId
E03.FR.05 If EV not plugged in before EVConnectionTimeOut AND TxStopPoint doesn't contain ParkingBayOccupancy, CS SHOULD end the transaction
E04

Transaction Started While Charging Station is Offline

Handle transactions that were started while the Charging Station had no connection to the CSMS.

Flow sequence after connection restored
     ... CS is offline, starts transaction using local auth ...
     ... Connection restored ...
CS -> CSMS: HeartbeatRequest()
CSMS -> CS: HeartbeatResponse()
CS -> CSMS: TransactionEventRequest(eventType=Started, offline=true,
            transactionId=XY5678, seqNo=0, ...)
CSMS -> CS: TransactionEventResponse(...)
CS -> CSMS: TransactionEventRequest(eventType=Updated, offline=true,
            transactionId=XY5678, seqNo=1, ...)
CSMS -> CS: TransactionEventResponse(...)
     ... more queued messages ...

CSMS Implementation Steps:

  1. Accept all queued messages — When offline = true, the CSMS receives messages that may be hours or days old. Process them chronologically.
  2. Validate tokens retroactively — The CS authorized locally. The CSMS should still validate the token and include idTokenInfo in responses to update the CS authorization cache.
  3. Handle out-of-order delivery — Messages may arrive in a different order. Use seqNo and timestamp to reconstruct the correct sequence.
  4. Always respond — The CSMS MUST always respond to TransactionEventRequest, even for offline transactions. Not responding causes the CS to retry (see E13).

Key Requirements:

ID Requirement
E04.FR.01 CS MUST queue TransactionEventRequest when offline
E04.FR.02 CS MUST send queued messages after connection restored
E04.FR.03 offline flag SHALL be TRUE for any message that occurred while offline
E05

Start Transaction: Id Not Accepted

Handle transactions where the CSMS rejects the IdToken that was authorized locally by the Charging Station.

Flow sequence
CS -> CSMS: TransactionEventRequest(eventType=Started, transactionId=AB1234,
            evse.id=1, evse.connectorId=1, seqNo=N, meterValues)
CSMS -> CS: TransactionEventResponse(idTokenInfo={status: Blocked|Invalid|Expired|Unknown})
     ... CS stops energy based on StopTxOnInvalidId / MaxEnergyOnInvalidId config ...

CSMS Implementation Steps:

  1. Validate the IdToken (CRITICAL) — The identifier might have been authorized locally using outdated information. The CSMS MUST verify validity (E05.FR.01).
  2. Respond with non-Accepted status when the token is invalid.
  3. What happens next depends on CS configuration (not CSMS controlled):
CS Config CS Behavior What CSMS Receives
StopTxOnInvalidId = false Suspends energy, keeps transaction TransactionEventRequest(Updated, ChargingStateChanged, SuspendedEVSE)
StopTxOnInvalidId = false + MaxEnergyOnInvalidId set Allows limited energy Nothing until limit reached
StopTxOnInvalidId = true, TxStopPoint has Authorized/PowerPathClosed/EnergyTransfer Ends transaction TransactionEventRequest(Ended, Deauthorized, stoppedReason=DeAuthorized)
StopTxOnInvalidId = true, TxStopPoint = EVConnected Deauthorizes but keeps tx TransactionEventRequest(Updated, Deauthorized, chargingState=EVConnected)
Example response for invalid token
{
  "idTokenInfo": {
    "status": "Blocked"  // or Invalid, Expired, Unknown, etc.
  }
}
E06

Stop Transaction Options

Understand the different moments a Charging Station can stop a transaction based on its TxStopPoint configuration.

TxStopPoint Config Trigger triggerReason in Ended stoppedReason
ParkingBayOccupancy EV departs parking bay EVDeparted Local
EVConnected Cable unplugged / EV disconnected EVCommunicationLost EVDisconnected
Authorized Driver presents token to stop / CSMS revokes auth StopAuthorized or Deauthorized Local or DeAuthorized
PowerPathClosed EV disconnected or auth revoked varies varies
EnergyTransfer Energy transfer stops ChargingStateChanged varies

CSMS Implementation Steps:

  1. Close the transaction — Mark it as completed with the timestamp from the Ended message.
  2. Store final meter values — The meterValue array with context = Transaction.End contains final readings for billing.
  3. Calculate and return cost (optional) — Return totalCost in the response. Omit = not free; 0.00 = free.
  4. Record stoppedReason — Important for billing disputes and analytics.
  5. Validate idToken (if present) — The stopping token may differ from the starting token (same GroupId). Still respond with idTokenInfo.

Key Requirements:

ID Requirement
E06.FR.08 stoppedReason SHALL be included if not ended by EV Driver
E06.FR.09 stoppedReason MAY be omitted if ended by EV Driver (CSMS interprets as Local)
E06.FR.11 Ended message SHALL include meter values with context = Transaction.End
E06.FR.16 If stopped by abnormal condition, triggerReason = AbnormalCondition
E07

Transaction Locally Stopped by IdToken

Handle the flow where an EV Driver presents their IdToken to stop an ongoing transaction.

Variant A: StopAuthorized reported immediately with End
CS -> CSMS: TransactionEventRequest(
  eventType=Ended,
  triggerReason=StopAuthorized,
  stoppedReason=Local,
  idToken.id=1234,
  transactionId=AB1234,
  chargingState=EVConnected,
  seqNo=N+1,
  meterValues
)
CSMS -> CS: TransactionEventResponse(idTokenInfo={status: ...})
Variant B: StopAuthorized as Update first, then End
CS -> CSMS: TransactionEventRequest(
  eventType=Updated,
  triggerReason=StopAuthorized,
  idToken.id=1234,
  transactionId=AB1234,
  seqNo=N+1
)
CSMS -> CS: TransactionEventResponse(idTokenInfo={status: ...})
     ... CS stops energy, unlocks cable ...
CS -> CSMS: TransactionEventRequest(
  eventType=Ended,
  triggerReason=ChargingStateChanged,
  chargingState=EVConnected,
  stoppedReason=Local,
  seqNo=N+2,
  meterValues
)
CSMS -> CS: TransactionEventResponse(totalCost=15.75)

CSMS Implementation Steps:

  1. On Updated with triggerReason=StopAuthorized — The stopping idToken may differ from the starting token (they share the same GroupId). Validate the token and respond with idTokenInfo. Note: the CSMS CANNOT prevent a transaction from stopping.
  2. On Ended — Close the transaction, store final meter values, optionally return totalCost, respond with idTokenInfo if idToken was included.

Key Requirements:

ID Requirement
E07.FR.01 CS SHALL end authorization without sending AuthorizeRequest first (if same token or same GroupId)
E07.FR.02 CS SHALL send TransactionEventRequest with triggerReason=StopAuthorized and include the stopping idToken
E07.FR.04 stoppedReason MAY be omitted if stopped locally by EV driver
E07.FR.05 stoppedReason SHOULD be Local if stopped by EV driver at CS
E08

Transaction Stopped While Charging Station is Offline

Handle transactions that were stopped while the Charging Station had no connection to the CSMS.

Flow sequence after connection restored
     ... CS is offline, EV Driver presents token to stop ...
     ... CS validates locally (same token or same GroupId) ...
     ... CS stores TransactionEventRequest(eventType=Ended, offline=true) ...
     ... Connection restored ...
CS -> CSMS: TransactionEventRequest(eventType=Ended, offline=true,
            transactionId=AB1234, stoppedReason=Local, meterValues)
CSMS -> CS: TransactionEventResponse(totalCost=12.50)

CSMS Implementation Steps:

  1. Process identically to online stop — The transaction end is valid; process meter values and calculate costs.
  2. Note the offline = true flag — The stop happened in the past, potentially hours or days ago.
  3. Respond normally — Include totalCost if applicable.

Key Requirements:

ID Requirement
E08.FR.04 CS SHALL generate TransactionEventRequest(eventType=Ended)
E08.FR.05 CS MUST queue messages when offline
E08.FR.06 CS MUST send queued messages after connection restored
E08.FR.07 offline SHALL be TRUE
E09

Cable Disconnected on EV-side: Stop Transaction

Handle transactions that are stopped when the EV Driver unplugs the cable on the EV side.

Prerequisite: StopTxOnEVSideDisconnect = true

Flow sequence
CS -> CSMS: TransactionEventRequest(eventType=Ended, transactionId=AB1234,
            triggerReason=EVCommunicationLost, stoppedReason=EVDisconnected,
            seqNo=N+1, meterValues)
CSMS -> CS: TransactionEventResponse(totalCost=10.00)
     ... EV Driver authenticates and unplugs cable from CS side ...
CS -> CSMS: StatusNotificationRequest(status=Available)
CSMS -> CS: StatusNotificationResponse()

CSMS Implementation Steps:

  1. Close the transaction immediately upon receiving the Ended event.
  2. Store meter values — These are the final readings for billing.
  3. Return totalCost if applicable.
  4. Update connector status when StatusNotificationRequest(Available) arrives.

Key Requirements:

ID Requirement
E09.FR.01 Transaction SHALL be deauthorized when cable disconnected. If EV reconnects, energy not allowed until re-authorized
E10

Cable Disconnected on EV-side: Suspend Transaction

Handle the flow where the cable is disconnected on the EV side but the transaction is NOT stopped — just suspended.

Prerequisite: StopTxOnEVSideDisconnect = false

Cable disconnected — transaction suspended
CS -> CSMS: TransactionEventRequest(eventType=Updated, transactionId=AB1234,
            chargingState=SuspendedEV, triggerReason=EVCommunicationLost,
            seqNo=N+1, meterValues)
CSMS -> CS: TransactionEventResponse()
Cable plugged back in — transaction resumes
CS -> CSMS: TransactionEventRequest(eventType=Updated, transactionId=AB1234,
            chargingState=Charging, triggerReason=CablePluggedIn, seqNo=N+2)
CSMS -> CS: TransactionEventResponse()
     ... Continues with E02 Cable Plugin First flow ...
EV Driver ends transaction without reconnecting
     ... EV Driver authenticates ...
CS -> CSMS: TransactionEventRequest(eventType=Ended, transactionId=AB1234,
            triggerReason=StopAuthorized, seqNo=N+2, meterValues)
CSMS -> CS: TransactionEventResponse(totalCost=...)

CSMS Implementation Steps:

  1. On Updated (SuspendedEV) — Update transaction state to suspended. Do NOT close the transaction. Continue tracking seqNo.
  2. On subsequent Updated (Charging, CablePluggedIn) — Transaction resumes. Update state back to active.
  3. On Ended — Close the transaction and calculate total cost based on all meter values received during the full transaction.
E11

Connection Loss During Transaction

Handle the scenario where the connection between CS and CSMS is lost while a transaction is ongoing.

Flow sequence after connection restored
     ... Transaction is ongoing, connection is lost ...
     ... CS continues charging, queues TransactionEventRequest messages ...
     ... Connection restored ...
CS -> CSMS: TransactionEventRequest(eventType=Updated, offline=true,
            transactionId=AB1234, seqNo=3, meterValues, ...)
CSMS -> CS: TransactionEventResponse(...)
CS -> CSMS: TransactionEventRequest(eventType=Updated, offline=true,
            transactionId=AB1234, seqNo=4, meterValues, ...)
CSMS -> CS: TransactionEventResponse(...)

CSMS Implementation Steps:

  1. Detect missing messages — Use seqNo to identify gaps. If you received seqNo 2 and then receive seqNo 5, messages 3 and 4 are missing.
  2. Process queued messages — All messages with offline = true should be processed and stored.
  3. Use GetTransactionStatus (E14) to check if all messages have been delivered.
  4. Validate tokens retroactively — Include idTokenInfo in responses to update the CS authorization cache.

Key Behavior:

  • CS MUST queue all TransactionEventRequest messages while offline
  • CS MUST send queued messages once connection is restored
  • CS sets offline = true on all queued messages
  • Transaction continues on the CS regardless of connection state
E12

Inform CSMS of an Offline Occurred Transaction

Handle a complete transaction (started AND stopped) that occurred entirely while the Charging Station was offline.

Full offline transaction delivered after reconnect
     ... Connection restored ...
CS -> CSMS: TransactionEventRequest(eventType=Started, offline=true,
            transactionId=OFF123, seqNo=0, timestamp=<past>, ...)
CSMS -> CS: TransactionEventResponse(...)
CS -> CSMS: TransactionEventRequest(eventType=Updated, offline=true,
            transactionId=OFF123, seqNo=1, ...)
CSMS -> CS: TransactionEventResponse(...)
CS -> CSMS: TransactionEventRequest(eventType=Ended, offline=true,
            transactionId=OFF123, seqNo=2, stoppedReason=Local, meterValues)
CSMS -> CS: TransactionEventResponse(totalCost=8.25)

CSMS Implementation Steps:

  1. Process the full transaction retroactively — Create the transaction, process all events, close it.
  2. All messages will have offline = true — The entire transaction happened while offline.
  3. Calculate costs — Based on the meter values provided in the Started and Ended messages.
  4. Always respond — Even if the transaction already ended, always respond to allow the CS to clear its queue.

Key Requirements:

ID Requirement
E12.FR.01 CS MUST queue TransactionEventRequest when offline
E12.FR.02 CS MUST send queued messages after connection restored
E12.FR.03 offline SHALL be TRUE for any message that occurred while offline
E13

Transaction-related Message Not Accepted by CSMS

Define behavior when the CSMS fails to respond to a TransactionEventRequest or responds with an error.

This use case is primarily about CS retry behavior

The CSMS must understand it to handle duplicates and retry scenarios correctly.

CSMS Implementation Steps:

  1. If CSMS doesn't respond within the timeout — The CS will retry the message. The CSMS may receive duplicate messages with the same transactionId + seqNo.
  2. Handle duplicates gracefully — Use transactionId + seqNo as an idempotency key. If the same pair is received again, respond normally but don't process it twice.
  3. Never fail to respond — The outcome of sanity checks SHALL NOT cause the CSMS to not respond. Always send a TransactionEventResponse, even if the data seems invalid. Failing to respond only causes the CS to retry.
  4. CALLERROR responses — If the CSMS sends a CALLERROR, the CS should not retry. Use this only for malformed messages that can never be accepted.

Idempotency Pattern:

The combination of transactionId + seqNo uniquely identifies a message. Store processed pairs and skip re-processing if the same pair arrives again.

E14

Check Transaction Status

Allow the CSMS to query the Charging Station about the status of a transaction and whether there are pending messages.

Check specific transaction
CSMS -> CS: GetTransactionStatusRequest(transactionId="AB1234")
CS -> CSMS: GetTransactionStatusResponse(
  ongoingIndicator=true,
  messagesInQueue=true
)
Check for any pending messages
CSMS -> CS: GetTransactionStatusRequest()  // no transactionId
CS -> CSMS: GetTransactionStatusResponse(
  messagesInQueue=false
)

CSMS Implementation Steps:

  1. When to use — After a connection restoration to check for pending messages; to verify if a specific transaction is still ongoing; to confirm all messages for a completed transaction have been delivered.
  2. With transactionId — Check a specific transaction's pending status and whether it's still active.
  3. Without transactionId — Check if ANY transaction messages are pending on the CS.
Scenario Request Expected Response
After connection restore, check pending {} (no transactionId) {messagesInQueue: true/false}
Verify all messages received for billing {transactionId: "X"} {ongoingIndicator: false, messagesInQueue: false}
Check if transaction still active {transactionId: "X"} {ongoingIndicator: true, messagesInQueue: true}
E15

End of Charging Process

Handle the final steps of the charging process, including interrupting and stopping charging.

Interrupting Charging (CSMS-initiated):

Method Action Result
Change availability Send ChangeAvailabilityRequest to make EVSE unavailable CS stops energy delivery but may not end the transaction
Revoke authorization Respond to any TransactionEventRequest with idTokenInfo.status != Accepted CS suspends or ends transaction based on StopTxOnInvalidId config
Remote Stop (E15) Send RequestStopTransactionRequest(transactionId=...) CS responds Accepted/Rejected, then sends TransactionEventRequest(Ended, stoppedReason=Remote)

The charging process ends when:

  1. All transaction events are delivered — CSMS has received TransactionEventRequest(eventType=Ended)
  2. All messages are delivered — Verified via GetTransactionStatus (messagesInQueue=false)
  3. Connector becomes available — CS sends StatusNotificationRequest(Available)

CSMS Finalization Checklist:

  • Received TransactionEventRequest(eventType=Ended) with final meter values
  • Verified all seqNo values are present (no gaps)
  • Optionally confirmed via GetTransactionStatusRequest that messagesInQueue=false
  • Calculated final cost and included totalCost in the last TransactionEventResponse
  • Updated connector status based on StatusNotificationRequest
  • Updated authorization cache based on idTokenInfo sent in responses

4. Configuration Variables

Reference

These configuration variables control transaction behavior. They are set on the Charging Station, but the CSMS can read and write them via the GetVariables / SetVariables messages.

TxCtrlr Component

Variable Description
TxStartPoint Defines when transaction starts. Values: ParkingBayOccupancy, EVConnected, Authorized, DataSigned, PowerPathClosed, EnergyTransfer
TxStopPoint Defines when transaction ends. Values: ParkingBayOccupancy, EVConnected, Authorized, PowerPathClosed, EnergyTransfer
StopTxOnInvalidId Whether to stop the transaction when the Id becomes invalid (CSMS returns non-Accepted). Default behavior varies.
MaxEnergyOnInvalidId Maximum Wh to deliver with an invalid Id (only when StopTxOnInvalidId=false). Transaction suspends after this limit.
StopTxOnEVSideDisconnect Stop the transaction when the cable is disconnected at the EV side (E09 vs E10).
UnlockOnEVSideDisconnect Unlock the connector when the cable is disconnected at the EV side.
EVConnectionTimeOut Timeout (seconds) for the EV to connect after authorization. If exceeded, CS may send eventType=Ended with stoppedReason=Timeout.

AuthCtrlr Component

Variable Description
AuthorizeRemoteStart Whether the CS should send an AuthorizeRequest to the CSMS before starting a transaction initiated by RequestStartTransactionRequest.
MasterPassGroupId GroupId for Master Pass tokens. Tokens in this group can stop any transaction (emergency use).

5. Decision Tree & State Machine

Reference

Appendix A: CSMS Response Decision Tree

How to respond to TransactionEventRequest based on eventType and whether an idToken is present:

Response Decision Tree
On receiving TransactionEventRequest:
  |
  |-- eventType = Started?
  |     |-- idToken present?
  |     |     |-- Validate token
  |     |     |-- Return idTokenInfo with status + groupIdToken
  |     |-- No idToken?
  |           |-- Return empty response {}
  |
  |-- eventType = Updated?
  |     |-- idToken present (triggerReason = Authorized or StopAuthorized)?
  |     |     |-- Validate token
  |     |     |-- Return idTokenInfo with status
  |     |-- No idToken?
  |           |-- Return empty response {}
  |           |-- Optionally return updatedPersonalMessage or chargingPriority
  |
  |-- eventType = Ended?
        |-- Calculate totalCost (optional)
        |-- idToken present?
        |     |-- Validate token
        |     |-- Return idTokenInfo with status
        |-- Return { totalCost: X.XX }
        |-- NOTE: totalCost omitted = NOT free; totalCost: 0.00 = free

Appendix B: Transaction State Machine (CSMS Perspective)

Transaction State Machine
                    TransactionEventRequest
                    (eventType=Started)
                          |
                          v
                    +-----------+
                    |  ACTIVE   |
                    +-----------+
                    |           |
    Updated         |           |   Updated
    (Charging)      |           |   (SuspendedEV/EVSE)
         |          |           |        |
         v          |           |        v
    +-----------+   |           |   +-----------+
    | CHARGING  |<--+           +-->| SUSPENDED |
    +-----------+                   +-----------+
         |                               |
         |    TransactionEventRequest    |
         |    (eventType=Ended)          |
         |          |                    |
         v          v                    v
    +-----------------------------------+
    |           COMPLETED               |
    +-----------------------------------+
         |
         v
    Verify seqNo completeness
    Calculate totalCost
    Finalize billing

Appendix D: Common CSMS Error Scenarios

1. Duplicate TransactionEventRequest

Cause

CS retried because CSMS response was lost.

Solution

Use transactionId + seqNo as an idempotency key. Respond normally, don't double-process.

2. Out-of-order Messages

Cause

Messages queued offline arrive in unexpected order.

Solution

Use seqNo and timestamp to reconstruct ordering. Process in seqNo order.

3. Missing seqNo Gap

Cause

Messages lost in transit.

Solution

Use GetTransactionStatusRequest to check for pending messages. If messagesInQueue=false and gaps exist, the messages were truly lost.

4. Transaction Started Without IdToken

Cause

TxStartPoint is EVConnected or ParkingBayOccupancy — transaction starts before authentication.

Solution

Normal behavior. IdToken arrives in a subsequent Updated message. Do not reject the transaction.

5. Unknown TransactionId

Cause

CS generated the ID. CSMS has no prior knowledge of it.

Solution

Always accept and store. The CS is the source of truth for transaction IDs.

OCPP 2.0.1 Transaction Flows - CSMS Developer Guide. Based on OCPP 2.0.1 Edition 4 Specification (Part 2, Section E: Transactions, 2025-12-03).