Integration guides

OCPI handshake cookbook

A 10-step hand-rail for OCPI 2.2.1 peers (third-party CPOs + eMSPs) onboarding with the PixellEnergy CSMS. Walks the canonical Token A → Token B → Token C state machine, the IN-PXE / IN-PXM dual-role pattern, the six data modules at v1, and the revoke / rotate surfaces that keep the peer relationship operationally healthy.

1.Audience and prerequisites

This cookbook is for OCPI peers — third-party CPOs and eMSPs — establishing a roaming relationship with the PixellEnergy platform under OCPI 2.2.1 §7 (Credentials and Registration). Familiarity with OCPI module semantics is assumed; the cookbook walks the PixellEnergy-specific decisions only.

You will need, before you start:

  • A peer party_id (3 chars) + country_code (ISO 3166-1 alpha-2) issued by your roaming registry.
  • HTTPS-reachable endpoints implementing the OCPI 2.2.1 surface for each module you intend to enable (minimum: /versions + /credentials + at least one data module).
  • A bootstrap Token A issued out-of-band by PixellEnergy.
  • Operations contact + DPO contact (per OCPI 2.2.1 BusinessDetails and PixellEnergy's DPDP framework).

2.PixellEnergy is a dual-role platform (IN-PXE + IN-PXM)

PixellEnergy operates as BOTH a CPO and an eMSP under separate party_ids on one platform:

FieldTypeRequiredNotes
IN-PXECPOrequiredPixellEnergy as charge-point operator — owns the physical infrastructure tenants connect via OCPP.
IN-PXMEMSPrequiredPixellEnergy as e-mobility service provider — issues driver tokens, settles roaming sessions on behalf of subscribers.

During the handshake response, PixellEnergy returns BOTH role entries in the roles[] array. If you only intend to roam with one of the two roles, you still receive both — the OCPI 2.2.1 spec allows you to ignore the unused role. Your own peer credentials row will list one or both of your roles depending on your business model.

3.Token A — bootstrap exchange (out-of-band)

Token A is the bearer the peer presents on the FIRST request to the PixellEnergy CSMS. It is issued out-of-band — via secure email to your DPO contact, or via the tenant-admin portal at /admin/ocpi-peers. Token A has a 30-day TTL after which it is invalidated even if unused.

Once you have Token A, the handshake state machine begins. The full sequence (per OCPI 2.2.1 §7 + the production reference at packages/api/src/ocpi/credentials.ts):

OCPI 2.2.1 handshake sequence (ASCII)
Peer (CPO/eMSP)                            PixellEnergy CSMS
      |                                          |
      |  (1)  Token A issued out-of-band (email/portal) ──────────►
      |                                          |
      |  (2)  GET  /ocpi/2.2.1/versions          |
      |       Authorization: Token <TOKEN_A>     |
      |  ────────────────────────────────────────►
      |       200 OK { versions: [2.2.1] }       |
      |  ◄────────────────────────────────────────
      |                                          |
      |  (3)  POST /ocpi/2.2.1/credentials       |
      |       Authorization: Token <TOKEN_A>     |
      |       body: { token: <YOUR_TOKEN_B>, .. }|
      |  ────────────────────────────────────────►
      |       200 OK { token: <PXE_TOKEN_B>, .. }|  (Token A invalidated)
      |  ◄────────────────────────────────────────
      |                                          |
      |  (4)  PUT  /ocpi/2.2.1/credentials       |
      |       Authorization: Token <PXE_TOKEN_B> |
      |       body: { token: <YOUR_TOKEN_C>, .. }|
      |  ────────────────────────────────────────►
      |       200 OK { token: <PXE_TOKEN_C>, .. }|  (Token B invalidated · status=ACTIVE)
      |  ◄────────────────────────────────────────
      |                                          |
      |  (5+) Module calls (locations, sessions, |
      |       cdrs, tariffs, tokens, commands)   |
      |       Authorization: Token <PXE_TOKEN_C> |
      |  ◄═════════════════════════════════════►

4.Discover modules via GET /versions

With Token A in hand, your first call is GET /ocpi/2.2.1/versions. This is the deliberate shape of OCPI — peers exchange a list of supported versions so a future v2.3 / v3.0 upgrade is non-breaking for older peers.

Shell
curl -X GET 'https://api.pixellenergy.com/ocpi/2.2.1/versions' \
  -H 'Authorization: Token <TOKEN_A>' \
  -H 'X-Request-ID: req-<your-ulid>'
Response
JSON
{
  "data": [
    {
      "version": "2.2.1",
      "url": "https://api.pixellenergy.com/ocpi/2.2.1"
    }
  ],
  "status_code": 1000,
  "status_message": "Success",
  "timestamp": "2026-05-18T08:00:00Z"
}

The PixellEnergy CSMS only supports 2.2.1 today. The detailed per-version module list is reached by GET /ocpi/2.2.1 — see the API reference for the module-endpoint matrix.

5.POST /credentials — exchange Token A for Token B

The peer presents Token A in the Authorization header and YOUR freshly-minted Token B in the body. PixellEnergy creates an ocpi_credentials row (status: PENDING) holding YOUR Token B (vaulted) plus a freshly-minted PixellEnergy Token B which it returns in the response — this is the bearer PixellEnergy expects when YOU call IT.

Shell
curl -X POST 'https://api.pixellenergy.com/ocpi/2.2.1/credentials' \
  -H 'Authorization: Token <TOKEN_A>' \
  -H 'Idempotency-Key: ocpi-handshake-<your-ulid>' \
  -H 'Content-Type: application/json' \
  -d '{
    "token": "<YOUR_TOKEN_B_FOR_INBOUND_CALLS>",
    "url": "https://your-peer.example.com/ocpi/2.2.1/versions",
    "roles": [
      {
        "role": "CPO",
        "business_details": { "name": "Your CPO Name" },
        "party_id": "ABC",
        "country_code": "IN"
      }
    ]
  }'
