What Is OCPP?
OCPP — Open Charge Point Protocol — is the industry standard for communication between EV charging stations (Charge Points) and backend management systems (Central System Management Software, or CSMS). Version 1.6 is the most widely deployed version in the field today.
The protocol runs over WebSocket. The Charge Point is always the WebSocket client; the CSMS is the server. Messages are JSON (in the -J variant, which is what everyone actually uses).
The Message Format
Every OCPP message is a JSON array with a fixed structure:
[MessageTypeId, UniqueId, Action, Payload]- MessageTypeId: 2 = Call (request), 3 = CallResult (response), 4 = CallError
- UniqueId: A string you generate to correlate requests with responses
- Action: The name of the operation (e.g., "BootNotification")
- Payload: The message body as a JSON object
A typical BootNotification exchange looks like:
// Charge Point → CSMS
[2, "19223201", "BootNotification", {
"chargePointModel": "SingleSocketCharger",
"chargePointVendor": "VendorX"// CSMS → Charge Point [3, "19223201", { "currentTime": "2026-03-05T10:00:00Z", "interval": 300, "status": "Accepted" }] ```
Core Message Flows
Startup Sequence
When a charger boots, it must send BootNotification and wait for Accepted before doing anything else. If the CSMS returns Pending or Rejected, the charger should back off and retry at the interval specified in the response.
After BootNotification is accepted, the charger sends StatusNotification for each connector, then starts sending Heartbeat messages at the interval the CSMS specified.
Authorization
Before starting a transaction, the charger typically needs to authorize the user. It sends Authorize with the idTag (RFID token), and the CSMS responds with an AuthorizationStatus. The important statuses are:
- Accepted: Allow the transaction
- Blocked: Card is blocked; do not start
- Expired: Card has expired
- Invalid: Unknown card
- ConcurrentTx: Card already has an active transaction elsewhere
Transaction Flow
StartTransaction → [CSMS assigns transactionId]
→ StatusNotification (Charging)
→ MeterValues (periodic, optional)
→ StopTransaction → [CSMS closes transaction]
→ StatusNotification (Available)The transactionId from StartTransaction must be included in StopTransaction and all MeterValues during the session.
Remote Commands
The CSMS can send commands to the charger. Key ones to implement:
- RemoteStartTransaction / RemoteStopTransaction: Start or stop a session
- Reset: Soft (graceful) or Hard (immediate) restart
- ChangeAvailability: Take a connector in/out of service
- GetConfiguration / ChangeConfiguration: Read and write config keys
- UnlockConnector: Physically release the cable
Common Implementation Mistakes
1. Not handling the backpressure from BootNotification Pending
Some chargers ignore a Pending response and start sending Heartbeats immediately. The spec is clear: wait until Accepted.
2. Using stale transactionIds
Always use the transactionId the CSMS assigned in StartTransaction.CallResult. Never reuse IDs from previous sessions.
3. Not sending StatusNotification after StopTransaction
After a transaction ends, the connector status should transition back to Available (or Preparing, or Faulted, depending on state). Forgetting this leaves the CSMS with a stale connector state.
4. Ignoring the heartbeat interval
The CSMS tells you how often to send Heartbeat in the BootNotification response. Use that value, not a hardcoded one.
Testing Your Implementation
This is where OCPP Tester comes in. It simulates a CSMS and drives your charger through all these flows, validating the message structure and sequencing at each step. You'll catch most compliance issues in the first run.