Authentication
Authentication is session based. You sign in once against/auth/* and the API
sets a session cookie that every subsequent request carries.
Because authentication rides on a cookie, a browser client must send requests
with credentials included, and its origin must be on the API’s allow list.
Roles and scoping
Users carry one of four roles:admin, merchant, merchant_manager and
user. The management endpoints documented here require merchant. A valid
session without that role gets 403 FORBIDDEN.
Scoping is implicit and worth understanding: the API resolves your organization
from your session and filters everything by it. You never pass an organization
id, and you cannot read another organization’s stations or sessions by guessing
an id. A resource that exists but belongs elsewhere answers as not found.
Errors
Errors always come back in the same shape, with a machine-readabletype you
can branch on.
attributes object with extra context. Failed OCPP
commands use it to explain what the station said:
type, never on message. Messages are written for humans and may be
reworded; types are part of the contract.
Errors you will meet everywhere
Errors specific to commands
Command endpoints talk to hardware over the network, so they fail in ways a normal CRUD endpoint does not. Handling these three well is most of what makes an integration feel solid.The station is not connected
The station is not connected
CHARGING_STATION_OFFLINE. The station has no live OCPP session, so the
command cannot be delivered at all. Chargers drop and reconnect routinely,
so treat this as a normal condition, not an incident.The station did not answer in time
The station did not answer in time
CHARGING_STATION_COMMAND_TIMEOUT. The frame was delivered but no reply
arrived within the window. The command may still have taken effect on the
charger, so prefer reading the resulting state over blindly retrying.The station refused
The station refused
CHARGING_STATION_COMMAND_FAILED. The charger answered with an error.
attributes carries its reason, which is usually the fastest way to tell a
firmware limitation from a bad request.Lists, pagination and sorting
Every list endpoint is aPOST to /search. It reads as unusual for a read
operation, but it keeps rich filters in a JSON body instead of a long and
ambiguous query string.
Pagination and sorting are the same everywhere:
perPage defaults to 25 and is capped at 150. Filters sit alongside these keys
at the top level of the body, not nested under a filters object.
The response splits results from metadata, so a table can render its pager
without a second call:
Filters by endpoint
Each search accepts its own filters on top of the shared pagination keys:
Log search is the richest of them, and
excludeEventTypes is the one worth
knowing about: stations emit a great deal of Heartbeat and MeterValues
traffic, and excluding those is usually the difference between a readable log
and a wall of noise.
Dates and units
Timestamps are ISO 8601 strings in UTC, both in and out. The dashboard endpoint acceptsutcOffsetMinutes so a client can bucket a time series by local days
without shifting the data itself.
Energy is expressed in kWh. Stations report meter readings in Wh or kWh
depending on the vendor, and the CSMS converts on the way in, so you never have
to guess which unit a number is in.