REST API Documentation
Automate your battery passport workflow. Create, update, publish and export products via REST API. The passport lookup endpoints are aligned with the methods and REST conventions of EN 18222:2026; a complete conformity assessment including dependent standards is still open.
Authentication
Scale plan required. Generate keys in your organization settings.
Authorization: Bearer dpp_live_...Base URL
120 requests/minute per organization.
https://app.dpphero.com/api/v1Quick Example
curl -X POST https://app.dpphero.com/api/v1/products \
-H "Authorization: Bearer dpp_live_..." \
-H "Content-Type: application/json" \
-d '{
"name": "LFP Module 48V",
"serial_number": "BAT-2025-001",
"battery_category": "industrial",
"manufacturing_date": "2025-06-15",
"battery_mass": 45.5
}'Available Endpoints
All endpoints require a Bearer token (API key). Available on the Scale plan.
Products
/products/products/products/{id}/products/{id}/products/{id}/products/{id}/image/products/{id}/image/products/{id}/filesBattery Condition
Update dynamic BMS data like state of charge, cycle count and capacity fade via API.
/products/{id}/condition/products/{id}/conditionBulk Import
/products/bulkExport
/products/{id}/export/json/products/{id}/export/gefeg-json/products/{id}/export/pdf/products/{id}/preprint-qr/products/{id}/export/qrOrganization
/organization/facilities/audit-logLists, filters and pagination
GET /products returns page by page. page starts at 1, per_page runs from 1 to 100 (default 25). You can filter by status and battery_category, search with search and sort by created_at, updated_at or name, ascending or descending. The response reports total and total_pages.
GET /products?page=1&per_page=25&sort=created_at&order=descMachine-readable specification
The complete interface as an OpenAPI document, available without signing in. Use it to generate client code or load the collection into your tool of choice.
openapi.jsonGS1 Digital Link
Passports can also be addressed through GS1 identifiers: GTIN and serial number together denote exactly one battery, the way GS1 Digital Link prescribes. How the GTIN is written in the process is stated at the endpoints concerned; which those are is described in the full documentation inside your account.
Errors and status codes
Every error arrives as a JSON object with the same shape. On 429 the Retry-After header gives the wait in seconds.
validation_errorInput incomplete or invalid; details names the fieldunauthorizedAPI key missing or invalidforbiddenKey may not address this resourceplan_requiredFeature belongs to a different plannot_foundResource does not exist in your organizationconflictValue already taken, for example a duplicate identifierrate_limit_exceededToo many requests; observe Retry-Afterinternal_errorError on our side; pass the correlation_id to support{
"error": {
"code": "validation_error",
"message": "...",
"details": { "name": ["Required"] },
"correlation_id": "..."
}
}The correlation_id also travels in the X-Correlation-Id header. Quote it when you contact support and we can find the same event in our logs.
Full Documentation
The complete API reference with field definitions, example payloads, error codes, auto-fill rules and the entire product schema is available in your dashboard.
What to know before your first request
Authentication
Every request carries a bearer token in the Authorization header. The REST API belongs to the Scale plan; on smaller plans you work through the interface or the CSV import.
Reading page by page
List endpoints do not return everything at once. You control that through page (from 1, default 1) and per_page (1 to 100, default 25). The response carries page, per_page, total and total_pages. So you do not have to guess when it ends. Sorting runs through sort (created_at, updated_at or name) and order (asc or desc). Filtering runs through status, battery_category and search.
No webhooks yet
Event notifications do not exist at present. You fetch changes by polling. It makes sense to sort by updated_at and limit to the period since your last run. We write this down instead of hiding it. That way you do not build your integration on a promise that does not exist.
The export follows the Battery Passport data model in version 2.0. What sits in which field is decided by the field registry of the application, not by the call. The endpoint descriptions above and the docs tab in the account come from the same source. They therefore do not drift apart.