Response (PixellEnergy mints its own Token B for inbound use)
JSON
{
  "data": {
    "token": "<TOKEN_B_FROM_PIXELLENERGY>",
    "url": "https://api.pixellenergy.com/ocpi/2.2.1/versions",
    "roles": [
      {
        "role": "CPO",
        "business_details": { "name": "PixellEnergy" },
        "party_id": "PXE",
        "country_code": "IN"
      },
      {
        "role": "EMSP",
        "business_details": { "name": "PixellEnergy" },
        "party_id": "PXM",
        "country_code": "IN"
      }
    ]
  },
  "status_code": 1000,
  "status_message": "Success",
  "timestamp": "2026-05-18T08:00:01Z"
}
POST /credentials request body
FieldTypeRequiredNotes
tokenstringrequiredYOUR Token B — the bearer the CSMS will present when calling YOUR endpoints. Generate via a CSPRNG; ≥ 16 bytes; URL-safe base64.
urlstring (uri)requiredAbsolute URL of YOUR /versions endpoint. Must be HTTPS in production; HTTP rejected at PUT.
rolesarray<Role>requiredEach role declares (role, party_id, country_code, business_details). For dual-role peers, list both CPO + EMSP rows.
roles[].party_idstring(3)requiredUppercase 3-char identifier issued by your roaming registry.
roles[].country_codestring(2)requiredISO 3166-1 alpha-2; e.g. IN, US, DE. Used together with party_id as the composite peer key.

6.PUT /credentials — promote Token B to Token C

With BOTH parties holding the other's Token B, the peer comes back with PUT — presenting PixellEnergy's Token B in the Authorization header and YOUR Token C in the body. PixellEnergy rotates its end to YOUR Token C, mints + returns its own Token C, and flips the peer row's status to ACTIVE. Token B is now invalidated on both sides.

Shell
curl -X PUT 'https://api.pixellenergy.com/ocpi/2.2.1/credentials' \
  -H 'Authorization: Token <TOKEN_B_FROM_PIXELLENERGY>' \
  -H 'Idempotency-Key: ocpi-token-c-<your-ulid>' \
  -H 'Content-Type: application/json' \
  -d '{
    "token": "<YOUR_TOKEN_C_FOR_INBOUND_CALLS>",
    "url": "https://your-peer.example.com/ocpi/2.2.1/versions",
    "roles": [
      {
        "role": "CPO",
        "business_details": { "name": "Your CPO Name" },
        "party_id": "ABC",
        "country_code": "IN"
      }
    ]
  }'

7.Module enablement

With Token C exchanged, both sides MAY now call any of the OCPI 2.2.1 modules. PixellEnergy ships the following at v1:

