Skip to main content
Identity is per message, not global config. One process can serve thousands of chargers or dozens of roaming partners, so the SDK asks who a message belongs to at capture time. There are two shapes.

Platform (OCPI)

The roaming partner on the other side of the exchange.
Identity is always the partner on the other side, never your own platform, in both directions. When a partner pushes you a CDR, it is their identity. When you pull their locations, it is still their identity.

Charger (OCPP)

The charge point an event belongs to.
OCPP identity is known at the WebSocket handshake, so you resolve it once per connection and the session handle carries it for every frame.

Tenants

tenantId and tenantName say which of your tenants an exchange belongs to. They are a property of your deployment, not of the partner or charger, which is why they keep the prefix that id and name do not need. They are optional but all or nothing. Supply both or neither; a half set pair fails validation and the message is dropped. Use them when one deployment serves several operators: a CPO platform hosting sub-operators, a white label CSMS, a hub carrying several parties. The dashboard filters chargers, platforms, messages, and issues by tenant.
Send a tenant pair on OCPP even with one operator. The ingestion API currently requires tenant_id and tenant_name on OCPP messages, and rejects those that omit them after a successful delivery, so nothing in the SDK reports the loss. A constant value such as your own operator name works.OCPI does not have this problem: there the pair is genuinely optional.

Choosing identifiers

  • Use the ID your systems already use. A charger ID should be the same string your CSMS, your support tooling, and your field team all say. Usually that is the OCPP identity from the WebSocket URL path.
  • Keep IDs stable, keep names readable. id groups your data over time and must not change for the same entity. name is a display string and can be updated freely; EVPanda shows the most recent one it saw.
  • Never put secrets in identity fields. They are stored and displayed. Do not pass a token or a certificate fingerprint as an ID.
  • Mind the limits. The ingestion API rejects a message whose tenant name exceeds 32 characters, or whose other identity fields exceed 64.

Invalid identity

The SDK validates identity at capture, before anything is buffered. A message that fails is dropped silently. It is not queued, not sent, and never raises into your code. An identity is invalid when a required field is empty or whitespace only, or when exactly one of the tenant fields is set. Dropping is deliberate: an unattributable message would arrive as an orphan nobody can search for. It is also the most common reason for “the SDK is not sending anything”, so every SDK counts it. The invalid-identity counter from stats() confirms it. See Getting started. Go and Python expose a validity check you can call yourself: