When you start a charging session via your phone app, the back-end of your charging network sends a RemoteStart message to the charger to begin the session. The message is one of the core OCPP operations, the flow is conceptually simple, and yet the unhappy paths cause a meaningful fraction of “the app says charging but the charger isn’t” support tickets.
This article covers what RemoteStart and RemoteStop do, the lifecycle, and the failure modes that come up in production.
The basic flow
A typical app-initiated session:
- User opens app, selects a charger, taps “Start Charging.”
- App sends a request to its back-end.
- Back-end (the eMSP) makes a Command request to the CPO via OCPI (since the user’s eMSP isn’t the charger’s operator).
- CPO’s CSMS receives the OCPI Command and translates to OCPP RemoteStart toward the specific charger.
- Charger receives RemoteStart and decides whether it can comply.
- Charger responds with Accepted or Rejected.
- If Accepted, charger waits for vehicle plug-in (or proceeds if the vehicle is already plugged in).
- Charger sends StartTransaction (1.6) or TransactionEvent (Started) (2.0.1).
- Charging proceeds normally.
The user sees: tap button → wait a few seconds → charging starts. If anything in the above flow breaks, the user sees: tap button → wait → nothing happens → frustrated user.
sequenceDiagram
participant App
participant eMSP
participant CPO as CPO CSMS
participant EVSE as Charger
App->>eMSP: Start charging
eMSP->>CPO: OCPI START_SESSION
CPO->>EVSE: RemoteStart
EVSE-->>CPO: Accepted
EVSE->>CPO: StatusNotification
EVSE->>CPO: Transaction Started
CPO-->>eMSP: Session push
eMSP-->>App: Charging active
RemoteStartTransaction (OCPP 1.6)
The request:
{
"connectorId": 1,
"idTag": "USER-12345",
"chargingProfile": null
}
- connectorId — which connector to start. Optional in some implementations; if omitted, the charger picks an available one.
- idTag — the user identifier this session is attributed to. Used for billing, CDR generation, and authorization context.
- chargingProfile — optional charging profile to apply for this transaction (smart charging).
The response:
{ "status": "Accepted" }
Or:
{ "status": "Rejected" }
The charger can reject for various reasons (already in a transaction, faulted, no power, connector not available). When rejected, no transaction starts.
RequestStartTransaction (OCPP 2.0.1)
The 2.0.1 equivalent is named RequestStartTransaction and is slightly richer:
{
"remoteStartId": 4567,
"idToken": {
"idToken": "USER-12345",
"type": "ISO14443"
},
"evseId": 1,
"chargingProfile": null
}
- remoteStartId — a request ID assigned by the CSMS, returned in subsequent TransactionEvents so the back-end can correlate.
- idToken — structured user identifier (the type field is new in 2.0.1).
- evseId — which EVSE (not just connectorId; 2.0.1 distinguishes EVSEs and connectors).
- chargingProfile — same as 1.6.
The response is similar:
{ "status": "Accepted" }
Or Rejected, with optional statusInfo for diagnostic detail.
What happens after Accepted
After accepting a RemoteStart, the charger:
- Updates connector status (Available → Preparing usually).
- Sends StatusNotification with the new state.
- Waits for the vehicle to be plugged in (if not already).
- Optionally waits for further conditions (cable lock, vehicle handshake, contactor close).
- Sends StartTransaction (coming soon) / TransactionEvent (Started) (coming soon) when actual charging begins.
The time between RemoteStart Accepted and StartTransaction can be seconds (if vehicle already plugged in) to minutes (if user hasn’t plugged in yet). Some chargers have a timeout — if no vehicle is plugged in within N minutes, the RemoteStart is cancelled.
RemoteStop (OCPP 1.6) / RequestStopTransaction (OCPP 2.0.1)
The mirror operation for stopping.
OCPP 1.6 RemoteStopTransaction:
{ "transactionId": 12345 }
Just the transactionId. The charger ends the session and sends StopTransaction.
OCPP 2.0.1 RequestStopTransaction:
{ "transactionId": "abc-123-def" }
Same idea, with the 2.0.1 string-based transactionId.
The response is Accepted or Rejected. Rejected typically means “no such transaction” or “transaction is in a state that can’t be stopped right now.”
Common failure modes
A list of things that go wrong with RemoteStart in production.
Charger is offline
The CSMS sends RemoteStart over the WebSocket. The WebSocket is dead. The CSMS doesn’t know yet (no failed heartbeat detected). The send fails or queues forever. The user sees “starting…” indefinitely.
Mitigation: detect offline status before attempting RemoteStart; tell the user upfront that the charger is offline.
Connector ID wrong
The app shows the user picking “Connector A,” which maps to connectorId 1 in the CPO’s database. But for this specific charger, the physical connector A is actually connectorId 2. The RemoteStart fails because connector 1 is in a different state.
Mitigation: keep your connector mapping rigorously synchronized between the OCPP layer and your user-facing presentation.
Charger is in a non-ready state
The charger is faulted, in maintenance mode, or already in a transaction. RemoteStart returns Rejected.
Mitigation: query the charger’s current state before sending RemoteStart; surface the actual reason to the user (“This charger is currently under maintenance”).
User unplugs / disappears
RemoteStart is Accepted but the user walks away without plugging in. After a timeout, the charger cancels. From the user’s perspective, “I tried to start charging but it didn’t work.”
Mitigation: clear UX explaining that the user needs to plug in within a time window; reset state if they don’t.
Race with local card tap
User taps Start in app. Simultaneously another user taps an RFID card at the same connector. Two sessions try to start. One wins, one fails confusingly.
Mitigation: this is hard to solve perfectly; locking on the connector at the CSMS level can help, but it adds latency. Most real-world implementations accept that this race exists and design UX around it.
eMSP-CPO OCPI failure
The eMSP sends an OCPI Command to start a session. The CPO’s OCPI endpoint is down or slow. The Command times out. The user’s app shows an error but the user doesn’t know whether to retry (which might cause a double-charge if the original eventually got through).
Mitigation: idempotent command IDs; clear retry semantics; back-off and surface error to user with actionable next step.
Charging profile rejected
RemoteStart includes a chargingProfile (smart charging). The charger doesn’t support smart charging, or the profile is malformed. The RemoteStart is rejected entirely.
Mitigation: handle profile errors separately from session-start errors; if the user just wants to start charging, accept without a profile rather than failing the whole start.
How the CSMS should handle RemoteStart
A few design principles.
Idempotency. If the same RemoteStart request comes in twice (because the eMSP retried), don’t start two sessions. Use a request ID or natural key (charger + connector + idTag + time-window) to deduplicate.
Timeout. If RemoteStart returns no response from the charger within 30-60 seconds, treat it as failed. Don’t leave the user’s app hanging.
State tracking. Track the in-flight RemoteStart state (“Sent at T, awaiting response, awaiting transaction start, transaction started”). Useful for diagnosis when something goes wrong.
Correlate with the resulting transaction. When TransactionEvent (Started) arrives, correlate it back to the RemoteStart that triggered it. Useful for debugging “did this session start because of an app initiation or a local card tap?”
Surface errors clearly to the OCPI caller. If the charger Rejects, return a meaningful OCPI Command response so the eMSP can tell its user something useful.
What chargers should do
For charge point firmware:
Validate the RemoteStart before accepting. Don’t accept if you’re in a state where you can’t actually start. Better to reject promptly than accept and fail later.
Send StatusNotification immediately. The CSMS uses StatusNotification to update its dashboard; don’t leave it stale after a state change.
Handle plug-in timeouts. If the user doesn’t plug in within a reasonable window after RemoteStart, cancel and return to Available. Don’t leave the connector reserved indefinitely.
Generate transactionId predictably. Don’t reuse old IDs; don’t generate duplicates.
Differentiate RemoteStart-initiated transactions from local-card transactions. The triggerReason field in OCPP 2.0.1 TransactionEvent helps with this.
App-side considerations
For the developer of the user-facing app:
Show realistic timing expectations. Tell the user “starting charge, this can take up to 30 seconds.” Don’t show a spinner forever.
Handle failures gracefully. If the charger rejects, explain why if you can (charger offline, in use, faulted). Don’t just show “An error occurred.”
Verify success. Don’t trust the Accepted response from RemoteStart alone. Wait until you see a Session start event (via OCPI Session push) before declaring success to the user.
Handle the unhappy stop. If RemoteStop fails for any reason, give the user an actionable next step (“the session is still active; please unplug the cable to end”).
The interplay with payment
A subtle but important detail: in many app-initiated flows, the user has pre-authorized payment (saved card, account balance). The eMSP commits to billing the user before sending RemoteStart. If RemoteStart fails, you need to release that pre-authorization.
In other flows, the user pays per-session via the charger’s display. RemoteStart bypasses this; the eMSP handles billing entirely. The charger needs no payment terminal interaction.
Make sure your billing flow matches your RemoteStart flow. Both must agree on who pays for the session.
The honest summary
RemoteStart and RemoteStop are the OCPP messages that make app-initiated charging possible. The happy path is simple; the unhappy paths are numerous and operationally important to handle well. Investing in proper state tracking, clear error surfacing, and good idempotency pays back in fewer “the app failed to start charging” support tickets — one of the most common categories of user complaint in EV charging.