OCPI 2.2.1 modules supported
FieldTypeRequiredNotes
locationsCPO sender · eMSP receiverrequiredPixellEnergy pushes the IN-PXE charge-point catalogue. Pull-by-eMSP supported as fallback.
sessionsCPO sender · eMSP receiverrequiredRealtime session updates while active.
cdrsCPO sender · eMSP receiverrequiredFinalised charge-detail records, with SignedMeterValue for OCPP 2.0.1-driven sessions.
tariffsCPO sender · eMSP receiverrequiredKSERC-aware ToD tariffs with GST SAC 998714.
tokenseMSP sender · CPO receiveroptionalRequired if you are an eMSP issuing driver tokens redeemable at PixellEnergy IN-PXE stations.
commandseMSP sender · CPO receiveroptionalRemote start/stop on behalf of subscribed drivers. Subject to per-tenant rate limit.

Each module call MUST present Token C as the bearer and SHOULD include an X-Request-ID header for correlation in support tickets.

8.Inbound + outbound flow patterns

OCPI is bidirectional. PixellEnergy publishes to YOUR endpoints (CPO → eMSP locations push; eMSP → CPO tokens push) and accepts inbound calls from your endpoints (eMSP → CPO commands; CPO → eMSP CDRs pull). The retry policy on PixellEnergy's outbound worker:

FieldTypeRequiredNotes
first attemptt+0requiredSync, on the producing event handler thread.
retry 1t+30srequiredOn 5xx / network timeout / 429.
retry 2t+5minrequiredSame conditions.
retry 3t+30minrequiredFinal retry before DLQ.
DLQmanual replayrequiredSurfaced in the operator portal at /operations/ocpi-dlq for super_admin review + targeted replay.

9.Revoke + rotate credentials

The OCPI 2.2.1 spec is sparse on credential rotation; PixellEnergy ships explicit super_admin admin routes (Wk 15 D4 + Wk 16 D2) that a tenant can use to revoke or rotate a peer's Token C without a full TERMINATE + new-onboarding cycle.

Revoke (per-peer; effective immediately)
Shell
curl -X POST 'https://api.pixellenergy.com/v1/ocpi/peers/IN-ABC/revoke' \
  -H 'Authorization: Bearer <your-super-admin-jwt>' \
  -H 'Idempotency-Key: ocpi-revoke-<your-ulid>' \
  -H 'Content-Type: application/json' \
  -d '{
    "country_code": "IN",
    "reason": "Peer migrated to a new party_id; rotating per OCPI 2.2.1 §4.4.5."
  }'
Rotate (mints a new Token C; old Token C kept valid for a 24h grace window)
Shell
curl -X POST 'https://api.pixellenergy.com/v1/ocpi/peers/IN-ABC/credentials/rotate' \
  -H 'Authorization: Bearer <your-super-admin-jwt>' \
  -H 'Idempotency-Key: ocpi-rotate-<your-ulid>' \
  -H 'Content-Type: application/json' \
  -d '{
    "country_code": "IN"
  }'

10.Settlement statements

Monthly OCPI settlement statements roll up CDRs published by the CPO + tokens consumed by the eMSP into a single per-peer settlement file. PixellEnergy emits the statement on the 5th of each month for the prior month's roaming activity, signed with PixellEnergy's GPG key and delivered to the BusinessDetails contact email on the peer row.

Disputes are surfaced via POST /v1/ocpi/peers/<party_id>/disputes with a reason + the disputed CDR set. PixellEnergy's settlement worker (BR-RC) responds within 5 business days with one of: confirmed (counter-signed), partial (with revised line items), or rejected (with rationale + audit references).

11.Compliance and reconciliation expectations

  • Reconcile your CDR ledger against PixellEnergy's settlement statement within 5 business days of receipt.
  • India-domestic peers MUST honour Mumbai-only data residency and 30-day DSR resolution per DPDP.
  • Honour the OCPI 2.2.1 X-Request-ID dedup key on EVERY mutating call (PUT/POST).
  • For OCPI peers operating as a CPO under PixellEnergy's eMSP badge: enforce SignedMeterValue on OCPP 2.0.1 sessions — required for IRN issuance.
  • Rotate Token C every 12 months minimum. PixellEnergy will issue a deprecation notice 30 days before forced rotation if a token exceeds the limit.
  • Outage notification: any peer planning ≥ 30 minutes of unavailability for the OCPI inbound surface MUST notify ocpi-ops@pixellenergy.com 24h in advance — avoids spurious DLQ accumulation.

For onboarding queries, write to ocpi-onboarding@pixellenergy.com; for production incidents, the PagerDuty rotation is exposed via the status page. Cross-link the OCPP onboarding cookbook if your peer also owns physical chargers connecting to the PixellEnergy gateway.