batterypass
Platform
How it works Features Comparison
Industries
Energy storage (BESS) Light means of transport Industrial batteries Electric vehicles Suppliers
Resources
Compliance overview EU Battery Regulation Security and privacy All articles Where the data comes from What data the passport needs QR code on the battery Who is responsible? Glossary Developers and API System status Product changes
Batterypass
Obligation check Pricing Demo: view sample passport Blog About us Contact
Log in Start for free
Developers

Connect battery passport data to your systems.

REST API, CSV import and export, fixed passport addresses and all data fields. With a test key you can try everything without changing any data.

100MB per file
67data fields in the app
3formats: CSV, SVG, PNG

Overview

Four objects and four routes for exchanging data. A CSV file is enough to get started; the REST API is there for ongoing operation.

  1. CompanyYour account with users and plan
  2. ModelMaster data, once per battery model
  3. PassportOne battery with serial number and its own address
  4. EventRepair, repurposing or waste
RouteWhat forStatus
CSV importTake over serial numbers from ERP, MES or ExcelAvailable
CSV exportBring passport IDs and addresses back into your systemsAvailable
Passport address and QR codeCreate your own labels or link to passportsAvailable
REST APICreate models and passports automatically, without manual uploadsAvailable

CSV import

Available

The usual route from your ERP: export a list and upload it to a model. Each new serial number gets a passport.

export.csv
Material;Serialnummer;Fertigungsdatum;Charge;Werk;Status
BX-48V;SN-0001;01.03.2027;L2027-03;Essen;frei
BX-48V;SN-0002;01.03.2027;L2027-03;Essen;frei
BX-48V;SN-0003;02.03.2027;L2027-03;Essen;frei
RuleSpecification
EncodingUTF-8 with or without BOM. Windows-1252 is detected and converted.
DelimiterSemicolon, comma or tab. The first line decides.
SizeAt most 100 MB per file, also as an Excel file (.xlsx). Files from 1 MB run in sections automatically.
StructureOne battery per row, no line breaks inside a field.
HeaderOptional. With a header, columns can be in any order and extra columns are ignored. Without one, the order in the table below applies.
ColumnFieldRecognised column namesRequiredRule
1Serial numberseriennummer, serialnummer, serial, serial number, serialnumber, serial no, sn, serien-nr, seriennr, sernrYesAt most 120 characters: letters, digits, spaces and - _ . / :
2Manufacturing dateherstelldatum, produktionsdatum, fertigungsdatum, manufacturing date, production date, date, datumOptional2027-03-01, 01.03.2027, 1.3.2027, 01/03/2027, 1/3/2027 or 2027/03/01
3Batchcharge, chargennummer, batch, lot, losOptionalAt most 120 characters
4Place of manufactureherstellort, produktionsort, werk, place, plant, manufacturing placeOptionalAt most 190 characters

What happens on upload

  • A preview appears first; nothing is saved yet.
  • Faulty rows are reported with their line number and skipped.
  • Duplicate serial numbers in the file and numbers already in this model are skipped.
  • Passports are only created after you confirm, in a single operation. The import appears in the audit trail.

Check a file

Available

Check an export before you sign in. The same rules apply as for the import in the app.

The check runs only in your browser; the file is not uploaded. Whether a number already exists in the model is only shown by the preview in the app.

CSV export

Available

For every model you can download the list of all passports, as UTF-8 with BOM and semicolon-separated. That brings passport IDs and addresses back into ERP, MES or label printing. The download requires signing in.

paesse_BX-48V.csv
Seriennummer;Pass-ID;Pass-URL;Herstelldatum;Charge;Herstellort;Status
SN-0001;7KM2XQ9RTA;https://app.digitalbatterypass.eu/p/7KM2XQ9RTA;2027-03-01;L2027-03;Essen;Original

Passport address and QR code

Available

Every passport has a fixed address. That is all a QR code, a link from a manual or an ERP entry needs.

