Battery Compliance DPP API (EN 18222)
Life Cycle API and Fine Granular API for digital battery passports, following the method names and status codes of EN 18222 as described in BatteryPass-Ready “User Stories from a Technical Perspective” v1.0 (tables 1, 2, 4). DPP ID = Product ID = the permanent item URI; in paths it is URL-encoded (encodeURIComponent). Reading public data needs no token. Controlled data, search and updates need an OAuth 2.0 access token (client credentials, POST /oauth/token). Responses: { statusCode, payload?, result? }. A passport payload is { dpp, version, accessLevel, links }: dpp is the signed passport filtered to the caller's access level; links lists the Art. 77(7) links to the passports of the original batteries (predecessors) and to new passports (successors) – they are not part of the signed passport.
POST /oauth /token
Obtain an access token (OAuth 2.0 client credentials)
Request body
| Field | Type | Details |
|---|---|---|
grant_type | | required |
scope | string | optional – space-separated subset of dpp:read dpp:search dpp:write |
client_id | string | optional |
client_secret | string | optional |
Example
grant_type=client_credentials&scope=dpp%3AreadResponses
- 200 Token
{ "access_token": "eyJhbGciOiJFZERTQSIs…", "token_type": "Bearer", "expires_in": 900, "scope": "dpp:read dpp:write" } - 400 invalid_request, unsupported_grant_type, invalid_scope
- 401 invalid_client
curl
curl -X POST "https://batterycompliance.eu/oauth/token" \
-d "grant_type=client_credentials&scope=dpp%3Aread"GET /api /dpp /v1 /dpps
ReadDPPByProductId – current active DPP for a Product ID
Parameters
| Field | In | Type | Details |
|---|---|---|---|
productId | query | string (uri) | required |
Responses
- 200 Active DPP filtered to the caller's access rights
{ "statusCode": "Success", "payload": { "dpp": { "dppHeader": { "digitalProductPassportId": "https://batterycompliance.eu/01/03850012345678/21/KS16X-2026-000123", "dppStatus": { "dppStatusValue": "active" } }, "performanceAndDurability": { "stateOfCharge": { "percentageValue": 80, "percentUnit": "%" } } }, "version": { "versionNo": 3, "publishedAt": "2026-10-01T08:00:00.000Z", "sha256": "9f2c…", "signature": "base64…" }, "accessLevel": "legitimateInterest", "links": { "predecessors": [], "successors": [] } } } - 400 Malformed or invalid request
{ "statusCode": "ClientErrorBadRequest", "result": { "message": "productIds must be a non-empty array" } } - 401 Missing, invalid, expired or revoked access token
{ "statusCode": "ClientNotAuthorized", "result": { "message": "Invalid access token" } } - 403 No access to the DPP, element or operation
{ "statusCode": "ClientForbidden", "result": { "message": "No write access to these data elements" } } - 404 DPP or element does not exist
{ "statusCode": "ClientErrorResourceNotFound", "result": { "message": "No DPP with this identifier" } }
curl
curl -X GET "https://batterycompliance.eu/api/dpp/v1/dpps" \
-H "Authorization: Bearer $ACCESS_TOKEN"POST /api /dpp /v1 /dpps
CreateDPP – not provided (501 ServerNotImplemented)
Responses
- 501 Not implemented
curl
curl -X POST "https://batterycompliance.eu/api/dpp/v1/dpps" \
-H "Authorization: Bearer $ACCESS_TOKEN"GET /api /dpp /v1 /dpps /{dppId}
ReadDPPById – latest version of a DPP, whatever its status
Parameters
| Field | In | Type | Details |
|---|---|---|---|
dppId | path | string | required – URL-encoded DPP ID (permanent URI) |
Responses
- 200 DPP
{ "statusCode": "Success", "payload": { "dpp": { "dppHeader": { "digitalProductPassportId": "https://batterycompliance.eu/01/03850012345678/21/KS16X-2026-000123", "dppStatus": { "dppStatusValue": "active" } }, "performanceAndDurability": { "stateOfCharge": { "percentageValue": 80, "percentUnit": "%" } } }, "version": { "versionNo": 3, "publishedAt": "2026-10-01T08:00:00.000Z", "sha256": "9f2c…", "signature": "base64…" }, "accessLevel": "legitimateInterest", "links": { "predecessors": [], "successors": [] } } } - 400 Malformed or invalid request
{ "statusCode": "ClientErrorBadRequest", "result": { "message": "productIds must be a non-empty array" } } - 401 Missing, invalid, expired or revoked access token
{ "statusCode": "ClientNotAuthorized", "result": { "message": "Invalid access token" } } - 403 No access to the DPP, element or operation
{ "statusCode": "ClientForbidden", "result": { "message": "No write access to these data elements" } } - 404 DPP or element does not exist
{ "statusCode": "ClientErrorResourceNotFound", "result": { "message": "No DPP with this identifier" } }
curl
curl -X GET "https://batterycompliance.eu/api/dpp/v1/dpps/$DPP_ID" \
-H "Authorization: Bearer $ACCESS_TOKEN"PATCH /api /dpp /v1 /dpps /{dppId}
UpdateDPPById – partial update of item-level data elements; creates a new signed version
Body: partial DPP by section. `null` removes an element. Every element must be within the client's write paths; identifiers, header and model data are immutable. Only active DPPs. All-or-nothing validation against the schema and the category profile. Optional Idempotency-Key header. Recycling (Art. 77(8)): `{"dppHeader":{"dppStatus":{"dppStatusValue":"archived"}},"identifiersAndProductData":{"batteryStatus":{"batteryStatusValues":"waste"}}}` with the scope dpp:recycle records that the battery was recycled – a last archived version is published and the passport is frozen (the "Marked for Deletion" step of BatteryPass-Ready, with the EN 18223 statuses). At most one automatic version a day per passport: a later change is stored and published when the day is over (the response gives publishAfter); the battery status, the putting into service and accidents are published at once.
Parameters
| Field | In | Type | Details |
|---|---|---|---|
dppId | path | string | required – URL-encoded DPP ID (permanent URI) |
Idempotency-Key | header | string | optional |
Request body
Example
{
"identifiersAndProductData": {
"batteryStatus": {
"batteryStatusValues": "repurposed"
}
},
"performanceAndDurability": {
"stateOfCharge": {
"percentageValue": 80
}
}
}Responses
- 200 Updated DPP (new version)
{ "statusCode": "Success", "payload": { "dpp": { "dppHeader": { "digitalProductPassportId": "https://batterycompliance.eu/01/03850012345678/21/KS16X-2026-000123", "dppStatus": { "dppStatusValue": "active" } }, "performanceAndDurability": { "stateOfCharge": { "percentageValue": 80, "percentUnit": "%" } } }, "version": { "versionNo": 3, "publishedAt": "2026-10-01T08:00:00.000Z", "sha256": "9f2c…", "signature": "base64…" }, "accessLevel": "legitimateInterest", "links": { "predecessors": [], "successors": [] } } } - 400 Malformed or invalid request
{ "statusCode": "ClientErrorBadRequest", "result": { "message": "productIds must be a non-empty array" } } - 401 Missing, invalid, expired or revoked access token
{ "statusCode": "ClientNotAuthorized", "result": { "message": "Invalid access token" } } - 403 No access to the DPP, element or operation
{ "statusCode": "ClientForbidden", "result": { "message": "No write access to these data elements" } } - 404 DPP or element does not exist
{ "statusCode": "ClientErrorResourceNotFound", "result": { "message": "No DPP with this identifier" } } - 409 Status does not allow the update, or Idempotency-Key reuse
{ "statusCode": "ClientResourceConflict", "result": { "message": "The DPP status is archived; only active DPPs can be updated" } }
curl
curl -X PATCH "https://batterycompliance.eu/api/dpp/v1/dpps/$DPP_ID" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{"identifiersAndProductData":{"batteryStatus":{"batteryStatusValues":"repurposed"}},"performanceAndDurability":{"stateOfCharge":{"percentageValue":80}}}'DELETE /api /dpp /v1 /dpps /{dppId}
DeleteDPPById – delete a passport after the battery was recycled (Art. 77(8))
Only the economic operator's own clients with the scope dpp:delete, only after the recycling was recorded (UpdateDPPById with dpp:recycle, or in the panel); a recycling recorded by another company (a recycler) holds the deletion for 14 days (409 with `details.deletableFrom`), while the platform administrator can still reverse a wrong record. Deletes every version, its backup copies and the readings; the permanent address then answers 410 Gone and is never used for another battery. Notify the EU registry of the deletion.
Parameters
| Field | In | Type | Details |
|---|---|---|---|
dppId | path | string | required – URL-encoded DPP ID (permanent URI) |
Responses
- 200 Deleted
{ "statusCode": "Success", "payload": { "dppId": "https://batterycompliance.eu/01/03850012345678/21/KS16X-2026-000123", "deleted": true, "versions": 4 } } - 401 Missing, invalid, expired or revoked access token
{ "statusCode": "ClientNotAuthorized", "result": { "message": "Invalid access token" } } - 403 No access to the DPP, element or operation
{ "statusCode": "ClientForbidden", "result": { "message": "No write access to these data elements" } } - 404 DPP or element does not exist
{ "statusCode": "ClientErrorResourceNotFound", "result": { "message": "No DPP with this identifier" } } - 409 Status does not allow the update, or Idempotency-Key reuse
{ "statusCode": "ClientResourceConflict", "result": { "message": "The DPP status is archived; only active DPPs can be updated" } }
curl
curl -X DELETE "https://batterycompliance.eu/api/dpp/v1/dpps/$DPP_ID" \
-H "Authorization: Bearer $ACCESS_TOKEN"GET /api /dpp /v1 /dpps /{dppId} /versions
ReadDPPVersionByIdAndDate – the version valid at a timestamp
Parameters
| Field | In | Type | Details |
|---|---|---|---|
dppId | path | string | required – URL-encoded DPP ID (permanent URI) |
date | query | string (date-time) | required |
Responses
- 200 DPP version
{ "statusCode": "Success", "payload": { "dpp": { "dppHeader": { "digitalProductPassportId": "https://batterycompliance.eu/01/03850012345678/21/KS16X-2026-000123", "dppStatus": { "dppStatusValue": "active" } }, "performanceAndDurability": { "stateOfCharge": { "percentageValue": 80, "percentUnit": "%" } } }, "version": { "versionNo": 3, "publishedAt": "2026-10-01T08:00:00.000Z", "sha256": "9f2c…", "signature": "base64…" }, "accessLevel": "legitimateInterest", "links": { "predecessors": [], "successors": [] } } } - 400 Malformed or invalid request
{ "statusCode": "ClientErrorBadRequest", "result": { "message": "productIds must be a non-empty array" } } - 401 Missing, invalid, expired or revoked access token
{ "statusCode": "ClientNotAuthorized", "result": { "message": "Invalid access token" } } - 403 No access to the DPP, element or operation
{ "statusCode": "ClientForbidden", "result": { "message": "No write access to these data elements" } } - 404 DPP or element does not exist
{ "statusCode": "ClientErrorResourceNotFound", "result": { "message": "No DPP with this identifier" } }
curl
curl -X GET "https://batterycompliance.eu/api/dpp/v1/dpps/$DPP_ID/versions" \
-H "Authorization: Bearer $ACCESS_TOKEN"GET /api /dpp /v1 /dpps /{dppId} /elements /{elementPath}
ReadDataElement – one data element (section.attribute[.part])
Parameters
| Field | In | Type | Details |
|---|---|---|---|
dppId | path | string | required – URL-encoded DPP ID (permanent URI) |
elementPath | path | string | required |
Responses
- 200 Element
{ "statusCode": "Success", "payload": { "dppId": "https://batterycompliance.eu/01/03850012345678/21/KS16X-2026-000123", "elementPath": "performanceAndDurability.stateOfCharge", "value": { "percentageValue": 80, "percentUnit": "%" }, "versionNo": 3 } } - 400 Malformed or invalid request
{ "statusCode": "ClientErrorBadRequest", "result": { "message": "productIds must be a non-empty array" } } - 401 Missing, invalid, expired or revoked access token
{ "statusCode": "ClientNotAuthorized", "result": { "message": "Invalid access token" } } - 403 No access to the DPP, element or operation
{ "statusCode": "ClientForbidden", "result": { "message": "No write access to these data elements" } } - 404 DPP or element does not exist
{ "statusCode": "ClientErrorResourceNotFound", "result": { "message": "No DPP with this identifier" } }
curl
curl -X GET "https://batterycompliance.eu/api/dpp/v1/dpps/$DPP_ID/elements/$ELEMENT_PATH" \
-H "Authorization: Bearer $ACCESS_TOKEN"PATCH /api /dpp /v1 /dpps /{dppId} /elements /{elementPath}
UpdateDataElement – set or remove (value: null) one attribute; creates a new version
At most one automatic version a day per passport: a later change is stored and published when the day is over (the response gives publishAfter); the battery status, the putting into service and accidents are published at once.
Parameters
| Field | In | Type | Details |
|---|---|---|---|
dppId | path | string | required – URL-encoded DPP ID (permanent URI) |
elementPath | path | string | required |
Idempotency-Key | header | string | optional |
Request body
Example
{
"value": {
"percentageValue": 64
}
}Responses
- 200 Updated element
- 400 Malformed or invalid request
{ "statusCode": "ClientErrorBadRequest", "result": { "message": "productIds must be a non-empty array" } } - 401 Missing, invalid, expired or revoked access token
{ "statusCode": "ClientNotAuthorized", "result": { "message": "Invalid access token" } } - 403 No access to the DPP, element or operation
{ "statusCode": "ClientForbidden", "result": { "message": "No write access to these data elements" } } - 404 DPP or element does not exist
{ "statusCode": "ClientErrorResourceNotFound", "result": { "message": "No DPP with this identifier" } } - 409 Status does not allow the update, or Idempotency-Key reuse
{ "statusCode": "ClientResourceConflict", "result": { "message": "The DPP status is archived; only active DPPs can be updated" } }
curl
curl -X PATCH "https://batterycompliance.eu/api/dpp/v1/dpps/$DPP_ID/elements/$ELEMENT_PATH" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{"value":{"percentageValue":64}}'POST /api /dpp /v1 /dpps /search
ReadDPPIdsByProductIds – DPP IDs for up to 100 Product IDs (identifiers only)
Request body
| Field | Type | Details |
|---|---|---|
productIds | array of string (uri) | required |
limit | integer | optional |
cursor | string | optional |
Example
{
"productIds": [
"https://batterycompliance.eu/01/03850012345678/21/KS16X-2026-000123"
],
"limit": 50
}Responses
- 200 DPP IDs; cursor present when more results exist
{ "statusCode": "Success", "payload": { "dppIds": [ "https://batterycompliance.eu/01/03850012345678/21/KS16X-2026-000123" ] } } - 400 Malformed or invalid request
{ "statusCode": "ClientErrorBadRequest", "result": { "message": "productIds must be a non-empty array" } } - 401 Missing, invalid, expired or revoked access token
{ "statusCode": "ClientNotAuthorized", "result": { "message": "Invalid access token" } } - 403 No access to the DPP, element or operation
{ "statusCode": "ClientForbidden", "result": { "message": "No write access to these data elements" } }
curl
curl -X POST "https://batterycompliance.eu/api/dpp/v1/dpps/search" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{"productIds":["https://batterycompliance.eu/01/03850012345678/21/KS16X-2026-000123"],"limit":50}'POST /api /dpp /v1 /dpps /{dppId} /readings
AddReadings – store dynamic data readings (platform extension, not an EN 18222 method); optionally apply the latest values as a new version
Paths: item-level attributes with dynamic data (state of charge, remaining capacity, cycles, temperature…) within the client's write paths. Readings do not create a version unless apply is true. Only active DPPs. With apply, at most one automatic version a day per passport: a later apply stores the values and answers with publishAfter, when the maintenance publishes them.
Parameters
| Field | In | Type | Details |
|---|---|---|---|
dppId | path | string | required – URL-encoded DPP ID (permanent URI) |
Request body
Example
{
"readings": [
{
"path": "performanceAndDurability.stateOfCharge",
"value": {
"percentageValue": 76
},
"measuredAt": "2026-10-01T08:00:00Z",
"source": "bms"
},
{
"path": "performanceAndDurability.numberOfFullChargingAndDischargingCycles",
"value": 312,
"measuredAt": "2026-10-01T08:00:00Z",
"source": "bms"
}
],
"apply": true
}Responses
- 201 Stored
{ "statusCode": "SuccessCreated", "payload": { "dppId": "https://batterycompliance.eu/01/03850012345678/21/KS16X-2026-000123", "created": 2, "versionNo": 4 } } - 400 Malformed or invalid request
{ "statusCode": "ClientErrorBadRequest", "result": { "message": "productIds must be a non-empty array" } } - 401 Missing, invalid, expired or revoked access token
{ "statusCode": "ClientNotAuthorized", "result": { "message": "Invalid access token" } } - 403 No access to the DPP, element or operation
{ "statusCode": "ClientForbidden", "result": { "message": "No write access to these data elements" } } - 404 DPP or element does not exist
{ "statusCode": "ClientErrorResourceNotFound", "result": { "message": "No DPP with this identifier" } } - 409 Status does not allow the update, or Idempotency-Key reuse
{ "statusCode": "ClientResourceConflict", "result": { "message": "The DPP status is archived; only active DPPs can be updated" } }
curl
curl -X POST "https://batterycompliance.eu/api/dpp/v1/dpps/$DPP_ID/readings" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{"readings":[{"path":"performanceAndDurability.stateOfCharge","value":{"percentageValue":76},"measuredAt":"2026-10-01T08:00:00Z","source":"bms"},{"path":"performanceAndDurability.numberOfFullChargingAndDischargingCycles","value":312,"measuredAt":"2026-10-01T08:00:00Z","source":"bms"}],"apply":true}'