DataTransfer Flows - CSMS Developer Guide
Based on OCPP 2.0.1 Edition 4 Specification (Part 2, Section P, pages 354-359). This guide covers the DataTransfer functional block for extending OCPP with custom vendor-specific functionality.
1. Introduction
Section PThe DataTransfer functional block enables parties to extend OCPP with custom attributes or add new custom commands not standardized in the protocol. OCPP offers two extension mechanisms for vendor-specific functionality.
Extension Mechanisms
DataTransferRequest Message
Allows exchange of data or messages not standardized in OCPP. It provides a framework for experimental functionality that may find its way into future OCPP versions. It also enables vendor-specific functionality agreed upon between specific CSMS and Charging Station vendors.
CustomData Element
An optional element in all JSON schemas that allows adding custom attributes to any type. CustomData is the only class that allows additional properties. It is NOT meant for standard implementations.
Key Characteristics
The data field in
both DataTransferRequest and DataTransferResponse has no specified length or type. It can be any valid JSON value (string, number, object, array, boolean, null).
It is RECOMMENDED that the data format/length is agreed upon by all parties involved.
Important: DataTransfer should be used with extreme caution and only for optional functionality, since it impacts compatibility with other systems that do not implement the same vendor extensions.
OCPP Wire Format Example
The data field can
conveniently be used as structured JSON content:
[2,
"<unique msg id>",
"DataTransfer",
{
"vendorId": "com.mycompany.ice",
"messageId": "iceParkedAtCs",
"data": { "start_time": "2020-04-01T11:01:02" }
}
]2. DataTransfer Message Schema
Reference2.1 DataTransferRequest
The DataTransferRequest PDU can be sent either by the CSMS to the Charging Station (P01) or by the Charging Station to the CSMS (P02). The same message structure is used in both directions.
| Field | Type | Required | Description |
|---|---|---|---|
vendorId | string[0..255] | Yes | Identifies the vendor-specific implementation. SHOULD be a reversed DNS namespace
(e.g., com.vendor.product). |
messageId | string[0..50] | No | May be used to indicate a specific message or implementation within the vendor's namespace. |
data | anyType | No | Data without specified length or format. This needs to be decided by both parties (open to implementation). Can be any valid JSON value. |
2.2 DataTransferResponse
| Field | Type | Required | Description |
|---|---|---|---|
status | DataTransferStatusEnumType | Yes | Indicates the success or failure of the data transfer. |
data | anyType | No | Data without specified length or format, in response to request. |
statusInfo | StatusInfoType | No | Detailed status information. |
2.3 DataTransferStatusEnumType
| Value | Description |
|---|---|
Accepted | Message has been accepted and the contained request is accepted. |
Rejected | Message has been accepted but the contained request is rejected. |
UnknownMessageId | Message could not be interpreted due to unknown messageId string. |
UnknownVendorId | Message could not be interpreted due to unknown vendorId string. |
2.4 StatusInfoType
Provides additional information about the response status.
| Field | Type | Required | Description |
|---|---|---|---|
reasonCode | string[0..20] | Yes | A predefined code for the reason why the status is returned. Case-insensitive. |
additionalInfo | string[0..512] | No | Additional text to provide detailed information. |
3. DataTransfer Flows
Use Cases P01-P02Data Transfer to the Charging Station
To send information from the CSMS to the Charging Station for a function that is not supported by OCPP.
Actors: Charging Station, CSMS
Scenario:
- The CSMS sends information to a Charging Station for a function not supported by OCPP with DataTransferRequest.
- The Charging Station responds to the CSMS with DataTransferResponse.
┌──────┐ ┌──────────────────┐
│ CSMS │ │ Charging Station │
└──┬───┘ └────────┬─────────┘
│ │
│ DataTransferRequest(vendorId, │
│ [messageId], [data]) │
│──────────────────────────────────────────>│
│ │
│ DataTransferResponse(status, [data]) │
│<──────────────────────────────────────────│
│ │Postconditions:
- Success: DataTransferRequest is received successfully and Accepted.
- Failure: Message has been accepted but the contained request is Rejected.
- In all other cases, the usage of status Accepted or Rejected and the data element is part of the vendor-specific agreement between the parties involved.
CSMS Implementation (Initiator):
The CSMS is the initiator in this flow:
- Construct the DataTransferRequest with the appropriate
vendorId, optionalmessageId, and optionaldata. - Send as OCPP CALL message (message type 2) over the WebSocket to the target Charging Station.
- Handle the DataTransferResponse from the Charging Station.
{
"vendorId": "com.yourcompany.feature",
"messageId": "specificCommand",
"data": { ... }
}Response Handling:
| Response Status | CSMS Action |
|---|---|
Accepted | The Charging Station recognized the vendorId/messageId and accepted the request. Process any returned data. |
Rejected | The Charging Station recognized the vendorId/messageId but rejected the request. Check statusInfo for details. |
UnknownVendorId | The Charging Station has no implementation for the specified vendorId. The vendor extension is not supported on this station. |
UnknownMessageId | The Charging Station recognizes the vendorId but not the messageId. The specific sub-command is not supported. |
Requirements:
| ID | Precondition | Requirement |
|---|---|---|
P01.FR.01 | — | The CSMS SHALL only use DataTransferRequest for a function which is not supported by OCPP. |
P01.FR.02 | — | The vendorId SHOULD be a value from the reversed DNS namespace (e.g., com.vendor.product). |
P01.FR.03 | — | The messageId in the request message MAY be used to indicate a specific message or implementation. |
P01.FR.04 | — | The length of data in both the request and response message is undefined and it is RECOMMENDED that this is agreed upon by all parties involved. |
P01.FR.05 | Recipient has no implementation for the specific vendorId. | The recipient SHALL return a status UnknownVendorId. |
P01.FR.06 | Receipt of DataTransferRequest with messageId mismatch. | The recipient SHALL return status UnknownMessageId. |
P01.FR.07 | — | The usage of status Accepted or Rejected and the data element SHALL be part of the vendor-specific agreement. |
Data Transfer to the CSMS
To send information from the Charging Station to the CSMS for a function which is not supported by OCPP.
Actors: Charging Station, CSMS
Scenario:
- The Charging Station sends information to the CSMS for a function not supported by OCPP with DataTransferRequest.
- The CSMS responds to the Charging Station with DataTransferResponse.
┌──────────────────┐ ┌──────┐
│ Charging Station │ │ CSMS │
└────────┬─────────┘ └──┬───┘
│ │
│ DataTransferRequest(vendorId, │
│ [messageId], [data]) │
│──────────────────────────────────────────>│
│ │
│ DataTransferResponse(status, [data]) │
│<──────────────────────────────────────────│
│ │Postconditions:
- Success: DataTransferRequest is received successfully and Accepted.
- Failure: Message has been accepted but the contained request is Rejected.
- In all other cases, the usage of status Accepted or Rejected and the data element is part of the vendor-specific agreement between the parties involved.
CSMS Implementation (Recipient):
The CSMS is the recipient in this flow. This is the primary flow a CSMS developer needs to implement as a message handler.
Inbound Message (OCPP CALL):
The CSMS will receive a CALL message (type 2) with action "DataTransfer" on the WebSocket:
[2, "<messageId>", "DataTransfer", {
"vendorId": "com.charger-vendor.feature",
"messageId": "someCustomMessage",
"data": { ... }
}]Handler Logic:
function handleDataTransferRequest(request: DataTransferRequest) -> DataTransferResponse:
1. Check if the CSMS has an implementation for request.vendorId
├── NO → return { status: "UnknownVendorId" }
└── YES → continue
2. If request.messageId is provided, check if it is recognized
├── NO → return { status: "UnknownMessageId" }
└── YES → continue
3. Process the vendor-specific logic based on vendorId + messageId
├── Parse request.data according to the vendor-specific agreement
├── Execute the custom business logic
└── Build response data (if applicable)
4. Return DataTransferResponse
├── Success → { status: "Accepted", data: { ... } }
└── Failure → { status: "Rejected", statusInfo: { reasonCode: "...", additionalInfo: "..." } }Response Construction:
{
"status": "UnknownVendorId"
}{
"status": "UnknownMessageId"
}{
"status": "Accepted",
"data": { ... }
}{
"status": "Rejected",
"statusInfo": {
"reasonCode": "InvalidData",
"additionalInfo": "The provided data does not conform to the expected format."
}
}Requirements:
| ID | Precondition | Requirement |
|---|---|---|
P02.FR.01 | — | The vendorId in the request message SHOULD be known to the Charging Station and uniquely identify the vendor-specific implementation. |
P02.FR.02 | — | The Charging Station SHALL only use DataTransferRequest for a function which is not supported by OCPP. |
P02.FR.03 | — | The vendorId SHOULD be a value from the reversed DNS namespace. |
P02.FR.04 | — | The messageId in the request message MAY be used to indicate a specific message or implementation. |
P02.FR.05 | — | The length of data in both the request and response message is undefined and it is RECOMMENDED that this is agreed upon by all parties involved. |
P02.FR.06 | Recipient has no implementation for the specific vendorId. | The recipient SHALL return a status UnknownVendorId. |
P02.FR.07 | Receipt of DataTransferRequest with messageId mismatch. | The recipient SHALL return status UnknownMessageId. |
P02.FR.08 | — | The usage of status Accepted or Rejected and the data element SHALL be part of the vendor-specific agreement. |
4. JSON Schema Reference
Schemas4.1 DataTransferRequest JSON Schema
{
"$schema": "http://json-schema.org/draft-06/schema#",
"$id": "urn:OCPP:Cp:2:2020:3:DataTransferRequest",
"comment": "OCPP 2.0.1 FINAL",
"definitions": {
"CustomDataType": {
"description": "This class does not get 'AdditionalProperties = false' in the schema generation, so it can be extended with arbitrary JSON properties to allow adding custom data.",
"javaType": "CustomData",
"type": "object",
"properties": {
"vendorId": {
"type": "string",
"maxLength": 255
}
},
"required": ["vendorId"]
}
},
"type": "object",
"additionalProperties": false,
"properties": {
"customData": {
"$ref": "#/definitions/CustomDataType"
},
"messageId": {
"description": "May be used to indicate a specific message or implementation.",
"type": "string",
"maxLength": 50
},
"data": {
"description": "Data without specified length or format. This needs to be decided by both parties (Open to implementation)."
},
"vendorId": {
"description": "This identifies the Vendor specific implementation.",
"type": "string",
"maxLength": 255
}
},
"required": ["vendorId"]
}Key observations:
vendorIdis the only required field (max 255 chars).messageIdis optional (max 50 chars).datahas no type constraint — it accepts any valid JSON value (string, number, boolean, null, object, array).customDatais the standard OCPP extension point (separate from vendor DataTransfer logic).additionalProperties: falsemeans no extra top-level fields beyond the defined ones.
4.2 DataTransferResponse JSON Schema
{
"$schema": "http://json-schema.org/draft-06/schema#",
"$id": "urn:OCPP:Cp:2:2020:3:DataTransferResponse",
"comment": "OCPP 2.0.1 FINAL",
"definitions": {
"CustomDataType": {
"description": "This class does not get 'AdditionalProperties = false' in the schema generation, so it can be extended with arbitrary JSON properties to allow adding custom data.",
"javaType": "CustomData",
"type": "object",
"properties": {
"vendorId": {
"type": "string",
"maxLength": 255
}
},
"required": ["vendorId"]
},
"DataTransferStatusEnumType": {
"description": "This indicates the success or failure of the data transfer.",
"javaType": "DataTransferStatusEnum",
"type": "string",
"additionalProperties": false,
"enum": ["Accepted", "Rejected", "UnknownMessageId", "UnknownVendorId"]
},
"StatusInfoType": {
"description": "Element providing more information about the status.",
"javaType": "StatusInfo",
"type": "object",
"additionalProperties": false,
"properties": {
"customData": {
"$ref": "#/definitions/CustomDataType"
},
"reasonCode": {
"description": "A predefined code for the reason why the status is returned in this response. The string is case-insensitive.",
"type": "string",
"maxLength": 20
},
"additionalInfo": {
"description": "Additional text to provide detailed information.",
"type": "string",
"maxLength": 512
}
},
"required": ["reasonCode"]
}
},
"type": "object",
"additionalProperties": false,
"properties": {
"customData": {
"$ref": "#/definitions/CustomDataType"
},
"status": {
"$ref": "#/definitions/DataTransferStatusEnumType"
},
"statusInfo": {
"$ref": "#/definitions/StatusInfoType"
},
"data": {
"description": "Data without specified length or format, in response to request."
}
},
"required": ["status"]
}Key observations:
statusis the only required field (one of the 4 enum values).datahas no type constraint — any valid JSON value.statusInfoprovides optional detail viareasonCode(required within, max 20 chars) andadditionalInfo(optional, max 512 chars).
5. CSMS Implementation Summary
ChecklistMessages the CSMS Sends (Initiator)
| Flow | Action | Message | Direction |
|---|---|---|---|
P01 | DataTransfer | DataTransferRequest | CSMS → Charging Station |
Messages the CSMS Receives and Must Handle
| Flow | Action | Message | Direction | CSMS Response |
|---|---|---|---|---|
P02 | DataTransfer | DataTransferRequest | Charging Station → CSMS | DataTransferResponse |
CSMS Handler Checklist for P02
- ✓Register handler for incoming DataTransfer action in the OCPP message router
- ✓Implement vendorId registry/lookup to match incoming vendorId values
- ✓For each supported vendorId, implement messageId dispatch (if messageId is used)
- ✓Return UnknownVendorId for unrecognized vendorId values
- ✓Return UnknownMessageId for recognized vendorId but unrecognized messageId
- ✓Implement vendor-specific business logic for each supported vendorId+messageId combination
- ✓Return Accepted with optional response data on success
- ✓Return Rejected with optional statusInfo on failure
- ✓Ensure the data field parser handles the agreed-upon format for each vendor extension