batterypass
Product
How it works Features Comparison
Solutions
Energy storage (BESS) Light means of transport Industrial batteries Electric vehicles Suppliers
Compliance
Compliance overview EU Battery Regulation Obligation check Security and privacy
Resources
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
Pricing About us
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.

50.000passports per file
38data 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 8 MB and 50,000 rows per file.
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.batterypass2027.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.batterypass2027.eu/p/{PASS-ID}
https://app.batterypass2027.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')

Data fields

Available

These 38 fields exist in the app today, in simplified form based on Annex XIII. They are maintained in the model form. The categories are lmt, industrie, ev, sli and geraet.

General information6
FieldTechnical nameTypeVisible toRequired
Manufacturer (name)manufacturer_nametextPublicAll passport categories
Manufacturer (address)manufacturer_addresstextPublicAll passport categories
Contact (email or website)manufacturer_contacttextPublicAll passport categories
Place of manufacture (default)manufacturing_placetextPublicAll passport categories
Weightweight_kgnumber · kgPublicAll passport categories
Warranty / guaranteewarrantytextPublicOptional
Materials & substances6
FieldTechnical nameTypeVisible toRequired
Battery chemistrychemistrytextPublicAll passport categories
Hazardous substanceshazardous_substancestextPublicAll passport categories
Critical raw materialscritical_raw_materialstextPublicAll passport categories
Cathode compositioncomposition_cathodetextLegitimate interestAll passport categories
Anode compositioncomposition_anodetextLegitimate interestAll passport categories
Electrolyte compositioncomposition_electrolytetextLegitimate interestAll passport categories
Performance & durability11
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
Rated energyrated_energy_kwhnumber · kWhPublicAll passport categories
Power (original)rated_power_wnumber · WPublicindustrie, ev
Expected lifetimeexpected_lifetime_cyclesnumber · ZyklenPublicAll passport categories
Temperature range fromtemp_min_cnumber · °CPublicAll passport categories
Temperature range totemp_max_cnumber · °CPublicAll passport categories
Energy efficiency (round trip)round_trip_efficiency_pctnumber · %Publicindustrie, ev
Internal resistanceinternal_resistance_mohmnumber · mΩPublicOptional
Carbon footprint & recycled content6
FieldTechnical nameTypeVisible toRequired
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
Share of renewable contentrenewable_content_pctnumber · %PublicOptional
Conformity & labelling4
FieldTechnical nameTypeVisible toRequired
EU declaration of conformity (link)doc_urlurlPublicAll passport categories
Labels & symbolslabels_symbolstextPublicAll passport categories
Due diligence report (link)due_diligence_urlurlPublicApplies later
Return & disposalend_of_life_infotextPublicAll passport categories
Dismantling, repair & spare parts4
FieldTechnical nameTypeVisible toRequired
Disassembly instructionsdismantling_infotextLegitimate interestAll passport categories
Component part numberspart_numberstextLegitimate interestAll passport categories
Spare parts sourcespare_parts_contacttextLegitimate interestAll passport categories
Safety measuressafety_measurestextLegitimate interestAll passport categories
Test reports1
FieldTechnical nameTypeVisible toRequired
Test reports (links or references)test_reportstextAuthorities 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.batterypass2027.eu/api/v1

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.batterypass2027.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.batterypass2027.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.batterypass2027.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 Pro or Enterprise plan
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 keysPro and Enterprise. 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.

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.batterypass2027.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.batterypass2027.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, not on the public passport page.

cURL
curl -X POST https://app.batterypass2027.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.batterypass2027.eu/api/v1/certificates?model_code=BX-48V" -H "Authorization: Bearer $BATTERYPASS_KEY"
curl -s https://app.batterypass2027.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.batterypass2027.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.batterypass2027.eu/api/v1/supplier-requests?status=submitted" -H "Authorization: Bearer $BATTERYPASS_KEY"
curl -X POST https://app.batterypass2027.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.batterypass2027.eu/01/{GTIN}/21/{SERIENNUMMER}
https://app.batterypass2027.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.

Versions

The major version is in the path. Within v1, only fields and endpoints are added. Planned but not yet available: webhooks, access for authorities and recyclers, and a verifiable change chain.

VersionDateChange
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.