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

Core concepts

The vocabulary covered the words OCPP gave us. This page covers the ones we added, and how they nest.

Every API call is scoped by some part of this hierarchy, so it is worth getting straight before you write anything.

Organization                    the account. Billing and membership.
 └─ Environment                 the isolation boundary. prod, staging, dev.
     ├─ Site                    a physical location.
     │   └─ Circuit             the electrical tree feeding it.
     └─ Charger                 a physical charging station.
         └─ EVSE                can charge one vehicle at a time.
             └─ Connector       a single socket or tethered cable.

The top four are ours. The bottom three are OCPP's — see How Flowion maps onto OCPP.

Organization#

The root of everything, and the unit of billing and membership. An organization's bill is the sum of usage across all of its environments; there is no separate billing per environment.

It has a name (free-form, for humans) and a slug — a URL-safe identifier you choose, not derived from the name. Slugs are lowercase alphanumeric segments joined by single hyphens, 1–63 characters: a DNS label. They are globally unique, and they appear in every charger's connection URL, so pick one you can live with.

Creating an organization does three things at once: it creates the organization, creates a default environment named prod, and makes you its Owner.

Environment#

An environment groups a fleet within an organization — prod, staging, dev, or anything else. Names are free-form; nothing is special-cased.

Environments are the isolation boundary. This is the concept to reach for when you think "tenant". Chargers, sites, transactions and authorization tokens all belong to exactly one environment, and access is granted per environment. An organization is a grouping above that line, not itself a wall.

Exactly one environment per organization is the default at any time. It is usually prod, but that is convention rather than a rule, and the default is what a charger connects to when its URL names no environment.

An environment slug is unique only within its organization, so two organizations may both have a staging.

Environments also carry two settings that matter for anything time- or price-aware: a price zone (an ENTSO-E bidding zone, for day-ahead electricity prices) and a time zone (an IANA name like Europe/Stockholm, the zone an operator reads timestamps in). Both may be unset.

Environments goes into how to use them.

Charger#

A charger is one physical charging station, belonging to exactly one environment.

It has a charge point id — the identity the station itself uses on the wire, and the last segment of its connection URL. This is unique per environment, not globally: two environments, even in different organizations, may both contain a charger called CP-01. Everything inside the platform therefore addresses a charger by its UUID, never by its charge point id; the string only appears at the two edges, in the connection URL and in OCPP messages themselves.

Provisioning a charger returns an authorization key — the password half of its credentials, a 40-character hex string. It is returned exactly once. Only an Argon2id hash is stored, so there is no way to read it back; if you lose it, rotate it and configure the station with the new one.

A charger carries two different notions of "is it working":

FieldMeans
statusonline / offline — whether some gateway currently holds its socket
last_seenThe last time it communicated at all
registration_statusAccepted / Pending / Rejected — whether you permit it to operate
ocpp_versionWhat it actually negotiated on connect

status is a cache, not a source of truth: a gateway killed without unwinding can leave a stale row behind, so online can briefly lag reality. last_seen is the durable complement — use it to judge whether a suspiciously long-lived connection is real.

registration_status is a decision you own, not something derived from the station's behaviour. It defaults to Accepted; moving a charger to Pending or Rejected is how you withhold acceptance. Be careful with Rejected — see Lifecycle of a charging session for what it does to a station.

EVSE and Connector#

These come straight from OCPP and are covered in The vocabulary. The short version: an EVSE can charge one vehicle at a time; a connector is one physical socket. A station with two cables sharing one power module is one EVSE with two connectors.

You do not create these. They appear as chargers report themselves, which is why a freshly provisioned charger has none until it connects.

Site#

A site is a physical location — a depot, a car park, a building. It nests under an environment, not under an organization directly, because environment is the isolation boundary and a site is a grouping within it.

A site has no effect on how a charger connects. It is a data-model grouping, not a routing concept. OCPP itself has an equivalent idea, "Charging Location", and explicitly gives it no protocol meaning.

Like environments, a site can carry its own price zone and time zone, which is what you want when one environment spans countries.

Circuit#

A circuit is the electrical wiring chargers hang off. This is the concept that makes load management possible, and it has no equivalent in OCPP at all.

Circuits form a tree per site:

  • A circuit with no parent is a Main circuit — the connection to the grid. Main is only legal at the top of a site's tree.
  • Every other circuit has a parent, and represents a subdivision of it.

Each circuit records a phase count (1 or 3) and a rated current in amps. A single-phase circuit also records which of the site's three grid lines it is wired to — L1, L2 or L3 — because nested single-phase circuits have to be capacity-checked per line. An aggregate watt figure would hide a single-line overload. Voltage is a fixed 230 V per phase rather than a stored value.

Two invariants are enforced on write, not merely checked at read time:

  1. A child's lines must be a subset of its parent's. A single-phase parent can only host single-phase children on the same line.
  2. The sum of a parent's immediate children's rated current, per line, must not exceed the parent's own rating on that line.

Which means it is not possible to persist a circuit tree that oversubscribes its own wiring. Expect a write that would break either rule to be rejected.

Circuit membership is per-EVSE, not per-charger. A multi-EVSE charger can have its EVSEs on different circuits, because they draw independently.

Transaction#

One charging session: one vehicle, one EVSE, one continuous visit. Covered in Lifecycle of a charging session.

Transactions are recorded as an event log — a Started event, any number of Updated events, and an Ended event — with meter readings hanging off them. Energy delivered is derived from the readings, not stored as a field.

Id token#

A credential a driver presents: an RFID card, a key code, an app-issued token. Id tokens live in an environment's authorization registry, which is what the CSMS consults when a station asks whether someone may charge.

An id token identifies a credential, not a person. Mapping tokens to accounts, customers or invoices is your business logic.

Members and roles#

Users belong to organizations, and each membership carries exactly one role. On the wire the values are lowercase: owner, admin, user.

OwnerAdminUser
Operate chargersall environmentsall environmentsgranted environments only
Create and manage environments
Provision chargers, manage credentials
Manage members and access grants✅ (not the Owner)
Billing

There is exactly one Owner per organization, assigned when the organization is created. Adding a member with role owner is rejected, and there is no transfer operation yet.

Owners and Admins implicitly reach every environment. A member with role user reaches only the environments explicitly granted to them — which is the mechanism for "this contractor can touch staging but not prod".

How this shapes the API#

Two patterns follow from the hierarchy, and they explain most endpoint shapes:

Creation is scoped to the parent. You create an environment under an organization, a charger under an environment, a circuit under a site.

Reads by id are flat. Once something exists it has a UUID, and you fetch it directly — /v1/chargers/{id}, /v1/sites/{id} — without repeating its ancestry. Authorization still resolves the whole chain behind the scenes, but you do not have to spell it out.

The API reference has every endpoint.