The message
// Charge point -> CSMS
[2, "19223210", "StopTransaction", {
"transactionId": 770142,
"idTag": "DR88231ABCD",
"meterStop": 4496370,
"timestamp": "2026-08-11T10:03:41Z",
"reason": "EVDisconnected",
"transactionData": [{
"timestamp": "2026-08-11T10:03:41Z",
"sampledValue": [{
"value": "4496370",
"context": "Transaction.End",
"measurand": "Energy.Active.Import.Register",
"unit": "Wh"
}]
}]
}]
// CSMS -> charge point
[3, "19223210", { "idTagInfo": { "status": "Accepted" } }]Energy delivered is 4496370 - 4471820 = 24550 Wh, or 24.55 kWh. That subtraction is the entire financial basis of the session.
idTag is optional and may differ from the one that started the session — a driver can start with a card and stop with an app credential, provided both share a parentIdTag.
The stop reason is diagnostic gold
reason is optional in the spec and routinely ignored in implementations. It is the single best signal you have about what is actually happening across a fleet.
| Reason | Means | What a cluster of these tells you |
|---|---|---|
EVDisconnected | Driver unplugged | Normal — the healthy majority |
Local | Stopped at the charger | Normal |
Remote | Stopped by RemoteStopTransaction | Normal — app-initiated |
DeAuthorized | Authorisation withdrawn | Token or roaming problem |
EmergencyStop | Emergency button pressed | Investigate the site immediately |
PowerLoss | Charger lost power | Site electrical problem |
Reboot / HardReset / SoftReset | Charger restarted mid-session | Firmware instability — a repeat pattern is a warranty case |
UnlockCommand | Cable released remotely | Usually a stuck-cable incident |
Other | Unspecified | Vendor-specific; investigate |
EVDisconnected and Local. A model showing 5% Reboot has a firmware defect; a site showing repeated PowerLoss has an electrical problem. Neither shows up in uptime metrics, and both are visible here for free.transactionData and the offline case
transactionData carries meter samples the CSMS may not have received — typically the full set of readings taken while the charger was offline.
This is why an offline session still bills correctly. The charger stores samples locally and delivers them all in the stop message. Your ingestion must merge these with any MeterValues already received, de-duplicating on timestamp and measurand, rather than treating them as a second set of readings.
Doing that naively double-counts energy. The samples in transactionData frequently overlap with what already arrived.
Reconciliation: the honesty metric
This message is the point where an EV platform can check its own arithmetic. Three reconciliations are worth running continuously:
| Check | Compare | A mismatch means |
|---|---|---|
| Meter arithmetic | meterStop - meterStart vs the sum of MeterValues deltas | Lost or duplicated meter samples |
| OCPI CDR energy | Transaction energy vs CDR total_energy | Your CDR generation is wrong — a billing defect |
| Session closure | Every StartTransaction has a StopTransaction | Stuck sessions or lost messages |
The second row is the one that matters commercially. A roaming partner's dispute is settled by whether your CDR matches your own StopTransaction. If it does not, you cannot defend the invoice — and the mismatch rate against StopTransaction is the number an audit will ask for.
Sessions that never stop
Some transactions never receive a StopTransaction:
- The charger lost power mid-session and never recovered its queue.
- Firmware crashed and lost local state.
- The unit was decommissioned mid-transaction.
- The message was sent and lost, and the charger did not retry.
You cannot leave these open forever — they inflate the “currently charging” count and block the connector in your availability model. Age them out on a defined policy: close using the last received meter sample, mark the record as estimated, and exclude it from partner settlement rather than invoicing a number you cannot evidence.
Never silently invoice an estimated close. If you cannot evidence the energy, you cannot defend the charge.
Production lessons
- Reconcile every CDR against its StopTransaction. The mismatch rate is your platform's honesty metric.
- De-duplicate
transactionDataagainst received MeterValues before summing anything. - Record and dashboard the stop reason. It is free fleet diagnostics that most platforms discard.
- Age out unclosed transactions with an explicit policy, flagged as estimated.
- Handle zero-energy stops —
DeAuthorizedseconds after start must not generate an invoice. - Keep the raw payload. When a partner disputes energy, the original StopTransaction ends the discussion.
- Accept late stops without complaint. An offline charger delivering yesterday's transaction is working correctly.
Frequently asked questions
By subtracting meterStart on StartTransaction from meterStop on StopTransaction. Both are cumulative register readings in watt-hours, so the difference is the energy delivered during that session.
Meter samples the CSMS may not have received, typically readings taken while the charger was offline. They must be merged with any MeterValues already received and de-duplicated on timestamp and measurand, otherwise energy is double-counted.
It is the best fleet-diagnostic signal in the protocol and is usually discarded. A healthy estate is dominated by EVDisconnected and Local. A charger model showing frequent Reboot has a firmware defect, and a site showing repeated PowerLoss has an electrical problem — neither appears in uptime metrics.
Age it out on a defined policy: close it using the last received meter sample, mark the record as estimated, and exclude it from partner settlement. Never silently invoice an estimated close, because you cannot evidence the energy.
Yes, provided both credentials share a parentIdTag. This is what lets a driver start with an RFID card and stop from a mobile app.