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.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 — includingAuthorization, 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.
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
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
Anything you don't hand it
Anything you don't hand it
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.
Headers outside the OCPI allowlist
Headers outside the OCPI allowlist
Authorization, Cookie, X-API-Key, and every other unlisted header are dropped at capture, before the message reaches the buffer.Bodies over the size cap
Bodies over the size cap
A body or frame larger than the per-capture cap drops the whole message rather than storing a truncated one.
Transport-level events
Transport-level events
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.
Requests that never completed
Requests that never completed
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.