Plugchoice

OCPP 1.6J Protocol Reference

The complete technical reference for the Open Charge Point Protocol, version 1.6J. All 28 messages documented from the official Open Charge Alliance specification.

What is OCPP?

The Open Charge Point Protocol (OCPP) is a free, open communication standard maintained by the Open Charge Alliance (OCA). It defines how EV chargers (Charge Points) talk to management software (a Central System) over a network connection.

OCPP 1.6J uses WebSocket with JSON payloads. A charger connects to a Central System URL, and both sides exchange structured messages: the charger reports its status, meter readings, and transaction events, while the Central System sends commands like starting sessions, updating firmware, or adjusting charging profiles.

Because OCPP is an open standard, any charger that supports it can connect to any compatible Central System. This prevents vendor lock-in and gives operators the freedom to mix hardware from different manufacturers under a single management platform.

Looking to switch your OCPP backend or run Plugchoice alongside an existing one? The Plugchoice OCPP proxy handles backend migrations and layered setups without disconnecting chargers.

Open protocol
Free to implement, maintained by the OCA
WebSocket + JSON
Persistent connection, structured payloads
28 messages
Organized across 6 feature profiles
Bidirectional
Both charger and server initiate messages

OCPP? Plugchoice

Free, no lock-inAny OCPP charger, any brandApp, portal and API includedSmart Charging built in

Plugchoice is a free charger management platform that acts as an OCPP Central System. Connect any OCPP-compatible charger and manage it through our web portal, mobile app, or REST API.

We support the full OCPP 1.6J specification, including Smart Charging profiles for load balancing and solar integration. Hardware-agnostic, no lock-in, no subscription fees for core features.

Plugchoice also acts as an OCPP Proxy, so you can run it alongside any existing billing or management platform without migration or charger reconfiguration.

See how the OCPP Proxy works

Protocol Reference

All 28 OCPP 1.6J messages organized by feature profile. Each message shows direction, required and optional fields, types, and valid enum values.

Core

Required. Fundamental charge point operations: authorization, transactions, status reporting, configuration, and basic remote control.

Firmware Management

Firmware updates and diagnostics upload for remote maintenance of charge points.

Local Auth List

Manage a local authorization cache on the charge point for offline authentication.

Reservation

Reserve a connector for a specific user ahead of time.

Smart Charging

Set and manage charging profiles for load balancing, solar integration, and scheduled charging.

Remote Trigger

Request the charge point to send a specific message on demand.

Configuration keys

ChangeConfiguration sets one key at a time on a charger, GetConfiguration reads them back. This is where most real-world charger behaviour is decided: how often meter values arrive, what is in them, whether a session survives a network outage, how a cable unlocks. Below are the standard OCPP 1.6 keys, what each one actually does, and a deep dive on the one that causes the most trouble.

How the call behaves

  • Every value is sent as a string, including numbers and booleans: "60", "true". Sending a JSON number is a common reason for a Rejected.
  • Key names are case sensitive and must match the spec exactly. MeterValuesSampledData works, metervaluessampleddata does not.
  • Many keys only take effect after a restart. The charger tells you by answering RebootRequired, and it is on you to send a Reset.
  • Manufacturers add their own keys beyond this list. GetConfiguration with an empty key list returns everything a charger supports, including those, plus an unknownKey array for anything it does not recognise.

What the four responses mean

Accepted
the key is set and active now.
Rejected
the key exists but the value was refused: out of range, wrong format, or read-only on this charger.
RebootRequired
the value is stored but does not apply until the charger restarts.
NotSupported
the charger does not implement this key at all.

Standard keys

Core

