PILLAR GUIDE · UPDATED 11 AUG 2026

OCPP: the complete guide

OCPP is the language every charge point speaks to the system that operates it. Everything a driver experiences — the card tap, the session starting, the number on the invoice — is OCPP messages underneath. This is the map of all of them.

IN ONE PARAGRAPH

OCPP runs over a persistent WebSocket between a charge point and its operator's CSMS. 1.6J is the deployed reality; 2.0.1 is the better-designed successor that most fleets cannot upgrade to. Everything above it — OCPI roaming, Beckn discovery — ultimately resolves into these messages.

What OCPP is for

A charge point is a piece of roadside hardware with a contactor, a meter, a card reader and a cellular modem. On its own it can do almost nothing useful: it does not know who is allowed to charge, what electricity costs, or where to send the meter readings.

OCPP connects it to a CSMS — a Charging Station Management System, the operator's platform. Over that link the charger asks permission, reports state, streams meter data, and accepts commands. Every business function of a charging network is built on those four things.

It is maintained by the Open Charge Alliance and is the reason a charging operator can buy hardware from several vendors and run it all from one platform.

Transport and framing

OCPP-J runs over a persistent WebSocket, initiated by the charge point. The charger dials out, which matters because roadside hardware is almost never publicly addressable.

GET /ocpp/CP014 HTTP/1.1
Host: csms.example.com
Upgrade: websocket
Sec-WebSocket-Protocol: ocpp1.6

The subprotocol header is how version selection happens — ocpp1.6 or ocpp2.0.1. A CSMS supporting both picks per connection.

Message framing

Every message is a JSON array with a type identifier first:

TypeNameShape
2CALL[2, "uniqueId", "Action", {payload}]
3CALLRESULT[3, "uniqueId", {payload}]
4CALLERROR[4, "uniqueId", "ErrorCode", "description", {details}]

The uniqueId correlates a result to its call. Because the socket is bidirectional, both sides initiate calls — the charger sends Heartbeat and StatusNotification upward, while the CSMS sends RemoteStartTransaction and Reset downward. A CSMS is a server that is also a client.

The message map

Each of these has a full guide.

Lifecycle and connection

MessageDirectionPurpose
BootNotificationCP → CSMSRegistration on connect; sets the heartbeat interval
HeartbeatCP → CSMSLiveness and clock synchronisation
StatusNotificationCP → CSMSConnector state and fault codes

Transactions

MessageDirectionPurpose
AuthorizeCP → CSMSMay this credential charge?
StartTransactionCP → CSMSOpens a session; CSMS assigns the transaction ID
MeterValuesCP → CSMSEnergy, power, voltage, state of charge
StopTransactionCP → CSMSFinal meter reading and stop reason
TransactionEventCP → CSMS2.0.1 only — replaces the three above

Remote control and operations

MessageDirectionPurpose
RemoteStartTransactionCSMS → CPStart a charge from the cloud
RemoteStopTransactionCSMS → CPStop a charge from the cloud
SetChargingProfileCSMS → CPPower and current limits
Get/ChangeConfigurationCSMS → CPRead and write charger settings
UpdateFirmwareCSMS → CPFirmware rollout and diagnostics
Reset / ChangeAvailabilityCSMS → CPRestart, or take out of service

A complete session

How the messages fit together for one driver, one charge:

Charge point                                CSMS
     │                                        │
     ├── WebSocket connect (ocpp1.6) ────────►│
     ├── BootNotification ───────────────────►│
     │◄── Accepted, interval: 900 ────────────┤
     ├── StatusNotification: Available ──────►│
     │                                        │
     │   ── driver plugs in and taps card ──  │
     ├── StatusNotification: Preparing ──────►│
     ├── Authorize { idTag } ────────────────►│
     │◄── idTagInfo: Accepted ────────────────┤
     ├── StartTransaction ───────────────────►│
     │◄── transactionId: 770142 ──────────────┤
     ├── StatusNotification: Charging ───────►│
     │                                        │
     ├── MeterValues (every 60s) ────────────►│
     ├── Heartbeat (every 900s) ─────────────►│
     │                                        │
     │   ── driver unplugs ──                 │
     ├── StopTransaction { meterStop } ──────►│
     ├── StatusNotification: Finishing ──────►│
     ├── StatusNotification: Available ──────►│

Energy billed is meterStop - meterStart. Everything else in a charging business — roaming settlement, driver invoices, partner disputes — reconciles back to that subtraction.

1.6J versus 2.0.1

1.6J2.0.1
Released20152020
DeploymentThe overwhelming majority of installed hardwareGrowing, mostly newer DC hardware
TransactionsStart / Stop / MeterValuesOne TransactionEvent
ConfigurationFlat string key-valueStructured components and typed variables
Transaction IDIntegerString
SecurityAdded later by whitepaperThree security profiles in the core spec
Device modelImplicitExplicit component/variable inventory
They are not wire-compatible and there is no migration path in the field. 1.6J hardware generally cannot be firmware-upgraded to 2.0.1 — the device model differs too fundamentally. Any CSMS operating a real fleet runs both side by side, for years. Normalise both into one internal transaction model at the protocol edge so that billing, roaming and reporting never know which version a charger speaks.

