Introduction
API guide
  • AuthenticationSoon
  • Your first API callSoon
  • Interactive API referenceSoon
  • Roles and permissionsSoon
  • Errors, pagination and versioningSoon
  • Live updatesSoon
  • Sending commands to a chargerSoon
  • Rate limitsSoon
Troubleshooting
  • My charger will not connectSoon
  • It connects, then dropsSoon
  • A command timed out or returned 409Soon
  • A card is not being authorizedSoon
  • My transaction looks wrongSoon
  • Meter values are missing or sparseSoon
  • Reading the OCPP message logSoon
  • Known limitationsSoon
Reference
  • GlossarySoon
  • Endpoint indexSoon
  • OCPP message supportSoon
  • Status and error codesSoon
  • ChangelogSoon
Flowion Docs

Start and stop sessions remotely

OCPP functional block F — RemoteControl.

Starting a session from your own app instead of an RFID card is the most common reason to reach for the API. It is also the operation whose failure modes surprise people most, because "accepted" does not mean "charging".

Starting#

curl -X POST https://api.flowion.io/v1/connectors/$CONNECTOR/commands/start-transaction \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{}'

The command is addressed to a connector, by its UUID — not to a charger with a connector number. Connector numbers are only unique within an EVSE, so they cannot address anything on their own.

The answer is accepted or rejected.

accepted means the station agreed to try. It does not mean a transaction started. The station still has to find a vehicle plugged in, close its contactor, and succeed. If nothing is plugged in, most stations accept and then wait — often with a timeout after which nothing happens at all.

The transaction arrives separately, on the inbound path, as a normal Started transaction event. Nothing links it to your request. There is no correlation id to follow, so the way to know a remote start worked is to watch for a new transaction on that connector shortly afterwards.

Capping a session as you start it#

Two optional fields shape the session being started, and they cap different things.

charging_limit caps the rate — how much current or power the session may draw. This is a charging profile attached to the session. See Keep a site within its electrical limits.

transaction_limit caps the total — how much energy, how long, or to what state of charge:

curl -X POST https://api.flowion.io/v1/connectors/$CONNECTOR/commands/start-transaction \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"transaction_limit": {"max_energy_wh": 30000, "max_time_seconds": 7200}}'

Any combination of max_energy_wh, max_time_seconds and max_soc_percent.

Two caveats. This is an OCPP 2.1 feature, honoured by 2.1 stations only. And it is not sent as part of the remote start at all — the CSMS holds the ceiling and attaches it to the transaction the start produces. So a 200 here means the ceiling is held, not that the station has accepted it.

You can also set or change a ceiling on a session already running:

curl -X PUT https://api.flowion.io/v1/transactions/$TRANSACTION/limit \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"max_energy_wh": 20000}'

Stopping#

curl -X POST https://api.flowion.io/v1/chargers/$CHARGER/commands/remote-stop-transaction \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"transaction_id": {"numeric": 90210}}'

The transaction is named as the station knows it, which differs by OCPP version: a 1.6 station knows an integer, a 2.x station knows a string. This is the one place the version difference is unavoidable — see How Flowion maps onto OCPP.

Asking a 1.6 station to stop a string-identified transaction returns 422. The wire cannot express it, and inventing an integer would stop some transaction, just not the one you meant.

Fetch the transaction first and use whichever identifier it carries — numeric_id for 1.6, text_id for 2.x.

The answer is accepted or rejected. As with starting, the actual stop arrives afterwards as an Ended transaction event.

Reading the failures#

Every command shares the same status codes, and they distinguish genuinely different situations:

CodeWhat happenedWhat to do
200 + rejectedThe station answered noIt is a station-side condition — nothing plugged in, already charging, locally disabled
409Not connectedNothing was sent. Retry when it is back
422Not expressible for this stationFix the request; retrying will not help
502Answered with something unusableFirmware problem; check the command history
503Could not be sentTransient; retry
504No answer in timeUnknown outcome — see below

504 is the one that needs thought. The station may have received the command and acted on it, and simply failed to answer in time. Do not blindly retry a start on a timeout — you may end up with a session you did not intend. Check whether a transaction appeared first.

This is a consequence of the protocol's structure rather than a shortcoming here: a command travels down a socket the station opened, and stations on mobile connections are slow. See What a CSMS does.

Only one command at a time#

OCPP allows one outstanding request per direction on a connection. Commands to a single station are therefore serialised: a station that stops answering blocks the queue behind it until a timeout fires.

Practical consequences: do not fan out ten commands at one station and expect concurrency, and set your own client timeouts above the station's — a command can legitimately take tens of seconds.

Commands to different stations are independent.

What was asked, and what came back#

Every command is recorded:

curl https://api.flowion.io/v1/chargers/$CHARGER/commands \
  -H "Authorization: Bearer $TOKEN"

This is the audit trail — what was issued, by whom, and how the station answered synchronously. It is also the only record of a DataTransfer payload the CSMS cannot interpret.

What it does not record is the consequence. An accepted remote start and the transaction it produced are two unrelated rows.

Endpoints#

Commands · Transactions · Command History