DRAFT — not indexed by search engines. Visible only via direct URL or the admin page.

OCPP Message Flow: A Full Charging Session, Step by Step

The full OCPP message flow for a charging session, in order: boot, status, authorize, transaction start, MeterValues, stop. Plus a live simulator to replay it.

Most OCPP writing treats each message in isolation: here is BootNotification, here is MeterValues, here is StopTransaction. That is useful for reference, but it hides the thing that actually matters when you are debugging a live charger — the order. A charging session is not one message. It is an ordered conversation of roughly a dozen messages between the charge point and the CSMS, and when a session misbehaves, the fault is almost always in the sequence: a message that arrived out of order, never arrived, or arrived before the one it depends on.

The OCPP simulator stepping through a full charging session, frame by frame

This article walks the entire flow start to finish, in order, for both OCPP 1.6 and 2.0.1. Once you have the sequence in your head, try the interactive OCPP simulator and replay it live — you can watch each message leave the charge point, see the CSMS response, and step through a full session at your own pace.

The two layers: connection and session

Before any energy flows, the charger and CSMS establish a working connection. That is a distinct phase from the session itself, and separating the two in your mind clears up most of the confusion:

  • Connection layer — everything that keeps the charger online and reporting: BootNotification, StatusNotification, Heartbeat. These happen once at startup and then continue in the background for the life of the connection.
  • Session layer — everything bracketed by a single charging transaction: Authorize, StartTransaction, MeterValues, StopTransaction (or their 2.0.1 equivalents). These repeat for every car that plugs in.

A charger can sit connected and idle for hours, sending nothing but Heartbeat and the occasional StatusNotification, without a single session. The session messages only appear when someone actually charges.

The full OCPP 1.6 sequence

Here is a complete session from cold boot to unplug. Billions of live sessions still run on 1.6, so this is the flow most operators debug day to day.

sequenceDiagram
    participant CP as Charge Point
    participant CS as CSMS
    CP->>CS: BootNotification
    CS-->>CP: Accepted (interval, currentTime)
    CP->>CS: StatusNotification (Available)
    loop Every interval
        CP->>CS: Heartbeat
        CS-->>CP: currentTime
    end
    Note over CP: User taps RFID card
    CP->>CS: Authorize (idTag)
    CS-->>CP: Accepted
    CP->>CS: StatusNotification (Preparing)
    CP->>CS: StartTransaction (meterStart, idTag)
    CS-->>CP: transactionId, Accepted
    CP->>CS: StatusNotification (Charging)
    loop During session
        CP->>CS: MeterValues (energy, power...)
    end
    Note over CP: User unplugs
    CP->>CS: StopTransaction (meterStop, reason)
    CS-->>CP: Accepted
    CP->>CS: StatusNotification (Available)

Step by step:

  1. BootNotification — the charger announces itself with vendor, model, and firmware. The CSMS replies Accepted along with a currentTime (which the charger uses to sync its clock) and an interval (the Heartbeat cadence). Nothing else can happen until this is Accepted. The full field breakdown lives in the BootNotification message (coming soon) article.
  2. StatusNotification (Available) — the charger reports each connector’s state. Until the CSMS sees a connector as Available, it will not let a session start on it. Missing this message is a classic reason a healthy-looking charger refuses to serve cars.
  3. Heartbeat — sent at the interval from the boot response, this is the keep-alive that tells the CSMS the charger is still there. It runs continuously in the background for the rest of the session and beyond.
  4. Authorize — when the user presents a credential, the charger asks the CSMS whether the idTag is valid. The CSMS may check its own cache or query an eMSP over OCPI before answering Accepted or Invalid.
  5. StatusNotification (Preparing) — the connector moves out of Available as the vehicle prepares to charge.
  6. StartTransaction — the pivotal session message. It carries meterStart (the meter reading at the beginning), the connectorId, and the idTag. The CSMS responds with a transactionId that identifies this session everywhere downstream. The mechanics of this and its closing partner are covered in StartTransaction and StopTransaction (coming soon).
  7. StatusNotification (Charging) — the connector confirms energy is flowing.
  8. MeterValues — periodic readings of energy, power, voltage, current, and whatever else the charger samples. These are what your billing and dashboards consume; the details and the wide variation across OEMs are in the MeterValues message (coming soon) guide.
  9. StopTransaction — when the user unplugs or the session ends, the charger sends meterStop (final reading) and a reason (for example Local, Remote, EVDisconnected). Session energy is meterStop minus meterStart.
  10. StatusNotification (Available) — the connector returns to Available and the cycle can begin again.

Notice how StatusNotification threads through the whole sequence. It is not a one-time message; it fires on every state change, and it is your single best signal for what the connector is actually doing at any moment.

Where remote-start changes the order