URL
https://app.digitalbatterypass.eu/p/{PASS-ID}
https://app.digitalbatterypass.eu/p/{PASS-ID}?lang=en
  • The passport ID has 10 characters and avoids easily confused ones such as 0, O, 1, I and L.
  • The QR code contains only this address. If the data changes, it stays valid.
  • In the app, the code is available per passport as SVG and PNG, along with label sheets for printing.
  • Without signing in, the passport page shows only the public data. Search engines are asked not to index it.
  • With a GTIN set, there is also a GS1 Digital Link.

Create your own labels from the export

etiketten.py
# pip install "qrcode[pil]"
import csv
import qrcode

with open("paesse_BX-48V.csv", encoding="utf-8-sig", newline="") as f:
    for row in csv.DictReader(f, delimiter=";"):
        qrcode.make(row["Pass-URL"]).save(f'{row["Pass-ID"]}.png')

Passport as JSON in EU format

The same address gives people the page and programs JSON under EU schema 1.0.0, without sign-in and with public data only. If required data is missing, it is also missing from the JSON and the Registry would reject the passport.

cURL
curl -H "Accept: application/json" https://app.digitalbatterypass.eu/p/{PASS-ID}
curl https://app.digitalbatterypass.eu/p/{PASS-ID}?format=json

Data fields

Available

The app uses 67 fields under the official EU data schema for batteries, version 1.0.0. Send multi-value fields as a list; GET /fields returns the allowed values. The categories are lmt, industrie, ev, sli and geraet.