KeyTypeAccessWhat it does
AllowOfflineTxForUnknownIdoptional in specbooleanRWWhether the charger starts a transaction for an unknown idTag while it is offline.True keeps a site charging through a network outage, at the cost of sessions you may not be able to bill to anyone.
AuthorizationCacheEnabledoptional in specbooleanRWWhether the charger caches the outcome of earlier Authorize calls.Different from the Local Auth List: the cache fills itself from real authorizations, the list is pushed by the backend.
AuthorizeRemoteTxRequestsbooleanRWhether the charger authorizes the idTag in a RemoteStartTransaction before starting.If true, a remote start from the app still needs an Authorize round trip, so a bad idTag fails the start.
BlinkRepeatoptional in specinteger (times)RWHow often the charger blinks the lamp during a blink sequence.
ClockAlignedDataIntervalinteger (seconds)RWInterval for clock-aligned meter values, measured from midnight. 0 disables them.900 gives a reading on every quarter hour. This is the one that feeds MeterValuesAlignedData, and it runs whether or not a car is plugged in.
ConnectionTimeOutinteger (seconds)RWHow long the charger waits for the driver to plug in after authorizing before it releases the connector.
ConnectorPhaseRotationCSLRWPhase rotation per connector, as connectorId.RST notation, for example 0.RST, 1.RST, 2.RTS.Wrong here means wrong phase-level meter values and wrong single-phase load balancing. Worth checking on any three-phase site.
ConnectorPhaseRotationMaxLengthoptional in specintegerRMaximum number of items in ConnectorPhaseRotation.
GetConfigurationMaxKeysintegerRMaximum number of keys a single GetConfiguration request may ask for.Ask for more than this and the charger may answer with an error. Send GetConfiguration with no keys at all to get everything it supports.
HeartbeatIntervalinteger (seconds)RWHow often the charger sends a Heartbeat when nothing else is happening.The BootNotification response can override this. On a metered SIM, a short heartbeat is the quiet data cost that adds up.
LightIntensityoptional in specinteger (%)RWBrightness of the charger's lighting, as a percentage.
LocalAuthorizeOfflinebooleanRWWhether the charger authorizes from its local list or cache while offline.
LocalPreAuthorizebooleanRWWhether the charger starts a transaction from the local list or cache while online, without waiting for the backend.Cuts the wait at the charger, at the cost of the backend not having the final say on every start.
MaxEnergyOnInvalidIdoptional in specinteger (Wh)RWEnergy the charger still delivers after an authorization turns out to be invalid.
MeterValuesAlignedDataCSLRWMeasurands sent in the clock-aligned MeterValues, on the ClockAlignedDataInterval.Same measurand vocabulary as MeterValuesSampledData, different trigger: the clock, not the session.
MeterValuesAlignedDataMaxLengthoptional in specintegerRMaximum number of measurands in MeterValuesAlignedData.
MeterValuesSampledDataCSLRWMeasurands sampled during a transaction and sent in MeterValues, on the MeterValueSampleInterval.The single most useful key on this page. See the deep dive below.
MeterValuesSampledDataMaxLengthoptional in specintegerRMaximum number of measurands in MeterValuesSampledData.Read this before you build a long list: exceed it and the charger rejects the whole thing.
MeterValueSampleIntervalinteger (seconds)RWHow often, during a transaction, the charger samples MeterValuesSampledData. 0 disables sampling.60 is a sane default. Below 30, with a long measurand list, you are generating a lot of traffic for very little extra insight.
MinimumStatusDurationoptional in specinteger (seconds)RWMinimum time the charger stays in a status before it reports the next one.Useful against status flapping on chargers that bounce between Preparing and Available.
NumberOfConnectorsintegerRNumber of physical connectors on this charger.
ResetRetriesinteger (times)RWHow often the charger retries a failed reset.
StopTransactionOnEVSideDisconnectbooleanRWWhether unplugging at the car side stops the running transaction.False means the session stays open after the cable is pulled, which is how you end up with sessions that never end.
StopTransactionOnInvalidIdbooleanRWWhether the charger stops the transaction when the backend rejects the idTag.
StopTxnAlignedDataCSLRWClock-aligned measurands added to the transactionData of StopTransaction.
StopTxnAlignedDataMaxLengthoptional in specintegerRMaximum number of measurands in StopTxnAlignedData.
StopTxnSampledDataCSLRWSampled measurands added to the transactionData of StopTransaction.Keep this short. Everything in it is repeated for every sample of the whole session inside one StopTransaction payload, which is how chargers produce megabyte stop messages that backends reject.
StopTxnSampledDataMaxLengthoptional in specintegerRMaximum number of measurands in StopTxnSampledData.
SupportedFeatureProfilesCSLRFeature profiles this charger implements, for example Core, FirmwareManagement, SmartCharging.The honest answer to what a charger can do. Read it before you promise a customer smart charging.
SupportedFeatureProfilesMaxLengthoptional in specintegerRMaximum number of items in SupportedFeatureProfiles.
TransactionMessageAttemptsinteger (times)RWHow often the charger retries sending a transaction message the backend did not acknowledge.
TransactionMessageRetryIntervalinteger (seconds)RWBase wait between those retries. The charger multiplies it by the attempt number.
UnlockConnectorOnEVSideDisconnectbooleanRWWhether the cable unlocks at the charger when it is unplugged at the car.
WebSocketPingIntervaloptional in specinteger (seconds)RWInterval for WebSocket ping frames on the OCPP-J connection.The quiet fix for chargers that keep dropping offline behind a NAT or firewall that closes idle connections.

