Everything shared across protocols — installing the SDK, getting an API key, configuration, monitoring, shutdown — is in Getting started. This page is the OCPI-specific part.
The model
The direction is never something you pass. It follows from the method you call.Where identity comes from
Your OCPI server already knows who is calling: you looked the partner up by their Token A or Token B to decide whether to serve the request at all. That lookup is your identity source. The order matters. Adapters resolve identity once per request, so they must run after whatever authenticates the partner. Mounted the other way around, no request has an identity yet, every message is dropped, and you see nothing in the dashboard.A request with no resolvable identity is served exactly as it would have been. The adapters never block, alter, or fail a request on EVPanda’s account — they simply don’t capture it.
What ships per language
The Go middleware is the stdlib shape, so it drops into net/http, chi, and gorilla/mux directly and into echo and gin through their wrappers. The Node express adapter is typed against
node:http, so it works on connect too, with no express dependency.
For anything else — koa, hono, fastify, FastAPI, Django — skip the adapter and call the capture methods yourself. It is a few lines, and you hand the identity over directly instead of resolving it.
Integration steps
1
Start one client at boot
2
Teach the SDK how to find the partner
Each SDK has its own hook into your existing partner lookup.Returning nothing — or an identity that fails validation, such as an empty platform name — means the exchange is not captured. The request itself is never blocked.
3
Capture inbound traffic
Mount capture after your auth layer.The Go middleware records the request body as your handler reads it, tees the response on its way out, and ships one message when the handler returns — including when the handler panics, so the exchange that broke your server is still recorded.
4
Capture outbound traffic
Instrument the HTTP client your OCPI calls actually go through.
A complete example
- Go
- Node
- Python
server.go
false means “don’t capture this one”.Per-SDK notes
Go — prefer the context over headers
Go — prefer the context over headers
The default resolver reads the request context first, then falls back to
X-EVPanda-* headers. The context is the better hook: it keeps identity out of the HTTP layer entirely and can’t be spoofed by a partner who guessed the header names.The round tripper’s only change to your request is stripping those four headers before dispatch, so a partner never receives them — your tenant names stay internal.Node — mount a body parser first
Node — mount a body parser first
The express adapter reads the request body from
req.body rather than teeing the raw stream: a data listener would flip the stream to flowing mode and could starve your own parser. Without a parser, exchanges are captured with no request body.express.raw() gives you the exact bytes off the wire; express.json() gives a re-serialized form, which is usually fine and occasionally differs in key order or whitespace.Node — axios and fetch are separate worlds
Node — axios and fetch are separate worlds
In Node, axios goes through
node:http and never fetch. Wrapping one captures nothing from the other. Instrument whichever client your OCPI calls actually use, or both.Python — no adapters yet
Python — no adapters yet
Build the
HttpExchange yourself, as shown above. The capture methods are a stable API; the adapters, when they land, will be a convenience on top of them.For httpx, an event hook on response also works, as long as you call await response.aread() first. A wrapper function is easier to reason about and gives you one obvious place to attach identity.The X-EVPanda-* headers
The X-EVPanda-* headers
Every SDK’s default resolver understands the same four headers, matched case-insensitively — they exist so a host can stamp identity in middleware it already has, without writing a resolver.
Partners never send them and never receive them: the outbound adapters strip all four before dispatch.
Capturing without the adapters
When no adapter fits — koa, hono, fastify, a message queue, a replay tool — build the exchange yourself. Both methods take an identity and an HTTP exchange; the method name sets the direction.captureOutboundMessage is the same call for the other direction. Both are non-blocking and never raise back at you.
Capture extra headers
OCPI headers pass through an allowlist, soAuthorization, Cookie, and everything else unlisted is dropped at capture. The list can be extended, never shrunk.
Common mistakes
Next
What gets captured
The exchange shape, the header allowlist, and credentials masking.
Getting started
Configuration, monitoring, shutdown, and troubleshooting.