Charger management

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:

FieldMeaning
station_idStation resource ID
station_sequenceIncreases by one with every event of this station. Order one station's events by it; webhooks may arrive out of order
occurred_atThe 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

TypeWhenresource_iddata
station.connectedThe station's connection to Ivora opensstationstation_id, online, last_seen (time of its last OCPP message)
station.disconnectedThe connection closesstationas above
station.bootedThe charger sends a BootNotificationstationboot_status (Accepted, Pending, Rejected), booted_at, protocol, vendor, model, serial, firmware_version
connector.status_changedA connector's normalized status changesconnectorconnector_id, evse_number, status, previous_status, ocpp_status, error_code
station.fault_openedA status notification reports a faultfaultfault_id, connector_id, evse_number, error_code, info, vendor_id, vendor_error_code, ocpp_status, opened_at, cleared_at (null)
station.fault_clearedA later notification for the same connector no longer reports itfaultthe same fields, with cleared_at
meter.sampledA charger reports meter values during a transactiontransactionsee 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.

EndpointPurposeScope
GET /v1/tenants/{tenant_id}/stations/{station_id}/faultsOpen 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_faultsstations:read

Cleared faults are kept for 90 days.

Meter samples

meter.sampled reports one meter reading of a transaction:

FieldMeaning
transaction_idTransaction resource ID, as in GET …/transactions
transaction_referenceThe charger's own transaction identifier
connector_idConnector resource ID
sampled_atThe charger's timestamp of the reading
energy_kwh, energy_whEnergy import register as a decimal kWh string and integer Wh
power_kwActive import power, decimal string
current_a, voltage_vCurrent and voltage, decimal strings
soc_percentVehicle state of charge, when reported
contextOCPP 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>.