General information13
FieldTechnical nameTypeVisible toRequired
Language of the textscontent_languagevocabPublicOptional
Manufacturer (name)manufacturer_nametextPublicAll passport categories
Trade namemanufacturer_trade_nametextPublicOptional
Trademarkmanufacturer_trademarktextPublicOptional
Manufacturer (address)manufacturer_addresstextPublicAll passport categories
Manufacturer websitemanufacturer_websiteurlPublicOptional
Manufacturer emailmanufacturer_emailemailPublicOptional
Product numberproduct_numbertextPublicOptional
Place of manufacture (city)manufacturing_placetextPublicOptional
Regionmanufacturing_regiontextPublicOptional
Country of manufacturemanufacturing_countryvocabPublicAll passport categories
Weightweight_kgnumber · kgPublicAll passport categories
Commercial warrantywarranty_monthsinteger · MonatePublicOptional
Materials & substances8
FieldTechnical nameTypeVisible toRequired
Battery chemistrychemistrylist · vocabPublicAll passport categories
Hazardous substanceshazardous_substanceslistPublicAll passport categories
Critical raw materialscritical_raw_materialslist · vocabPublicAll passport categories
Chemical symbol on the labelchemical_symbollist · vocabPublicOptional
Extinguishing agentextinguishing_agenttext · langPublicAll passport categories
Cathode compositioncomposition_cathodetextLegitimate interestAll passport categories
Anode compositioncomposition_anodetextLegitimate interestAll passport categories
Electrolyte compositioncomposition_electrolytetextLegitimate interestAll passport categories
Performance & durability23
FieldTechnical nameTypeVisible toRequired
Rated capacityrated_capacity_ahnumber · AhPublicAll passport categories
Nominal voltagenominal_voltage_vnumber · VPublicAll passport categories
Minimum voltagemin_voltage_vnumber · VPublicAll passport categories
Maximum voltagemax_voltage_vnumber · VPublicAll passport categories
Voltage values apply fromvoltage_temp_min_cnumber · °CPublicAll passport categories
Voltage values apply up tovoltage_temp_max_cnumber · °CPublicAll passport categories
Power (original)rated_power_wnumber · WPublicAll passport categories
Power limitpower_limit_wnumber · WPublicAll passport categories
Power limit applies frompower_temp_min_cnumber · °CPublicOptional
Power limit applies up topower_temp_max_cnumber · °CPublicOptional
Test of the temperature range when not in usetemp_testtext · langPublicAll passport categories
Temperature range fromtemp_min_cnumber · °CPublicAll passport categories
Temperature range totemp_max_cnumber · °CPublicAll passport categories
Internal cell resistanceinternal_cell_resistance_mohmnumber · mΩPublicAll passport categories
Internal pack resistanceinternal_pack_resistance_mohmnumber · mΩPublicAll passport categories
Expected lifetimeexpected_lifetime_cyclesinteger · ZyklenPubliclmt, ev
Cycle life reference testcycle_life_testtext · langPubliclmt, ev
Capacity exhaustion thresholdcapacity_threshold_pctnumber · %Publicev
Initial round-trip efficiencyinitial_rte_pctnumber · %Publiclmt, ev
Round-trip efficiency at half cycle liferte_half_life_pctnumber · %Publiclmt, ev
Charge C-rate in the cycle testcycle_charge_cratenumber · 1/hPubliclmt, ev
Discharge C-rate in the cycle testcycle_discharge_cratenumber · 1/hPublicOptional
Rated energyrated_energy_kwhnumber · kWhPublicOptional
Carbon footprint & recycled content6
FieldTechnical nameTypeVisible toRequired
Share of renewable contentrenewable_content_pctnumber · %PublicAll passport categories
Carbon footprintcarbon_footprintnumber · kg CO₂e/kWhPublicApplies later
Recycled cobalt contentrecycled_cobalt_pctnumber · %PublicApplies later
Recycled lithium contentrecycled_lithium_pctnumber · %PublicApplies later
Recycled nickel contentrecycled_nickel_pctnumber · %PublicApplies later
Recycled lead contentrecycled_lead_pctnumber · %PublicApplies later
Conformity & labelling3
FieldTechnical nameTypeVisible toRequired
Separate collection symbol presentseparate_collection_symbolbooleanPublicAll passport categories
EU declaration of conformity (link)doc_urlurlPublicAll passport categories
Due diligence report (link)due_diligence_urlurlPublicApplies later
Waste prevention and take-back10
FieldTechnical nameTypeVisible toRequired
End-user role in waste preventionend_user_preventiontext · langPublicAll passport categories
End-user role in separate collectionend_user_collectiontext · langPublicAll passport categories
Separate collection pointscollection_pointstext · langPublicAll passport categories
Take-back pointstake_back_pointstext · langPublicAll passport categories
Preparation-for-reuse facilitiesreuse_facilitiestext · langPublicAll passport categories
Preparation-for-repurposing facilitiesrepurposing_facilitiestext · langPublicAll passport categories
Waste battery treatment facilitiestreatment_facilitiestext · langPublicAll passport categories
Safety instructions for waste batterieswaste_safetytext · langPublicAll passport categories
Meaning of the label symbolslabel_symbols_meaningtext · langPublicAll passport categories
Impact of substances on environment and healthsubstances_impacttext · langPublicAll passport categories
Dismantling, repair & spare parts3
FieldTechnical nameTypeVisible toRequired
Spare parts and replacement (link)spare_parts_urlurlLegitimate interestAll passport categories
Dismantling instructions (link)dismantling_urlurlLegitimate interestAll passport categories
Safety measures (link)safety_urlurlLegitimate interestAll passport categories
Test reports1
FieldTechnical nameTypeVisible toRequired
Compliance test reports (link)compliance_report_urlurlAuthorities and test bodiesAll passport categories

REST API

Available

Create models and passports directly from ERP, MES or BMS and report events. JSON over HTTPS, authentication by key. Base address: https://app.digitalbatterypass.eu/api/v1

In live operation, the REST API is part of the Enterprise plan. With Pro you only send BMS measurements. Test keys are available in every plan.

Get started in three steps

  1. Sign in as an administrator and open Settings, then API keys.
  2. Create a test key. It is shown only once, so keep it like a password.
  3. Check the connection with GET /me. If the API responds, the key and network path are correct.
cURL
export BATTERYPASS_KEY="bp_test_..."

curl -s https://app.digitalbatterypass.eu/api/v1/me \
  -H "Authorization: Bearer $BATTERYPASS_KEY"

One key, one company

The key determines which data can be reached. You create it in the app and it is shown only once.

Test keys save nothing

A test key checks each request as in live operation but changes no data and uses no quota.

Safe to retry

With the same Idempotency-Key, no second record is created even after an interruption. The document number from your ERP works well for this.

Passports are not deleted

The API has no DELETE for passports. The end of a battery’s life is reported as an event.

Test keys respond with status 200 and dry_run: true. They read real data but change nothing.