Local Auth List Management

KeyTypeAccessWhat it does
LocalAuthListEnabledbooleanRWWhether the local authorization list is in use.
LocalAuthListMaxLengthintegerRHow many entries the local authorization list holds.
SendLocalListMaxLengthintegerRHow many entries fit in a single SendLocalList message.A list bigger than this has to be sent in several differential updates.

Reservation

KeyTypeAccessWhat it does
ReserveConnectorZeroSupportedoptional in specbooleanRWhether the charger accepts a reservation on connector 0, meaning any connector.

Smart Charging

KeyTypeAccessWhat it does
ChargeProfileMaxStackLevelintegerRHighest stack level the charger accepts on a charging profile. Higher levels win.
ChargingScheduleAllowedChargingRateUnitCSLRWhich units the charger accepts in a charging schedule: Current (A), Power (W), or both.Send a profile in watts to a charger that only takes amps and it is rejected. This key tells you which to use.
ChargingScheduleMaxPeriodsintegerRMaximum number of periods in one charging schedule.
ConnectorSwitch3to1PhaseSupportedoptional in specbooleanRWhether the charger can switch between three-phase and single-phase charging.Decides whether you can throttle below the three-phase minimum instead of pausing altogether.
MaxChargingProfilesInstalledintegerRHow many charging profiles can be installed at once.

MeterValuesSampledData

This one key decides what telemetry you get out of a charging session. It is a comma separated list of measurands, and the charger samples every item on it at the interval set by MeterValueSampleInterval, then sends them in a MeterValues message. Leave it at the default and you get one cumulative energy reading, enough to bill, and nothing else: no power curve, no per-phase current, no voltage, no way to see whether a smart charging limit landed.

It never works alone. MeterValueSampleInterval sets how often it fires, MeterValuesSampledDataMaxLength caps how many measurands you may list, StopTxnSampledData decides which of them get repeated inside StopTransaction, and MeterValuesAlignedData is the same vocabulary on a clock schedule instead of a session.

The measurand vocabulary

Any of these may appear in the list. Which ones a charger actually supports is hardware dependent: an AC wallbox will not report SoC, and a basic charger may only have the energy register.

MeasurandUnitTypically onWhat it gives you
Energy.Active.Import.RegisterbillingWhAC and DCCumulative energy drawn from the grid, read straight off the meter register. The default when MeterValuesSampledData is empty, and the value nearly every billing calculation is built on.
Energy.Active.Export.RegisterWhV2G capableCumulative energy fed back, for bidirectional setups.
Energy.Active.Import.IntervalWhAC and DCEnergy imported since the previous sample, rather than a running total.
Energy.Reactive.Import.RegistervarhMeter dependentCumulative reactive energy imported.
Power.Active.ImportWAC and DCInstantaneous active power. What you plot to see a charging curve, and what load management reacts to.
Power.OfferedWAC and DCPower the charger is currently offering the car. Compare it with Power.Active.Import to see whether a limit is actually being applied.
Power.Reactive.ImportvarMeter dependentInstantaneous reactive power.
Power.FactorratioMeter dependentRatio of active to apparent power.
Current.ImportAAC and DCCurrent drawn. Usually reported per phase, so this one measurand can become three values per sample.
Current.OfferedAAC and DCCurrent limit the charger is signalling to the car. The direct read-out of whether your smart charging profile landed.
Current.ExportAV2G capableCurrent fed back, for bidirectional setups.
VoltageVAC and DCSupply voltage, per phase on three-phase chargers. Useful for spotting a dropped phase or a weak connection.
FrequencyHzMeter dependentGrid frequency. Note that the spec gives it no unit field.
TemperatureCelsiusCharger dependentTemperature at the charger or connector. Explains derating on a hot day before anyone calls it a fault.
SoC%DC, or ISO 15118 on ACState of charge of the car's battery. Only present when the car actually reports it, which on plain AC charging it usually does not.
RPMrpmRareFan speed, on chargers that report it.