Not every session begins with a card tap. When a driver starts charging from a mobile app, the CSMS is the initiator:

  1. The CSMS sends RemoteStartTransaction with the idTag already inside it.
  2. The charger accepts, and because the credential is already supplied, it can skip a separate Authorize round trip.
  3. From there the flow rejoins the normal path: StartTransaction, MeterValues, StopTransaction.

This is why “does a session always start with Authorize?” has no single answer — it depends on how the session was initiated. Remote start, cached local authorization, and plug-and-charge each shortcut or relocate the authorization step.

The OCPP 2.0.1 sequence

The connection layer in 2.0.1 looks almost identical: BootNotification, StatusNotification, Heartbeat. The session layer is where 2.0.1 makes its big simplification. Instead of three distinct messages, everything transaction-related flows through a single TransactionEvent message with an eventType field:

  • TransactionEvent (Started) replaces StartTransaction.
  • TransactionEvent (Updated) replaces the stream of MeterValues — the meter readings now ride inside the event.
  • TransactionEvent (Ended) replaces StopTransaction.
sequenceDiagram
    participant CP as Charge Point
    participant CS as CSMS
    CP->>CS: BootNotification
    CS-->>CP: Accepted
    CP->>CS: StatusNotification (Available)
    CP->>CS: Authorize (optional)
    CS-->>CP: Accepted
    CP->>CS: TransactionEvent (Started)
    CS-->>CP: idTokenInfo
    loop During session
        CP->>CS: TransactionEvent (Updated, meterValue)
    end
    CP->>CS: TransactionEvent (Ended, meterValue, reason)
    CS-->>CP: Accepted

The payoff is that a single, well-defined message envelope carries the entire life of a transaction, each event tied together by a shared transactionId and an incrementing seqNo so the CSMS can detect gaps or reordering. The trade-offs, the sequencing rules, and the offline behavior are covered in the TransactionEvent in OCPP 2.0.1 (coming soon) deep dive.

The important mental shift: in 1.6 you reason about three message types; in 2.0.1 you reason about three event types of one message. The information carried is broadly the same. What changed is the envelope and the discipline around ordering.

What actually goes wrong in the sequence

Once you see a session as an ordered flow, the common failure modes name themselves:

  • Boot accepted but no sessions. The charger connected and Heartbeats fine, but never sent StatusNotification (Available) after boot, so the CSMS treats every connector as unknown and refuses to start.
  • StartTransaction with no matching Authorize. In deployments that require pre-authorization, a session that skips the auth step gets rejected downstream even though the transaction opened locally.
  • MeterValues before StartTransaction. A reading arrives referencing a transactionId the CSMS has not created yet, usually because messages were queued offline and replayed out of order.
  • Missing StopTransaction. The charger lost connectivity mid-session and never sent the close, leaving a “stuck” open transaction that has to be reconciled or force-closed.
  • StatusNotification lag. The connector physically changed state but the notification was delayed, so the dashboard shows Charging on a connector that is actually free.

Every one of these is a sequencing problem, not a single-message problem. You cannot diagnose them by reading the spec for one message — you have to watch the whole conversation.

See the whole flow live

Reading the sequence is one thing; watching it unfold is another. The interactive OCPP simulator lets you replay a full session message by message — boot, status, authorize, transaction start, the MeterValues stream, and the close — for both 1.6 and 2.0.1. Step through it once end to end and the ordering stops being a diagram you memorize and becomes something you have actually seen happen.

If you are still building the foundations, the individual message guides linked above go one level deeper on each step. But keep coming back to the sequence — because in production, the order is the thing that breaks.

Frequently asked questions

What is the order of OCPP messages in a charging session?

At the connection level: BootNotification, then StatusNotification and Heartbeat. At the session level: Authorize (optional), StartTransaction (1.6) or a TransactionEvent Started (2.0.1), a stream of MeterValues or TransactionEvent Updated messages, then StopTransaction or TransactionEvent Ended. StatusNotification fires whenever the connector changes state throughout.

Does every session start with an Authorize message?

No. Authorize is used when the charger needs the CSMS to validate a credential before energy flows — a tapped RFID card, for example. Remote-start sessions carry the idToken in the RemoteStartTransaction request, so a separate Authorize is often skipped. Plug-and-charge and cached local authorization can also bypass an online Authorize round trip.

How is the OCPP 2.0.1 message flow different from 1.6?

The connection setup is nearly identical. The session itself changes: 1.6 uses three separate messages (StartTransaction, MeterValues, StopTransaction), while 2.0.1 folds all of them into one TransactionEvent message sent with eventType Started, Updated, or Ended. Meter readings ride inside those events instead of a standalone message.

Which side sends which messages?

The charge point initiates most session messages: BootNotification, StatusNotification, Authorize, StartTransaction, MeterValues, StopTransaction. The CSMS responds to each and initiates its own commands such as RemoteStartTransaction, RemoteStopTransaction, and SetChargingProfile. OCPP is bidirectional, so both ends can be the requester depending on the message.

Found this useful? Share it.