Charger events
Subscribe to what your chargers do (connectivity, boots, connector status, faults and meter readings) as stable, protocol-independent events. OCPP 1.6 and OCPP 2.0.1/2.1 chargers produce the same event types and fields, addressed by station and connector resource IDs, never OCPP connector numbers. The events use the tenant event log and webhooks, so cursor replay, signatures and retries work exactly as for other events.
How events are produced
Ivora reads the charging core's records (status notifications, connectors, boots, the stations' online state and meter values) about every 15 seconds and appends what changed to your tenant's event log. Each sweep reads a bounded batch, so a backlog of readings is worked off over several sweeps rather than delaying other deliveries. Ivora never writes to the charging core for these events.
- Events start when the observer first runs: earlier charger history is not replayed.
- Connectivity comes from the core's online state. A disconnect and reconnect that both happen between two sweeps is not reported, although the charger's reboot, if any, still is.
- A restart of the API neither repeats nor skips events in the log: the events
and the position they were read up to are stored together. Webhook delivery
remains at-least-once, so deduplicate by event
id.
Event shape
Every charger event has the usual id, sequence, type, tenant_id,
resource_id, created_at and data, plus:
| Field | Meaning |
|---|---|
station_id | Station resource ID |
station_sequence | Increases by one with every event of this station. Order one station's events by it; webhooks may arrive out of order |
occurred_at | The charger's own timestamp, when it sent one (null for connectivity) |
created_at is when Ivora recorded the event. Read scope for every type below
is stations:read.
Event types
| Type | When | resource_id | data |
|---|---|---|---|
station.connected | The station's connection to Ivora opens | station | station_id, online, last_seen (time of its last OCPP message) |
station.disconnected | The connection closes | station | as above |
station.booted | The charger sends a BootNotification | station | boot_status (Accepted, Pending, Rejected), booted_at, protocol, vendor, model, serial, firmware_version |
connector.status_changed | A connector's normalized status changes | connector | connector_id, evse_number, status, previous_status, ocpp_status, error_code |
station.fault_opened | A status notification reports a fault | fault | fault_id, connector_id, evse_number, error_code, info, vendor_id, vendor_error_code, ocpp_status, opened_at, cleared_at (null) |
station.fault_cleared | A later notification for the same connector no longer reports it | fault | the same fields, with cleared_at |
meter.sampled | A charger reports meter values during a transaction | transaction | see meter samples |
station.booted never contains the SIM's ICCID or IMSI. serial is the same
value as the station resource's serial.
Connector status
status is one of Available, Preparing, Charging, SuspendedEV,
SuspendedEVSE, Finishing, Reserved, Unavailable or Faulted. OCPP 1.6
statuses map one to one. OCPP 2.x reports Occupied for every in-use state; it
becomes Charging while the connector has an active transaction and
Preparing otherwise. Any other value reads as Unavailable. ocpp_status
keeps what the charger sent. previous_status is null for the first change
Ivora observes on a connector. Repeated notifications with the same status
produce no event.
Faults
A fault opens when a status notification carries an OCPP 1.6 errorCode other
than NoError, or the status Faulted (OCPP 2.x has no error code, so
error_code is null there). It stays open until a later notification for the
same connector reports no error; that notification clears it with the same
fault_id. A different error code on the same connector clears the open fault
and opens a new one. Faults reported for the whole station (OCPP 1.6 connector
0, OCPP 2.x EVSE 0) have connector_id null.
| Endpoint | Purpose | Scope |
|---|---|---|
GET /v1/tenants/{tenant_id}/stations/{station_id}/faults | Open and recent faults, newest first. open=true returns open ones only; pass next_cursor as before for the next page (null on the last) | stations:read |
GET /v1/tenants/{tenant_id}/stations/{station_id} | The station's open_faults | stations:read |
Cleared faults are kept for 90 days.
Meter samples
meter.sampled reports one meter reading of a transaction:
| Field | Meaning |
|---|---|
transaction_id | Transaction resource ID, as in GET …/transactions |
transaction_reference | The charger's own transaction identifier |
connector_id | Connector resource ID |
sampled_at | The charger's timestamp of the reading |
energy_kwh, energy_wh | Energy import register as a decimal kWh string and integer Wh |
power_kw | Active import power, decimal string |
current_a, voltage_v | Current and voltage, decimal strings |
soc_percent | Vehicle state of charge, when reported |
context | OCPP reading context such as Sample.Periodic or Transaction.End |
Fields the charger did not report are null. Values are decimal strings so
that no precision is lost. OCPP energy registers default to Wh; Ivora
converts them to kWh exactly (6941 Wh becomes "6.941" kWh) and applies the
unit multiplier. A charger reporting kWh is passed through. Where only per-phase
values exist, energy and power are summed over L1-L3, current_a is the highest
phase current and voltage_v the average phase voltage.
The event log keeps at most one sample per transaction every 10 seconds, and
keeps meter.sampled events for 7 days (other events are kept). Each
webhook endpoint then receives at most one sample per transaction every
meter.sample_interval_seconds (default 60, minimum 10). A transaction's first
(Transaction.Begin) and last (Transaction.End) readings are always
delivered.
Subscribing
POST /v1/tenants/7/webhooks with:
{
"url": "https://app.example.com/ivora/webhooks",
"events": ["connector.status_changed", "station.fault_opened", "station.fault_cleared", "meter.sampled"],
"stations": [12, 13],
"meter": {"sample_interval_seconds": 30}
}
stations limits station, connector, fault and meter events to those stations;
omit it for every station. It does not affect other event types. Both filters
apply to webhook deliveries only. To recover or poll, read the log with
GET /v1/tenants/{tenant_id}/events?type=meter.sampled&station_id=12&after=<cursor>.