Lists that work

Copy one of these into the value of a ChangeConfiguration call. Start narrow and add measurands once you have confirmed the charger accepts them.

Billing only

The minimum that still produces a correct invoice. The default on most chargers.

Energy.Active.Import.Register

Standard telemetry

Sensible default for a managed AC site: a power curve, per-phase current and voltage for diagnosis.

Energy.Active.Import.Register,Power.Active.Import,Current.Import,Voltage

Smart charging

Adds the offered values, so you can see whether a profile is actually being applied rather than assuming.

Energy.Active.Import.Register,Power.Active.Import,Power.Offered,Current.Import,Current.Offered,Voltage

DC fast charging

Adds state of charge and temperature, which DC chargers do report and which explain most derating.

Energy.Active.Import.Register,Power.Active.Import,Current.Import,Voltage,SoC,Temperature

What goes wrong

One bad measurand rejects the whole list

Chargers validate the list as a unit. If a single item is unsupported you get Rejected or NotSupported for everything, with no indication which one failed. Set the list one measurand at a time to find the offender, or read MeterValuesSampledDataMaxLength and the vendor documentation first.

One measurand can be three values

Current.Import and Voltage are reported per phase, so on a three-phase charger they arrive as three sampledValue entries each, tagged L1, L2, L3 or L1-N and so on. A list of six measurands can easily be a dozen values per sample. Payload size grows faster than the list length suggests.

Wh against kWh

The energy register is Wh by default, but the unit field can say kWh and some firmware does exactly that. Read the unit rather than assuming it, or you get an invoice that is off by a factor of a thousand.

A short interval is not free

MeterValueSampleInterval at 10 seconds with a long list means hundreds of messages per session. On a metered SIM that is real money, and on a large site it is real backend load. 60 seconds is a good default, 300 for sites where you only need the shape of the curve.

StopTxnSampledData is the payload trap

Everything listed there is repeated, for every sample of the entire session, inside a single StopTransaction message. A long list on a long session produces a payload big enough for backends to reject or truncate, and the transaction then fails to close cleanly. Keep it to the energy register unless you have a specific reason.

Drop the energy register and billing breaks

If Energy.Active.Import.Register is not in the list, the periodic meter values carry no cumulative total. Most backends then fall back to meterStart and meterStop from the transaction messages, and any session where StopTransaction goes missing becomes unbillable. Keep it in the list, always.

SoC is usually not available on AC

State of charge comes from the car, over ISO 15118 or the DC charging protocol. On a plain AC wallbox without Plug and Charge the car does not report it, so requesting SoC either gets rejected or returns nothing useful.

Read the context field

Each sampledValue carries a context: Sample.Periodic, Transaction.Begin, Transaction.End, Sample.Clock or Trigger. A value at Transaction.Begin is a starting register, not consumption. Treating every sample as periodic is how sessions end up double counted.

A full round tripSetting the list, and the MeterValues that follow on a three-phase charger.
// Set the list
[2,"19223201","ChangeConfiguration",{
  "key": "MeterValuesSampledData",
  "value": "Energy.Active.Import.Register,Power.Active.Import,Current.Import,Voltage"
}]
[3,"19223201",{"status":"RebootRequired"}]

// What the charger then sends, every MeterValueSampleInterval
[2,"19223202","MeterValues",{
  "connectorId": 1,
  "transactionId": 8123,
  "meterValue": [{
    "timestamp": "2026-07-23T11:04:00Z",
    "sampledValue": [
      {"value":"14230","measurand":"Energy.Active.Import.Register",
       "unit":"Wh","context":"Sample.Periodic"},
      {"value":"7360","measurand":"Power.Active.Import","unit":"W"},
      {"value":"10.7","measurand":"Current.Import","unit":"A","phase":"L1"},
      {"value":"10.6","measurand":"Current.Import","unit":"A","phase":"L2"},
      {"value":"10.8","measurand":"Current.Import","unit":"A","phase":"L3"},
      {"value":"231.2","measurand":"Voltage","unit":"V","phase":"L1-N"}
    ]
  }]
}]

This page for AI assistants

The whole reference, every message and every configuration key, as one plain-text file an LLM can read in a single fetch.

plugchoice.com/help/ocpp/llms.txt