Endpoints

MethodPathWhat for
GET/meConnection test: company, plan, rights and remaining quota
GET/fieldsField catalogue with requirements per category
GET/modelsList models, also by model code
POST/modelsCreate a model
GET/models/{id}Read one model with data and missing required fields
PATCH/models/{id}Change master data
GET/passportsList passports, also by serial number or change date
POST/passports/batchCreate up to 1,000 passports in one call
GET/passports/{id}Read one passport with address and status
GET/passports/{id}/eventsRead a passport’s events
POST/passports/{id}/eventsReport an event, such as repair or waste
POST/models/validateCheck a draft, save nothing
POST/passportsCreate one passport
PATCH/passports/{id}Change date, batch or place
GET/passports/{id}/componentsRead components
POST/passports/{id}/componentsInstall a component
PATCH/passports/{id}/components/{cid}Change or remove a component
POST/passports/{id}/components/{cid}/replaceReplace a component
GET/passports/{id}/telemetryRead measurement series
POST/passports/{id}/telemetryReport measurements
GET/certificatesList evidence
GET/certificates/{id}Evidence with download link
GET/suppliersList suppliers
GET/supplier-requestsList data requests
POST/supplier-requestsSend a supplier request
GET/supplier-requests/{id}Read a request with supplied values
POST/supplier-requests/{id}/acceptAccept supplied values into the model
GET/auditRead the audit trail

Example: create passports from the ERP

curl -X POST https://app.digitalbatterypass.eu/api/v1/passports/batch \
  -H "Authorization: Bearer $BATTERYPASS_KEY" \
  -H "Idempotency-Key: erp-4711" \
  -H "Content-Type: application/json" \
  -d '{
  "model_code": "BX-48V",
  "on_conflict": "skip",
  "items": [
    { "serial": "SN-0001", "manufactured_at": "2027-03-01", "batch": "L2027-03" },
    { "serial": "SN-0002", "manufactured_at": "2027-03-01", "batch": "L2027-03" }
  ]
}'

Response

201 Created
HTTP/1.1 201 Created
X-Request-Id: req_4f7a91c2d03e8b56

{
  "created": 1,
  "skipped": 1,
  "skipped_serials": ["SN-0002"],
  "items": [
    {
      "id": "7KM2XQ9RTA",
      "serial": "SN-0001",
      "status": "original",
      "url": "https://app.digitalbatterypass.eu/p/7KM2XQ9RTA"
    }
  ]
}

Errors

422
HTTP/1.1 422 Unprocessable Entity

{
  "error": {
    "code": "invalid_serial",
    "message": "Serial number is missing or contains invalid characters.",
    "field": "items[3].serial",
    "request_id": "req_a03c5e17b92d4f68"
  }
}
HTTPCodeMeaning
400invalid_requestRequest is not valid JSON or contains unknown fields
401unauthorizedKey is missing or invalid
403insufficient_scopeThe key lacks the required right
403plan_requiredLive keys require the Enterprise plan; with Pro only for BMS measurements
403email_not_verifiedThe company’s email address is not confirmed yet
403quota_exceededThe plan’s quota is used up
404not_foundObject does not exist or belongs to another company
409duplicate_serialSerial number already exists in this model (with on_conflict: fail)
409duplicate_modelThe model code is already taken
409idempotency_conflictThe Idempotency-Key was used for a different request
413payload_too_largeThe request is larger than 2 MB
422invalid_serialA serial number is invalid; the response names the field. Nothing is saved.
422invalid_dateA date does not match the format YYYY-MM-DD
422out_of_rangeA measurement is outside the allowed range
422invalid_gtinThe GTIN has a wrong length or check digit
422validation_failedAnother value breaks the rules
429rate_limitedToo many requests; retry after Retry-After
500internal_errorAn error on our side. Safe to retry with the same Idempotency-Key.

Limits

Requests per minute and keyLive 300, test 60
Passports per call1.000
Request size2 MB
Entries per list page100, at most 500
Active keys per company10
Live keysEnterprise with all scopes, Pro only with the scopes for BMS measurements. Test keys are available in every plan.

