Remote commands
Public API — Remote Commands & Troubleshooting
How to drive charging stations remotely — reset, start/stop sessions, availability, unlock, diagnostics, firmware — and how to find out why a command didn't do what you expected.
All command endpoints require permission charging-station:remote-control (see Authentication).
v1 vs v2
Both versions expose the same commands with the same request bodies:
- v1 —
/api/v1/commands/*. Most endpoints return204 No Content. - v2 —
/api/v2/commands/*. Every endpoint returns200with a JSON body containingocppMessageId— the correlation ID stamped on the outgoing OCPP message. Store it; it is your handle for tracing the command through OCPP logs (CPMS → OCPP adapter → charging station).
New integrations should use v2. Without ocppMessageId you cannot correlate a command with its OCPP exchange later.
The execution model: accepted ≠ executed
A command request is asynchronous: a 2xx response means the command was validated and dispatched towards the station — not that the station received or executed it. The station's reaction (or silence) arrives later over OCPP and shows up as entity state changes, sessions, webhooks, and OCPP log entries.
Two commands give you more than dispatch:
unlock-connectorwaits for the station's reply and returns the actual unlockstatus.start-sessionreturns a commandidyou can poll for the outcome.
sequenceDiagram
participant C as Your backend
participant API as Public API
participant CS as Charging Station
C->>API: POST /v2/commands/<command>
API-->>C: 200 { ocppMessageId }
Note over API,CS: asynchronous from here
API->>CS: OCPP call (ocppMessageId)
CS-->>API: Accepted / Rejected — visible in OCPP logs,<br/>entity state, sessions, webhooks
Command catalog
All paths relative to /api/v1/commands or /api/v2/commands. All are POST unless noted.
| Command | Path | Key request fields | v1 → / v2 → |
|---|---|---|---|
| Reset station | /reset | chargingStationId (UUID or OCPP ID), type: SOFT (default) | HARD | 204 / { ocppMessageId } |
| Start session | /start-session | connectorId, tokenUid | command DTO / { id, status, sessionId, ocppMessageId } |
| Start session status | GET /start-session/{id} | — | command DTO / { id, status, sessionId, ocppMessageId } |
| Stop session | /stop-session | chargingSessionId or chargingStationId + ocppTransactionId | 204 / { ocppMessageId } |
| Station availability | /change-charging-station-availability | id (UUID or OCPP ID), type: OPERATIVE | INOPERATIVE | 204 / { ocppMessageId } |
| Point availability | /change-charging-point-availability | id (charging point UUID), type | 204 / { ocppMessageId } |
| Connector availability | /change-connector-availability | id (connector UUID), type | 204 / { ocppMessageId } |
| Unlock connector | /unlock-connector | connectorId | { status } / { status, ocppMessageId } |
| Trigger message | /trigger-message | chargingStationId, requestedMessage, optional chargingPointId, connectorId | 204 / { ocppMessageId } |
| Get diagnostics | /get-diagnostics | chargingStationId (UUID), optional location, retries, retryInterval, startTime, stopTime | { url } / { url, message, ocppMessageId } |
| Update firmware | /update-firmware | chargingStationId, firmwareId xor locationUrl, optional retrieveDate, retries, retryInterval | 204 / { ocppMessageId } |
Command notes
Reset
SOFT asks the station to restart gracefully (finish transactions first); HARD reboots. Each reset is recorded in the station's restart log together with the API key that requested it.
curl -s -X POST -H "x-api-key: $API_KEY" -H "Content-Type: application/json" \
-d '{ "chargingStationId": "EWEL00629", "type": "SOFT" }' \
"https://<host>/api/v2/commands/reset"Start / stop session
Covered in depth — with sequence diagrams — in Session Flows. The short version:
start-sessioncreates a trackable command. PollGET /v2/commands/start-session/{id};statusmoves throughPENDING→ACCEPTED→SESSION_CREATED(withsessionIdset), or ends inREJECTED/TIMED_OUT.stop-sessionidentifies the session bychargingSessionId, or bychargingStationId+ocppTransactionId. The stop is confirmed asynchronously by the station — verify via session status or a webhook.
Change availability
INOPERATIVE takes the target out of service (station screen typically shows "unavailable"); OPERATIVE returns it to service. Three granularities: whole station, one charging point (EVSE), one connector.
OCPP 1.6 caveat: point-level availability requires the point to have exactly one connector (the 1.6 protocol addresses connectors, not EVSEs); otherwise the request is rejected with 400.
Unlock connector
The only fully synchronous command — the response carries the station's verdict:
status | Meaning |
|---|---|
UNLOCKED | Connector released |
UNLOCK_FAILED | Station tried and failed (cable still latched by the vehicle?) |
ONGOING_AUTHORIZED_TRANSACTION | Active authorized session — stop it first |
UNKNOWN_CONNECTOR | Station doesn't know this connector |
NOT_SUPPORTED | Station cannot unlock remotely |
Trigger message
Asks the station to proactively send a message — the primary self-service diagnostic tool. requestedMessage values (OCPP-standard):
BootNotification, Heartbeat, MeterValues, StatusNotification, DiagnosticsStatusNotification, FirmwareStatusNotification — plus, on stations supporting the extended set, LogStatusNotification and SignChargePointCertificate.
Optional chargingPointId / connectorId scope the trigger (both must belong to the given station, else 422). Triggering StatusNotification on a connector is the quickest way to check whether a station is alive and what state it reports.
Get diagnostics
Requests the station to upload a diagnostics archive. If you pass location (an FTP URL you control), the station uploads there. Without it, a CPMS-hosted FTP location is used and the response url is where the file will appear — the hosted download link is valid for 1 hour, and only after the upload completes (watch for DiagnosticsStatusNotification, or trigger it). startTime/stopTime bound the log window.
Update firmware
Provide exactly one of firmwareId (a firmware entity registered via /api/v1/firmware) or locationUrl (direct download URL for the station). retrieveDate defaults to now. Download and installation progress arrives via FirmwareStatusNotification — visible in the OCPP logs.
Troubleshooting
First rule: verify effect, not response
A 2xx proves dispatch, nothing more. Confirm the actual outcome through:
- Entity state — station/point/connector status:
POST /api/v1/charging-stations/rsql-listwith{ "filter": "status == 'ONLINE'" }, orGETthe entity. - Sessions —
GET /api/v1/sessions/{id}or aSESSIONwebhook. - OCPP logs —
POST /api/v1/charging-stations/{id}/ocpp-logs/rsql-list(permissioncharging-station:read-logs): the raw request/response exchange with the station. Search around the command timestamp and match the v2ocppMessageId.
Diagnosis flow
flowchart TD
A[Command returned 2xx<br/>but nothing happened] --> B{Station ONLINE?}
B -- no --> C[Station offline — command never reached it.<br/>Check connectivity, then retry]
B -- yes --> D{OCPP logs show the message?<br/>match ocppMessageId}
D -- no --> E[Not dispatched — check adapter health,<br/>report with X-Correlation-Id]
D -- yes --> F{Station reply in logs?}
F -- Rejected / error --> G[Station refused — see reply payload.<br/>Trigger StatusNotification to inspect state]
F -- none --> H[Station silent — power/network issue.<br/>Trigger Heartbeat; escalate to field service]
Error responses
| Status | Typical cause | What to do |
|---|---|---|
401 | Missing/invalid API key | Check x-api-key header (Authentication) |
403 | Key's role lacks charging-station:remote-control | Grant via IAM endpoints |
404 <Entity> not found | Unknown connectorId / session / charging point UUID | You passed the wrong ID or the wrong kind of ID — most fields take the internal UUID, not the OCPP ID |
400 | Validation error, missing station details, or the OCPP 1.6 multi-connector availability caveat | Message names the field/rule |
422 | Business rule violated | See table below |
500 | Unexpected | Report with X-Correlation-Id |
Common 422 reasons by command:
| Command | 422 cause |
|---|---|
reset, trigger-message, get-diagnostics | Station unknown or has never connected (no station details yet — a station that never sent BootNotification cannot be commanded) |
stop-session | Selector rule violated (chargingSessionId or chargingStationId+ocppTransactionId required); session has no OCPP transaction ID (never actually started on the station) |
trigger-message | chargingPointId/connectorId not part of the given station |
get-diagnostics | No location given and no hosted FTP configured for the environment |
update-firmware | Neither or both of firmwareId/locationUrl given; unknown firmware ID |
Frequent symptoms
| Symptom | Likely cause / fix |
|---|---|
start-session stuck in PENDING, then TIMED_OUT | Station offline, connector occupied, or station ignored the remote start. Check OCPP logs by ocppMessageId. |
start-session → REJECTED | Station refused (connector faulted/occupied) or token not authorized. |
ACCEPTED but sessionId stays null | Station accepted but the driver never plugged in / transaction never started. Some stations only start the transaction after the cable is connected. |
stop-session OK but session stays ACTIVE | Station hasn't confirmed the stop yet — it must send the stop transaction event. If it persists, station is offline or ignored the request; check logs. |
| Availability change has no visible effect | Verify via connector status afterwards; trigger StatusNotification. Some stations only apply INOPERATIVE after the running transaction ends (OCPP: "Scheduled"). |
Diagnostics url gives 404 / empty file | Upload not finished (or failed). Wait for DiagnosticsStatusNotification in the logs; hosted links expire after 1 hour — re-request if expired. |
| Every command 404s | You are using OCPP IDs where UUIDs are expected. Only reset, stop-session (chargingStationId), and station-level availability accept the OCPP station ID as an alternative. |
Reporting an issue
Include: the endpoint and request body (minus the API key), the response, the X-Correlation-Id response header, the v2 ocppMessageId, and the timestamp with timezone. These let operators trace the exact request through CPMS and OCPP adapter logs.
Related
- Session Flows — remote start/stop sequence diagrams, session lifecycle
- Bulk Operations — running these commands across a fleet of stations
- Webhooks — push confirmation of session state changes
- General guide — errors, pagination, correlation headers
- Authentication — keys, roles, permissions
Updated 7 days ago