Security

OCPP 1.6 shipped without a security model; it was added afterwards as a separate whitepaper, which means security posture on 1.6 fleets varies enormously. 2.0.1 defines three profiles in the core specification:

ProfileTransportAuthentication
1Unsecured HTTPHTTP Basic
2TLSHTTP Basic
3TLSClient certificates, mutual TLS

Profile 1 should not exist on a public network — it puts credentials and meter data in clear text over cellular. Profile 3 is the target for new deployments, though it brings certificate lifecycle management into scope, which is a real operational burden on hardware that may be in the field for a decade.

Practical baseline regardless of version: TLS on every connection, per-charger credentials rather than a shared secret, and configuration auditing so a charger cannot be silently repointed at another CSMS.

Where OCPP sits in the stack

  Beckn  ── open discovery and booking, any buyer app to any provider
    │
  OCPI   ── bilateral roaming, eMSP ↔ CPO
    │
  OCPP   ── operator to its own hardware
    │
  Charge point

A single driver action can traverse all three. A driver taps “start” in an app found through Beckn; the booking becomes an OCPI START_SESSION to the CPO; the CPO issues RemoteStartTransaction to the charger. Three protocols, three company boundaries, one tap.

OCPPOCPI
BetweenCharger and its own operatorTwo companies
TransportPersistent WebSocketHTTPS request/response
Crosses a company boundaryNoYes
Owned byOpen Charge AllianceEVRoaming Foundation

The financial join between the layers is the one to get right: the OCPP StopTransaction is the ground truth an OCPI CDR must reconcile against. If those two disagree, the CDR is wrong and you cannot defend the invoice.

An implementation roadmap

PhaseBuildYou can now
1WebSocket + framing + BootNotification + HeartbeatKeep chargers connected and know they are alive
2StatusNotificationPublish accurate availability
3Authorize + Start / StopRun and bill real charging sessions
4MeterValuesLive progress and granular billing
5Remote start / stopApp-driven charging and OCPI roaming
6Configuration + firmware + resetOperate a fleet rather than a demo
7Smart chargingLoad management and grid participation

Phases 1 to 4 are a working charging network. Phase 6 is what separates an operator from a prototype — without configuration management and firmware control, a fleet becomes unmaintainable at a few hundred units.

Production lessons

  • Design for offline first. Chargers on cellular links lose connectivity constantly. Queued transactions arriving hours late are normal operation, not an error path.
  • Trust message timestamps over receipt time for anything financial.
  • Make ingestion idempotent. Chargers resend when unsure, and duplicates must never become duplicate charges.
  • Reconcile CDRs against StopTransaction continuously. The mismatch rate is the number an audit asks for.
  • Serve a synchronised clock in Heartbeat. Every downstream timestamp inherits it.
  • Normalise 1.6J and 2.0.1 at the edge. Two billing paths is a permanent tax.
  • Certify each charger model. Vendor conformance varies far more than the spec implies; what works on one model is not evidence about another.
  • Never publish stale availability. A charger you have not heard from is UNKNOWN, not available.

Official reference

The normative sources are the OCPP 1.6 and OCPP 2.0.1 specifications published by the Open Charge Alliance, along with the OCPP 1.6 Security Whitepaper. This guide and the linked message pages are written against them, with the operational detail that only appears once hardware from several vendors is running in the field.

Frequently asked questions

What is OCPP?

The Open Charge Point Protocol, the standard by which a charge point communicates with the operator's management system (CSMS). It carries authorisation requests, status and fault reporting, meter data and remote commands, and it is what lets an operator run hardware from multiple vendors on one platform.

What is the difference between OCPP and OCPI?

OCPP runs between a charger and its own operator over a persistent WebSocket. OCPI runs between two companies over HTTPS — typically a CPO and an eMSP exchanging locations, tokens, sessions and CDRs. OCPP never crosses a company boundary; OCPI exists to cross one.

Should you use OCPP 1.6J or 2.0.1?

In practice you support both. 1.6J is the overwhelming majority of installed hardware and generally cannot be upgraded, since the device model differs too fundamentally. Any CSMS running a real fleet speaks both side by side and normalises them into one internal model.

How does OCPP handle a charger losing connectivity?

The charger continues operating under its configured offline authorisation policy, generates temporary local transaction IDs, and queues messages for replay. Platforms must therefore expect transactions arriving hours late, out of order and sometimes duplicated.

What are the OCPP 2.0.1 security profiles?

Profile 1 is unsecured HTTP with basic authentication, profile 2 is TLS with basic authentication, and profile 3 is TLS with client certificates and mutual authentication. Profile 1 should not be used on a public network, and profile 3 is the target for new deployments.

How is energy billed in OCPP?

By subtracting meterStart on StartTransaction from meterStop on StopTransaction. Both are cumulative register readings in watt-hours, and that subtraction is what every roaming settlement and driver invoice ultimately reconciles against.