Planning more than 100,000 passports a year? Please talk to us in advance.

Permissions

Each key only gets the rights the system needs. If one is missing, the API responds with 403 and insufficient_scope. In the app you choose a template: All rights, ERP, BMS or Read only.

RightAllows
models:readRead models and check drafts
models:writeCreate and change models
passports:readRead passports, events and components
passports:writeCreate and change passports, report events, install and replace components
telemetry:read telemetry:writeRead and report measurements
certificates:readRead and download evidence
suppliers:read suppliers:writeRead suppliers and data requests, send and accept requests
audit:readRead the audit trail

Requests and responses

Lists come in pages with data, has_more and next_cursor. Pass the value of next_cursor as cursor. Unknown fields are rejected so typos show up immediately. With PATCH, a missing field stays unchanged and null clears it.

HeaderMeaning
Idempotency-KeyRetry without a second record, valid for 7 days. The ERP document number works well.
X-Batterypass-Dry-Run: trueEven a live key only checks this request and saves nothing.
X-Request-IdID of the call, also in errors and in the app’s log
X-RateLimit-Limit X-RateLimit-RemainingQuota for the current minute
Idempotent-Replayedtrue when a stored response was replayed

SDK and API console

Available

Two lean clients without dependencies: they retry requests safely, page through lists themselves and split large volumes into calls of 1,000 passports. Both are single files to copy into your project. The API console is in the app under Settings, API keys. The libraries are part of the Enterprise plan.

from batterypass import Batterypass

bp = Batterypass("bp_test_...")
print(bp.me()["organization"]["plan"])

items = [{"serial": f"SN-{i:06}"} for i in range(5000)]
print(bp.create_passports_all("BX-48V", items))

for passport in bp.list_all("/passports", model_code="BX-48V"):
    print(passport["serial"], passport["url"])

Components

Available

Record which modules, cells or BMS are installed in a battery. A serial number can only be installed once at a time per passport. On replacement, the old part stays on record with its removal date.

cURL
curl -X POST https://app.digitalbatterypass.eu/api/v1/passports/7KM2XQ9RTA/components \
  -H "Authorization: Bearer $BATTERYPASS_KEY" -H "Content-Type: application/json" \
  -d '{"kind": "module", "label": "Modul 1", "serial": "M-0001", "supplier": "Zellwerk GmbH"}'

curl -X POST https://app.digitalbatterypass.eu/api/v1/passports/7KM2XQ9RTA/components/12/replace \
  -H "Authorization: Bearer $BATTERYPASS_KEY" -H "Content-Type: application/json" \
  -d '{"serial": "M-0002", "note": "Modul nach Defekt getauscht"}'

Allowed types are pack, rack, module, cell, bms and other.

Measurements

Available

Report data from the BMS, individually or up to 1,000 measurements with items. Read the series with since and until. Measurements are available from the Pro plan. They appear in the app and for entitled parties, not on the public passport page.

cURL
curl -X POST https://app.digitalbatterypass.eu/api/v1/passports/7KM2XQ9RTA/telemetry \
  -H "Authorization: Bearer $BATTERYPASS_KEY" -H "Content-Type: application/json" \
  -d '{"recorded_at": "2027-03-01T10:00:00Z", "soh_pct": 94.5, "cycle_count": 120}'
FieldRange
recorded_atISO 8601
soh_pct0–100
soc_pct0–100
capacity_kwh≥ 0
remaining_capacity_ah≥ 0
internal_resistance_mohm≥ 0
cycle_count≥ 0, integer
temp_min_c temp_max_c≥ −273
energy_throughput_kwh≥ 0
negative_eventdeep_discharge, overheat, accident
notemax. 500

Evidence

Available

Upload test reports, declarations of conformity and similar documents in the app on the model: PDF, PNG or JPG up to 10 MB. Through the API you read the list and get a download link valid for 15 minutes. Each file has a SHA-256 checksum.

cURL
curl -s "https://app.digitalbatterypass.eu/api/v1/certificates?model_code=BX-48V" -H "Authorization: Bearer $BATTERYPASS_KEY"
curl -s https://app.digitalbatterypass.eu/api/v1/certificates/42 -H "Authorization: Bearer $BATTERYPASS_KEY"

