Skip to main content
The SDK records two things, one per protocol: OCPP events on a WebSocket connection, and OCPI HTTP exchanges with a roaming partner. Everything the dashboard shows is derived from these two records.

OCPP events

An OCPP capture is one of three event types, all carrying the same charger identity and connection ID.

Connections tie the events together

Every OCPP event carries a connection ID: an SDK-minted identifier that is stable for the lifetime of one WebSocket and fresh on every reconnect. It is what turns a stream of frames into a session you can read top to bottom. A charger that reconnects gets a new connection ID, which is exactly what you want: the dashboard can then show that a charge point flapped twenty times in an hour, instead of one endless session.

Direction is from the charge point’s perspective

Getting these backwards makes every request look like a response, so the validation engine flags traffic that makes no sense. Record the direction at the point of the actual socket read or write.

Frames are stored verbatim

Frames are captured as raw bytes, exactly as they crossed the wire. Nothing is reformatted, reordered, or stripped, so what you see in the dashboard is what your charge point actually sent.
There is no OCPP redaction. If your payloads carry data you don’t want stored — an idTag you consider personal, for example — mask it before you hand the frame to the SDK.

OCPI exchanges

An OCPI capture is one complete HTTP request/response pair, plus its direction.
The SDKs let you omit statusCode, but the ingestion API requires a value between 100 and 599 and rejects the message without one — after a successful delivery, so nothing in the SDK reports the loss. Record the status your service actually returned, or skip the capture entirely for an exchange that never produced a response.

Direction is from your perspective

OCPI is symmetric — you are a server to your partners and a client to them — so each exchange records which side you were on. There is no direction argument to get wrong: the method you call sets it.

Redaction happens before buffering

Redaction runs at the capture chokepoint — the last moment before a message enters memory that outlives the call. Nothing unredacted is ever buffered, so nothing unredacted can be delivered, logged, or recovered from a crash dump.

OCPI: the header allowlist

OCPI headers are filtered by an allowlist, not a denylist. Only the headers below are captured; everything else — including Authorization, Cookie, and X-API-Key — is dropped at capture and never reaches the buffer. Matching is case-insensitive. The list can be extended through ocpiAllowedHeaders, never shrunk — the defaults are always kept, so you cannot configure your way into leaking Authorization. See OCPI server.
Only add headers you are certain carry no secret. An allowlisted header is stored and displayed in the dashboard exactly as it arrived.

OCPI: credentials tokens are masked

The OCPI /credentials module exchanges the tokens partners use to authenticate against each other. Those exchanges are worth capturing — registration failures are a classic roaming problem — but the tokens themselves are not. On any URL ending in /credentials, the SDK replaces the token field with [redacted], in both the request body and the data object of the response envelope:
Captured
If the body isn’t JSON, or has no token at either known location, it is captured unchanged — masking never silently drops data it couldn’t safely rewrite.

Size limits

Dropping rather than truncating is deliberate: a body cut in half validates as broken and would generate issues that describe the SDK, not your traffic. Raise the per-capture cap if you routinely exchange large OCPI location or CDR payloads.

What the SDK does not capture

Capture is explicit. The SDK patches no globals, hooks no sockets, and monkey-patches nothing. A frame you never pass to it does not exist as far as EVPanda is concerned — which is also how you exclude traffic on purpose.
Authorization, Cookie, X-API-Key, and every other unlisted header are dropped at capture, before the message reaches the buffer.
A body or frame larger than the per-capture cap drops the whole message rather than storing a truncated one.
TLS handshakes, WebSocket ping/pong frames, TCP resets, and HTTP retries inside your own client are not protocol messages, and the SDK has no visibility into them. What it sees is what your application layer sees.
An outbound OCPI call that fails at the transport layer — DNS failure, connection refused, timeout — has no exchange to record. A response you receive and then never read is also never shipped, since the adapters complete capture when the body is closed.

Transport

Encrypted in transit

Batches are POSTed over HTTPS to ingest.evpanda.io. The API key travels in the X-API-Key header and is never placed in a URL.

Compressed by default

Bodies are compressed with zstd, or gzip if you prefer. Payloads below about 1 KB are sent uncompressed.

Outbound only

The SDK opens connections to EVPanda; EVPanda never connects to you. No control channel, no remote configuration, no callback into your process.

Egress allowlisting

Behind an egress firewall, ingest.evpanda.io on port 443 is the only destination the SDK needs.

Timestamps

The SDK stamps the capture time in your process, using the host clock. EVPanda normalizes it to UTC with millisecond precision on arrival. Message ordering in the dashboard therefore follows your clock, not the ingestion server’s — which is what you want when correlating with your own logs, and a reason to keep NTP healthy on the hosts running your CSMS.

Retention

Captured messages are retained for 90 days by default, then deleted. Issues and the entities discovered from your traffic — chargers, platforms, tenants — persist beyond the raw messages they were derived from. If your policy needs a different window, contact support@evpanda.io.
Decide what you are allowed to send before you go to production. OCPI bodies can contain CDRs and tokens; OCPP frames can contain RFID identifiers. Both may be personal data under your jurisdiction. Review a real captured message in staging with whoever owns privacy at your company before you point the SDK at production traffic.