Schema
The TCPP 1.3.0 message format
Twenty-seven endpoints, each a request/response pair, plus
all.json, the envelope every one of them shares. Every file is served here
at the URL its $id names, so $ref resolves without rewriting.
The envelope
Every TCPP message is one JSON object with the same five or six top-level members. The
endpoint decides what goes in record; everything around it is identical
whether the message reports a charging session or answers a ping.
| Member | In | What it holds |
|---|---|---|
| tcpp | both | The version this message is written against, as a URL: https://tcpp.digital/schema/1.3.0/. |
| head | both | Who, to whom, about what, when, and with what outcome. Identical in shape across all endpoints; described below. |
| record | both | The payload, defined by the endpoint's own schema. This is the only member whose shape changes. |
| parsed | response | Per-element outcome: a map from a path in the request to a six-digit error code, so a partially accepted message says exactly which part failed. |
| participants | both | Other parties to the process, each with its type, id and permissions (read, control, push, broker…), optionally naming a forwarder and an approver. |
| references | both | The messages this one relates to: each a reference id, a full copy of that message's head, and optionally its signature. This is what makes a process reconstructable from its records. |
The head
Twelve required fields. A response repeats the request's head with the direction
reversed, origin and target swapped, and its own outcome in error_code.
| Field | Type | Meaning |
|---|---|---|
| record_type | string | The endpoint: ping, charge_start, tariffs_list, … |
| record_direction | string | request, response or internal. Every request has a response; internal is for the exceptions, such as an error a device records about itself. |
| record_udt | date-time | Universal date and time of the record, with offset. |
| record_pagination | number | The sender's own counter for this record, from 1 upwards. |
| record_version | string | The TCPP version: 1.3.0. |
| origin_type | string(3) | The sender's module type. See the table below. |
| origin_id | string | The sender's identifier, prefixed by its namespace. |
| target_type | string(3) | The recipient's module type. |
| target_id | string | The recipient's identifier. |
| context_type | string(3) | What kind of process this message belongs to: a process type, not a module type. May be empty. |
| context_id | string | The identifier of that process, shared by every message in it. May be empty. |
| error_code | hex(6) | The outcome. 000000 in a request and in a response that succeeded. |
| error_text | string | Optional plain text alongside the code. |
Identifiers
Every id in a head (origin, target, context, participants) carries a one-letter prefix and a colon, naming the namespace it belongs to, so an identifier is never ambiguous about what kind of thing it names. The whole id, prefix included, is at most 120 characters.
| Prefix | Namespace | Example |
|---|---|---|
| E: | EVSE ID | E:DE*PID*E*IWS*00100017 |
| G: | GUID | G:90676293-fa28-49bd-81ba-1b58a0f62abd |
| D: | Domain namespace | D:node.example.de |
| P: | Private namespace | P:ECS-HOST |
| I: | Internal to the sender | I:slot-2 |
| H: | Hash | H:9f86d081884c7d… |
| N: | Numeric pagination | N:45330 |
| C: | Contract or tariff id | C:DE-8AA-C12345-6 |
| V: | Vehicle id | V:WDD1234567A123456 |
| X: | Undefined | X:legacy-7 |
Module types
Three upper-case letters identify what a participant is. The type says which role a party plays in the protocol; the id says which one it is.
Trusted services
| Type | Module | Holds |
|---|---|---|
| TMH | Trusted Management Host | Keys, modules, eMAIDs, charge points |
| TEH | Trusted Exchange Host | Dynamic data: status, reservations |
| TAH | Trusted Archive Host | Archived documents and records |
Market participants
| Type | Module | Notes |
|---|---|---|
| MSP | eMobility Service Provider | eMSP |
| CPO | Charge Point Operator | Where independent of the MSP |
| LMP | Location Management Provider | Parking space |
| FMP | Fleet Management Provider | Fleet and logistics |
| ESP | Energy Supplier Provider | Energy supplier |
| SMS | Support Monitoring Service | Technical service and monitoring |
| SAS | Surveillance Authority Service | Authorities |
Charge points and local devices
| Type | Module | Notes |
|---|---|---|
| CSU | Charge Switch Unit | The main charge point device |
| CCU | Charge Central Unit | Centre of a satellite system |
| LIU | Local Identification Unit | Where independent of the CSU |
| LDU | Local Display Unit | Where independent of the CSU |
| RIU | Remote Identification Unit | App, telematics, external display |
| RDU | Remote Display Unit | App, telematics, external display |
| PSU | Parking Space Unit | Car park, parking garage or lot |
| DEV | Device | Any other device |
Metering and energy management
| Type | Module | Notes |
|---|---|---|
| SMG | Smart Meter Gateway | BSI TR-03109 |
| SML | Smart Meter Light | |
| ELM | Electric Meter | Independent meter |
| EMU | Energy Management Unit | Local load control |
| GMU | Grid Energy Management Unit | Grid-side load management |
| BMU | Battery Management Unit | Battery storage |
Context types
context_type names the kind of process a message belongs to, and is
drawn from a separate set:
CRG charging · ENG energy control · MNT maintenance ·
INF information · DRR data request record · TFF tariff.
Error codes
Six hexadecimal digits, used in the head, in the per-element parsed block of a
response and in references. The code is read in three parts: the first digit is the
global class, the next two the detailed status, and the last three a module-specific
status, FFF where the module is not identified.
| Digit 1 | Class |
|---|---|
| 0 | No error |
| 1 | Not able to parse |
| 2 | Head data |
| 3 | Record parsing |
| 4 | Record building |
| 5 | Signature conversion or delivery |
| 6 | Internal software error |
| 7 | Internal hardware error |
| F | Unknown |
So 000000 is success and FFFFFF is an unknown failure. A
response that accepted the head but rejected one array element says so in
parsed, keyed by the path to that element, rather than failing the whole
message.
The two places spell the code differently. In a head,
error_code is upper-case hexadecimal and nothing else:
^[0-9A-F]{6}$. The values inside parsed are looser — either
case, and an optional leading #. A head carrying ffffff
fails validation; the same string in parsed passes.
Signing
A TCPP message travels as a compact JWS with alg: ES384,
ECDSA over the NIST P-384 curve with SHA-384. The JSON object above is the payload; the
receiver decodes it, checks it against the sender's public key, and keeps both the
message and the token it arrived in.
The payload bytes are signed as they were composed. A verifier must check the signature over the bytes it received, never over a re-serialisation of the parsed object: key order, spacing and number formatting all change under a round-trip, and the signature does not survive it.
JWS signatures use the fixed-width R‖S encoding of IEEE P1363, which is what a browser's
Web Crypto produces. Libraries that emit DER, Go's ecdsa.SignASN1 among
them, need converting first, including the left-padding of a short coordinate.
A signature can also be carried inside a message: each entry in
references may hold the jws of the record it refers to, so a
chain of records can be handed on as one document and still be checked link by link.
Note that this member is an object, not the compact string a message travels
as: inside a record the signature is carried in the JSON serialisation of JWS, so that
it stays readable as JSON rather than as one opaque line.
Endpoints
Twenty-seven request/response pairs. Each name below links to its two schema files.
Charging
| Endpoint | What it carries | Schema |
|---|---|---|
| charge_start | Opening a charging process: the base data of the session and the legal subjects party to it. | request · response |
| charge_process | The process itself: status, events, display, measurement curves and legal subjects. | request · response |
| charge_event | A single event within a running process, up to and including its end. | request · response |
| emaid_get | Resolving a contract identity: by card, by vehicle or by another form of enquiry. | request · response |
| tariffs_list | Tariffs for charge points, searched by identifier, by location or by charging limits. | request · response |
Metering
| Endpoint | What it carries | Schema |
|---|---|---|
| measurement_create | Creating a measurement configuration record, a meter's or charge point's digital self-description: what it is, what hardware it has found, which software it runs, which documents it refers to. | request · response |
| measurement_change | Superseding one configuration record with the next, leaving the old one findable. | request · response |
| measurement_configuration | Reading a configuration record back: the anchor every later message about that device refers to. | request · response |
Identity, keys and verification
| Endpoint | What it carries | Schema |
|---|---|---|
| key_get | The public key of a module, so its signatures can be checked. | request · response |
| module_get | What a module is: its type, its id and the details filed about it. | request · response |
| verification_get | The verifications recorded for a module: who attested what, and when. | request · response |
| verification_set | Filing a verification against a module, naming the administrator responsible. | request · response |
Configuration
| Endpoint | What it carries | Schema |
|---|---|---|
| parameters_get | Reading named parameters. | request · response |
| parameters_set | Writing parameters, naming the administrators who authorised it. | request · response |
| parameters_delete | Removing parameters, likewise attributed. | request · response |
| parameters_list | Listing parameters over a range, with a result limit. | request · response |
| trigger_set | Installing a trigger: formulas to evaluate and actions to take when they hold. | request · response |
| trigger_get | Reading one trigger back. | request · response |
| trigger_delete | Removing a trigger. | request · response |
| triggers_list | Listing triggers over a range. | request · response |
Operation
| Endpoint | What it carries | Schema |
|---|---|---|
| ping | Liveness. The smallest message in the set, and the one to implement first. | request · response |
| status | One or more statuses, counted and signed, referring back to what they describe. | request · response |
| error | Errors as their own record: counted, referenced and reportable in their own right. | request · response |
| display_output | What a display should show. | request · response |
| display_input | What was entered on one. | request · response |
Archive
| Endpoint | What it carries | Schema |
|---|---|---|
| archive_list | Searching archived records by head and by content, over a time range and with a result limit. | request · response |
| archive_get | Retrieving one archived record, with or without the signature it was filed under. | request · response |
The envelope schema
all.json is the base format the others specialise: the head, the participant
and reference definitions, and a free-form record. Validate against it when
you need to read a message whose endpoint you do not implement.
Getting the files
All 55 files, as served here, are also packaged as one archive. The reference node embeds the same set and serves it at the same paths, so an implementation can be developed against a local copy and moved to the published URLs unchanged.