Suppliers and data requests

Available

Request values from suppliers. They get an email with a link valid for 30 days and enter only the requested fields, without an account. Supplied values only reach the model after your approval. Available from the Starter plan, at most 20 requests per hour.

cURL
curl -X POST https://app.digitalbatterypass.eu/api/v1/supplier-requests \
  -H "Authorization: Bearer $BATTERYPASS_KEY" -H "Content-Type: application/json" \
  -d '{"model_code": "BX-48V", "supplier_name": "Zellwerk GmbH", "supplier_email": "daten@zellwerk.example",
       "fields": ["chemistry", "composition_cathode"], "message": "Bitte bis Monatsende"}'

curl -s "https://app.digitalbatterypass.eu/api/v1/supplier-requests?status=submitted" -H "Authorization: Bearer $BATTERYPASS_KEY"
curl -X POST https://app.digitalbatterypass.eu/api/v1/supplier-requests/7/accept -H "Authorization: Bearer $BATTERYPASS_KEY"

GS1 Digital Link

Available

Set a GTIN with a valid check digit on the model. The GS1 address from GTIN and serial number then leads to the passport page and appears in the API as gs1_link. Your QR codes still contain the fixed passport address, but you can create your own codes from the GS1 link. You get the GTIN itself from GS1.

URL
https://app.digitalbatterypass.eu/01/{GTIN}/21/{SERIENNUMMER}
https://app.digitalbatterypass.eu/01/04012345678901/21/SN-0001

Audit trail

Available

GET /audit returns all logged changes of the company, in pages and optionally from a point in time with since. Changes via the API carry the key’s name. In the app, administrators also see the latest calls per key.

EU registry

Test in the real registry pending

The app creates the key pair for your service account. The private key stays encrypted with us. The public key goes into the registry. Your company must first be verified there with a qualified seal.

Only released, complete passports are submitted, in batches of at most 100. App and API show the status. The registry reads the passport address as JSON; with its access token it also receives the protected views. Invalid tokens are rejected.

Built from the Commission’s technical documents of 30 Oct 2026 and tested against our own test server. The test in the real registry is still pending.

cURL
curl -X POST https://app.digitalbatterypass.eu/api/v1/registry/submissions \
  -H "Authorization: Bearer $BATTERYPASS_KEY" \
  -H "Content-Type: application/json" \
  -d '{"model_code":"LMT-48V"}'

curl https://app.digitalbatterypass.eu/api/v1/registry/submissions \
  -H "Authorization: Bearer $BATTERYPASS_KEY"

Release and proof

Available

With publish: false you create drafts. They cannot be reached publicly until you release them. Every change to master data becomes a new version linked by hash to the previous one. At /p/ID/proof anyone can recalculate the public state.

cURL
POST /api/v1/passports/batch        {"model_code":"LMT-48V","publish":false,"items":[...]}
POST /api/v1/passports/PASS-ID/publish
GET  /api/v1/models/42/versions
GET  /p/PASS-ID/proof

Versions

The major version is in the path. Within v1, only fields and endpoints are added. Planned but not yet available: webhooks.

VersionDateChange
1.2.02026-11-06Registry, release, versions, further measurements for the protected EU views
1.1.02026-11-06Components, measurements, evidence, suppliers, audit, single passport, GS1, granular rights, dry-run header, OpenAPI and health endpoint
1.0.02026-11-06Models, passports, events, keys, test mode, idempotency

Frequently asked questions

Short answers for your integration.

How do I test without creating real passports?

With a test key. It checks everything as in live operation and saves nothing.

What should I do after a timeout?

Send the same request again with the same Idempotency-Key. No second record is created.

How do I find the passport for a serial number?

With GET /passports?serial=… and model_code if needed.

Can I delete passports via the API?

No. Report the end of life as an event with the status waste.

How many passports are possible?

1,000 per call, 300 calls per minute. Your plan and our hosting also set limits. If you plan more than 100,000 passports a year, please talk to us in advance.

Try the import with your own file.

The Pilot plan is free and covers one model and 25 passports per year.