{"openapi":"3.1.0","info":{"title":"Collecta DPP API","version":"1.0.0","summary":"Create and maintain EU battery passports (Regulation (EU) 2023/1542) from your own systems.","description":"Every battery placed on the EU market from 18 February 2027 needs a digital passport. This API lets an ERP, MES or BMS create battery models, issue one passport per physical battery, publish them and keep their dynamic data current.\n\nAuthenticate with an API key created in the app (Organisation → API keys): `Authorization: Bearer dpp_live_…`. Keys carry `read` and/or `write` scopes. Records are never deleted over the API — a passport must stay available for ten years.\n\n**Conventions.** Lists are cursor-paginated (`limit`, `cursor` → `data`, `has_more`, `next_cursor`). Writes accept `Idempotency-Key`. `dpp_test_` keys and the `X-DPP-Dry-Run: true` header validate a write without storing it. Every response carries `x-request-id`; every error body carries `request_id`. Within v1 only additive changes are made.","contact":{"name":"Collecta DPP","url":"https://www.collectadpp.com/developers"},"license":{"name":"Proprietary — API terms of service","url":"https://www.collectadpp.com/terms"}},"servers":[{"url":"https://dppapi-production.up.railway.app/v1"}],"security":[{"apiKey":[]}],"tags":[{"name":"Account","description":"Who the key belongs to, and the EU data-point catalogue."},{"name":"Models","description":"Battery models: the data every battery of a type shares."},{"name":"Batteries","description":"Physical batteries. Creating one issues its passport, as a draft."},{"name":"Passports","description":"Publishing, dynamic data, lifecycle and QR codes."},{"name":"Fleet","description":"The same change across many passports."},{"name":"Data portability","description":"Everything you hold with us, in one export."},{"name":"Documents","description":"Evidence attached to models: declarations of conformity, test reports, data sheets."},{"name":"Audit","description":"The integrity log."},{"name":"Webhooks","description":"Be told about changes instead of polling."},{"name":"Suppliers","description":"Ask suppliers for the data you do not hold; accept what they send."}],"paths":{"/me":{"get":{"tags":["Account"],"summary":"Who am I","description":"Connection test: the key (name, scopes, mode), the organisation, its plan and this year's usage.","responses":{"200":{"description":"The key and its organisation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Me"}}},"headers":{"x-request-id":{"description":"Unique id of this request. Quote it to support.","schema":{"type":"string"}},"x-ratelimit-limit":{"description":"Requests allowed per minute for this key.","schema":{"type":"integer"}},"x-ratelimit-remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"x-ratelimit-reset":{"description":"Seconds until the window resets.","schema":{"type":"integer"}}}},"401":{"$ref":"#/components/responses/E401"},"402":{"$ref":"#/components/responses/E402"},"429":{"$ref":"#/components/responses/E429"}},"operationId":"getMe"}},"/field-catalog":{"get":{"tags":["Account"],"summary":"EU data-point catalogue","description":"All 71 data points of DG GROW's \"Digital Batteries Passport – data points by category\" v2.0 (15 Aug 2026). Each names its obligation per category (`required`, `conditional`, `na`) and where it lives in this API: a field (with its name, unit, Annex XIII point, access tier and the endpoint that writes it), a model attribute, a document, or a platform-managed value.","parameters":[{"name":"category","in":"query","required":false,"schema":{"type":"string","enum":["EV","LMT","INDUSTRIAL"]},"description":"Only this category's obligation."}],"responses":{"200":{"description":"The catalogue.","content":{"application/json":{"schema":{"type":"object"}}},"headers":{"x-request-id":{"description":"Unique id of this request. Quote it to support.","schema":{"type":"string"}},"x-ratelimit-limit":{"description":"Requests allowed per minute for this key.","schema":{"type":"integer"}},"x-ratelimit-remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"x-ratelimit-reset":{"description":"Seconds until the window resets.","schema":{"type":"integer"}}}},"401":{"$ref":"#/components/responses/E401"},"429":{"$ref":"#/components/responses/E429"}},"operationId":"getFieldCatalog"}},"/openapi.json":{"get":{"tags":["Account"],"summary":"This document","security":[],"responses":{"200":{"description":"OpenAPI 3.1","content":{"application/json":{"schema":{"type":"object"}}},"headers":{"x-request-id":{"description":"Unique id of this request. Quote it to support.","schema":{"type":"string"}},"x-ratelimit-limit":{"description":"Requests allowed per minute for this key.","schema":{"type":"integer"}},"x-ratelimit-remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"x-ratelimit-reset":{"description":"Seconds until the window resets.","schema":{"type":"integer"}}}},"429":{"$ref":"#/components/responses/E429"}},"operationId":"getOpenapiJson"}},"/models":{"get":{"tags":["Models"],"summary":"List models","description":"Newest first, each with its completeness for its category.","parameters":[{"$ref":"#/components/parameters/Limit"},{"$ref":"#/components/parameters/Cursor"},{"name":"category","in":"query","required":false,"schema":{"type":"string","enum":["EV","LMT","INDUSTRIAL"]},"description":"Filter by battery category."},{"name":"updated_since","in":"query","required":false,"schema":{"type":"string","format":"date-time"},"description":"Only models changed since then."},{"name":"complete","in":"query","required":false,"schema":{"type":"string","enum":["true","false"]},"description":"Only complete, or only incomplete, models."}],"responses":{"200":{"description":"A page of models.","content":{"application/json":{"schema":{"type":"object","required":["data","has_more","next_cursor"],"properties":{"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"category":{"type":"string","enum":["EV","LMT","INDUSTRIAL"]},"capacityKwh":{"type":"number"},"chemistry":{"type":"string"},"fields":{"type":"object","additionalProperties":true,"description":"Template field values keyed by field name — see GET /v1/field-catalog."},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"requiredFilled":{"type":"integer"},"requiredTotal":{"type":"integer"},"complete":{"type":"boolean","description":"Every field, attribute and document this category owes is present."},"itemCount":{"type":"integer"},"publishedCount":{"type":"integer"}}}},"has_more":{"type":"boolean"},"next_cursor":{"type":["string","null"],"description":"Pass as `cursor` to get the next page."}}}}},"headers":{"x-request-id":{"description":"Unique id of this request. Quote it to support.","schema":{"type":"string"}},"x-ratelimit-limit":{"description":"Requests allowed per minute for this key.","schema":{"type":"integer"}},"x-ratelimit-remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"x-ratelimit-reset":{"description":"Seconds until the window resets.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/E400"},"401":{"$ref":"#/components/responses/E401"},"429":{"$ref":"#/components/responses/E429"}},"operationId":"getModels"},"post":{"tags":["Models"],"summary":"Create a model","description":"Category and capacity decide which fields the passport needs. Industrial batteries are in scope above 2 kWh.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"templateKey":{"type":"string","minLength":1,"default":"battery"},"category":{"type":"string","enum":["LMT","INDUSTRIAL","EV"]},"industrialExternalStorage":{"type":"boolean","default":false},"name":{"type":"string","minLength":1,"maxLength":200},"capacityKwh":{"type":"number","exclusiveMinimum":0},"chemistry":{"type":"string","minLength":1,"maxLength":120},"fields":{"type":"object","additionalProperties":{}}},"required":["category","name","capacityKwh","chemistry"]},"example":{"category":"EV","name":"PowerCell EV-90","capacityKwh":90,"chemistry":"Li-ion NMC811","fields":{"manufacturerName":"Nordvolt Energy GmbH","modelDesignation":"NV-EV-90","ratedCapacity":225,"nominalVoltage":400}}}}},"responses":{"200":{"$ref":"#/components/responses/DryRun"},"201":{"description":"Created.","content":{"application/json":{"schema":{"type":"object","description":"A battery model: the data every battery of this type shares (model-static layer).","properties":{"id":{"type":"string"},"name":{"type":"string"},"category":{"type":"string","enum":["EV","LMT","INDUSTRIAL"]},"capacityKwh":{"type":"number"},"chemistry":{"type":"string"},"fields":{"type":"object","additionalProperties":true,"description":"Template field values keyed by field name — see GET /v1/field-catalog."},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}}}},"headers":{"x-request-id":{"description":"Unique id of this request. Quote it to support.","schema":{"type":"string"}},"x-ratelimit-limit":{"description":"Requests allowed per minute for this key.","schema":{"type":"integer"}},"x-ratelimit-remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"x-ratelimit-reset":{"description":"Seconds until the window resets.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/E400"},"401":{"$ref":"#/components/responses/E401"},"402":{"$ref":"#/components/responses/E402"},"403":{"$ref":"#/components/responses/E403"},"409":{"$ref":"#/components/responses/E409"},"429":{"$ref":"#/components/responses/E429"}},"operationId":"postModels","parameters":[{"$ref":"#/components/parameters/IdempotencyKey"},{"$ref":"#/components/parameters/DryRun"}]}},"/models/{id}":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Model id"}],"get":{"tags":["Models"],"summary":"Get a model","responses":{"200":{"description":"The model.","content":{"application/json":{"schema":{"type":"object","description":"A battery model: the data every battery of this type shares (model-static layer).","properties":{"id":{"type":"string"},"name":{"type":"string"},"category":{"type":"string","enum":["EV","LMT","INDUSTRIAL"]},"capacityKwh":{"type":"number"},"chemistry":{"type":"string"},"fields":{"type":"object","additionalProperties":true,"description":"Template field values keyed by field name — see GET /v1/field-catalog."},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}}}},"headers":{"x-request-id":{"description":"Unique id of this request. Quote it to support.","schema":{"type":"string"}},"x-ratelimit-limit":{"description":"Requests allowed per minute for this key.","schema":{"type":"integer"}},"x-ratelimit-remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"x-ratelimit-reset":{"description":"Seconds until the window resets.","schema":{"type":"integer"}}}},"401":{"$ref":"#/components/responses/E401"},"404":{"$ref":"#/components/responses/E404"},"429":{"$ref":"#/components/responses/E429"}},"operationId":"getModelsById"},"patch":{"tags":["Models"],"summary":"Update a model","description":"Field values are merged: fields you leave out are unchanged.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":200},"chemistry":{"type":"string","minLength":1,"maxLength":120},"fields":{"type":"object","additionalProperties":{}}}},"example":{"fields":{"minVoltage":300,"maxVoltage":450}}}}},"responses":{"200":{"description":"The updated model.","content":{"application/json":{"schema":{"type":"object","description":"A battery model: the data every battery of this type shares (model-static layer).","properties":{"id":{"type":"string"},"name":{"type":"string"},"category":{"type":"string","enum":["EV","LMT","INDUSTRIAL"]},"capacityKwh":{"type":"number"},"chemistry":{"type":"string"},"fields":{"type":"object","additionalProperties":true,"description":"Template field values keyed by field name — see GET /v1/field-catalog."},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}}}},"headers":{"x-request-id":{"description":"Unique id of this request. Quote it to support.","schema":{"type":"string"}},"x-ratelimit-limit":{"description":"Requests allowed per minute for this key.","schema":{"type":"integer"}},"x-ratelimit-remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"x-ratelimit-reset":{"description":"Seconds until the window resets.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/E400"},"401":{"$ref":"#/components/responses/E401"},"403":{"$ref":"#/components/responses/E403"},"404":{"$ref":"#/components/responses/E404"},"409":{"$ref":"#/components/responses/E409"},"429":{"$ref":"#/components/responses/E429"}},"operationId":"patchModelsById","parameters":[{"$ref":"#/components/parameters/IdempotencyKey"},{"$ref":"#/components/parameters/DryRun"}]}},"/models/{id}/completeness":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Model id"}],"get":{"tags":["Models"],"summary":"Missing-field analysis","description":"What this model still owes for its category: fields, core attributes (chemistry) and documents (EU declaration of conformity).","responses":{"200":{"description":"The analysis.","content":{"application/json":{"schema":{"type":"object","properties":{"category":{"type":"string"},"requiredTotal":{"type":"integer"},"requiredFilled":{"type":"integer"},"complete":{"type":"boolean"},"missing":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"label":{"type":"string"},"point":{"type":"integer","description":"Annex XIII point (1 public … 4 dynamic)."},"annexRef":{"type":"string"},"granularity":{"type":"string","enum":["model","item"]}}}},"conditionalUnset":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"label":{"type":"string"},"point":{"type":"integer","description":"Annex XIII point (1 public … 4 dynamic)."},"annexRef":{"type":"string"},"granularity":{"type":"string","enum":["model","item"]}}}}}}}},"headers":{"x-request-id":{"description":"Unique id of this request. Quote it to support.","schema":{"type":"string"}},"x-ratelimit-limit":{"description":"Requests allowed per minute for this key.","schema":{"type":"integer"}},"x-ratelimit-remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"x-ratelimit-reset":{"description":"Seconds until the window resets.","schema":{"type":"integer"}}}},"401":{"$ref":"#/components/responses/E401"},"404":{"$ref":"#/components/responses/E404"},"429":{"$ref":"#/components/responses/E429"}},"operationId":"getModelsByIdCompleteness"}},"/models/{id}/documents":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Model id"}],"post":{"tags":["Models"],"summary":"Upload a document","description":"Multipart upload. `type` names the document, e.g. `EU Declaration of Conformity` or `Test Report`; `point` 1 is public, 3 is authority-only.","requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","required":["file","type"],"properties":{"file":{"type":"string","format":"binary"},"type":{"type":"string"},"name":{"type":"string"},"point":{"type":"string","enum":["1","3"]}}}}}},"responses":{"200":{"$ref":"#/components/responses/DryRun"},"201":{"description":"Stored.","content":{"application/json":{"schema":{"type":"object"}}},"headers":{"x-request-id":{"description":"Unique id of this request. Quote it to support.","schema":{"type":"string"}},"x-ratelimit-limit":{"description":"Requests allowed per minute for this key.","schema":{"type":"integer"}},"x-ratelimit-remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"x-ratelimit-reset":{"description":"Seconds until the window resets.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/E400"},"401":{"$ref":"#/components/responses/E401"},"403":{"$ref":"#/components/responses/E403"},"404":{"$ref":"#/components/responses/E404"},"429":{"$ref":"#/components/responses/E429"}},"operationId":"postModelsByIdDocuments","parameters":[{"$ref":"#/components/parameters/IdempotencyKey"},{"$ref":"#/components/parameters/DryRun"}]}},"/models/{id}/items":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Model id"}],"get":{"tags":["Batteries"],"summary":"List a model's batteries","parameters":[{"name":"page","in":"query","schema":{"type":"integer","minimum":1,"default":1},"description":"Page number."},{"name":"pageSize","in":"query","schema":{"type":"integer","minimum":1,"maximum":200,"default":12},"description":"Rows per page."},{"name":"status","in":"query","schema":{"type":"string","enum":["draft","pending","published","attention","repurposed","waste","recycled"]},"description":"Derived display status."},{"name":"q","in":"query","schema":{"type":"string"},"description":"Serial number or identifier, case-insensitive."}],"responses":{"200":{"description":"A page of batteries with their display status.","content":{"application/json":{"schema":{"type":"object"}}},"headers":{"x-request-id":{"description":"Unique id of this request. Quote it to support.","schema":{"type":"string"}},"x-ratelimit-limit":{"description":"Requests allowed per minute for this key.","schema":{"type":"integer"}},"x-ratelimit-remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"x-ratelimit-reset":{"description":"Seconds until the window resets.","schema":{"type":"integer"}}}},"401":{"$ref":"#/components/responses/E401"},"404":{"$ref":"#/components/responses/E404"},"429":{"$ref":"#/components/responses/E429"}},"operationId":"getModelsByIdItems"}},"/items":{"post":{"tags":["Batteries"],"summary":"Create one battery","description":"Issues its unique identifier and a draft passport. Publishing is a separate, deliberate step.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"uniqueIdentifier":{"type":"string","maxLength":120},"foreignResolverUrl":{"type":"string","format":"uri","maxLength":500},"importedFrom":{"type":"string","maxLength":200},"modelId":{"type":"string","minLength":1},"serialNumber":{"type":"string","maxLength":200},"productionBatchId":{"type":"string"},"dateOfManufacture":{"type":"string","format":"date-time"},"placeOfManufacture":{"type":"string","maxLength":300},"placedOnMarketAt":{"type":"string","format":"date-time"},"putIntoServiceAt":{"type":"string","format":"date-time"},"fields":{"type":"object","additionalProperties":{}}},"required":["modelId"]},"example":{"modelId":"<model id>","serialNumber":"EVX-100001","dateOfManufacture":"2026-09-01","placeOfManufacture":"Leipzig Gigafactory"}}}},"responses":{"200":{"$ref":"#/components/responses/DryRun"},"201":{"description":"Created.","content":{"application/json":{"schema":{"type":"object","description":"One physical battery. Each battery has exactly one passport (Art. 77(1)).","properties":{"id":{"type":"string"},"uniqueIdentifier":{"type":"string","description":"Immutable, resolvable passport identifier (ISO/IEC 15459)."},"serialNumber":{"type":["string","null"]},"dateOfManufacture":{"type":["string","null"],"format":"date-time"},"placeOfManufacture":{"type":["string","null"]},"fields":{"type":"object","additionalProperties":true},"passport":{"type":"object","properties":{"id":{"type":"string"},"status":{"type":"string","enum":["ORIGINAL","REPURPOSED","REUSED","REMANUFACTURED","WASTE"]},"lifecycleState":{"type":"string"},"publishedAt":{"type":["string","null"],"format":"date-time"},"qrResolverUrl":{"type":"string"}}}}}}},"headers":{"x-request-id":{"description":"Unique id of this request. Quote it to support.","schema":{"type":"string"}},"x-ratelimit-limit":{"description":"Requests allowed per minute for this key.","schema":{"type":"integer"}},"x-ratelimit-remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"x-ratelimit-reset":{"description":"Seconds until the window resets.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/E400"},"401":{"$ref":"#/components/responses/E401"},"402":{"$ref":"#/components/responses/E402"},"403":{"$ref":"#/components/responses/E403"},"404":{"$ref":"#/components/responses/E404"},"409":{"$ref":"#/components/responses/E409"},"422":{"$ref":"#/components/responses/E422"},"429":{"$ref":"#/components/responses/E429"}},"operationId":"postItems","parameters":[{"$ref":"#/components/parameters/IdempotencyKey"},{"$ref":"#/components/parameters/DryRun"}]}},"/items/batch":{"post":{"tags":["Batteries"],"summary":"Create many batteries","description":"Up to 1,000 batteries in one call, in one transaction: either all are created or none. Give explicit `rows` (serials you already printed) or a `count` with an optional `serialPrefix`. Each battery gets its identifier and a draft passport. Send an `Idempotency-Key` so a retried request never creates them twice.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"modelId":{"type":"string","minLength":1},"count":{"type":"integer","minimum":1,"maximum":1000,"default":1},"serialPrefix":{"type":"string","maxLength":60},"placeOfManufacture":{"type":"string","maxLength":300},"dateOfManufacture":{"type":"string","format":"date-time"},"rows":{"type":"array","items":{"type":"object","properties":{"serialNumber":{"type":"string","minLength":1,"maxLength":200},"dateOfManufacture":{"type":"string","format":"date-time"},"placeOfManufacture":{"type":"string","maxLength":300},"fields":{"type":"object","additionalProperties":{}}},"required":["serialNumber"]},"maxItems":1000}},"required":["modelId"]},"example":{"modelId":"<model id>","placeOfManufacture":"Leipzig Gigafactory","dateOfManufacture":"2026-09-01","rows":[{"serialNumber":"EVX-100001"},{"serialNumber":"EVX-100002"}]}}}},"responses":{"200":{"$ref":"#/components/responses/DryRun"},"201":{"description":"Created.","content":{"application/json":{"schema":{"type":"object","properties":{"count":{"type":"integer"},"items":{"type":"array","items":{"type":"object","description":"One physical battery. Each battery has exactly one passport (Art. 77(1)).","properties":{"id":{"type":"string"},"uniqueIdentifier":{"type":"string","description":"Immutable, resolvable passport identifier (ISO/IEC 15459)."},"serialNumber":{"type":["string","null"]},"dateOfManufacture":{"type":["string","null"],"format":"date-time"},"placeOfManufacture":{"type":["string","null"]},"fields":{"type":"object","additionalProperties":true},"passport":{"type":"object","properties":{"id":{"type":"string"},"status":{"type":"string","enum":["ORIGINAL","REPURPOSED","REUSED","REMANUFACTURED","WASTE"]},"lifecycleState":{"type":"string"},"publishedAt":{"type":["string","null"],"format":"date-time"},"qrResolverUrl":{"type":"string"}}}}}}}}}},"headers":{"x-request-id":{"description":"Unique id of this request. Quote it to support.","schema":{"type":"string"}},"x-ratelimit-limit":{"description":"Requests allowed per minute for this key.","schema":{"type":"integer"}},"x-ratelimit-remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"x-ratelimit-reset":{"description":"Seconds until the window resets.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/E400"},"401":{"$ref":"#/components/responses/E401"},"402":{"$ref":"#/components/responses/E402"},"403":{"$ref":"#/components/responses/E403"},"404":{"$ref":"#/components/responses/E404"},"409":{"$ref":"#/components/responses/E409"},"429":{"$ref":"#/components/responses/E429"}},"operationId":"postItemsBatch","parameters":[{"$ref":"#/components/parameters/IdempotencyKey"},{"$ref":"#/components/parameters/DryRun"}]}},"/items/{id}":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Battery item id"}],"get":{"tags":["Batteries"],"summary":"Get a battery","responses":{"200":{"description":"The battery and its passport.","content":{"application/json":{"schema":{"type":"object","description":"One physical battery. Each battery has exactly one passport (Art. 77(1)).","properties":{"id":{"type":"string"},"uniqueIdentifier":{"type":"string","description":"Immutable, resolvable passport identifier (ISO/IEC 15459)."},"serialNumber":{"type":["string","null"]},"dateOfManufacture":{"type":["string","null"],"format":"date-time"},"placeOfManufacture":{"type":["string","null"]},"fields":{"type":"object","additionalProperties":true},"passport":{"type":"object","properties":{"id":{"type":"string"},"status":{"type":"string","enum":["ORIGINAL","REPURPOSED","REUSED","REMANUFACTURED","WASTE"]},"lifecycleState":{"type":"string"},"publishedAt":{"type":["string","null"],"format":"date-time"},"qrResolverUrl":{"type":"string"}}}}}}},"headers":{"x-request-id":{"description":"Unique id of this request. Quote it to support.","schema":{"type":"string"}},"x-ratelimit-limit":{"description":"Requests allowed per minute for this key.","schema":{"type":"integer"}},"x-ratelimit-remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"x-ratelimit-reset":{"description":"Seconds until the window resets.","schema":{"type":"integer"}}}},"401":{"$ref":"#/components/responses/E401"},"404":{"$ref":"#/components/responses/E404"},"429":{"$ref":"#/components/responses/E429"}},"operationId":"getItemsById"}},"/passports/{id}":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Passport id"}],"get":{"tags":["Passports"],"summary":"Get a passport","description":"The passport with its battery, model, dynamic events and status.","responses":{"200":{"description":"The passport.","content":{"application/json":{"schema":{"type":"object"}}},"headers":{"x-request-id":{"description":"Unique id of this request. Quote it to support.","schema":{"type":"string"}},"x-ratelimit-limit":{"description":"Requests allowed per minute for this key.","schema":{"type":"integer"}},"x-ratelimit-remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"x-ratelimit-reset":{"description":"Seconds until the window resets.","schema":{"type":"integer"}}}},"401":{"$ref":"#/components/responses/E401"},"404":{"$ref":"#/components/responses/E404"},"429":{"$ref":"#/components/responses/E429"}},"operationId":"getPassportsById"}},"/passports/{id}/publish":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Passport id"}],"post":{"tags":["Passports"],"summary":"Publish a passport","description":"Makes it resolvable at the public URL encoded in its QR code — a ten-year commitment. Refused with 422 `publish_blocked` and the list of `blockers` when the model is incomplete for its category or the battery has no place of manufacture. Dry-run it first to see the answer without publishing.","responses":{"200":{"description":"Published (or already was).","content":{"application/json":{"schema":{"type":"object"}}},"headers":{"x-request-id":{"description":"Unique id of this request. Quote it to support.","schema":{"type":"string"}},"x-ratelimit-limit":{"description":"Requests allowed per minute for this key.","schema":{"type":"integer"}},"x-ratelimit-remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"x-ratelimit-reset":{"description":"Seconds until the window resets.","schema":{"type":"integer"}}}},"401":{"$ref":"#/components/responses/E401"},"402":{"$ref":"#/components/responses/E402"},"403":{"$ref":"#/components/responses/E403"},"404":{"$ref":"#/components/responses/E404"},"409":{"$ref":"#/components/responses/E409"},"422":{"description":"Blocked.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"const":"publish_blocked"},"message":{"type":"string"},"blockers":{"type":"array","items":{"$ref":"#/components/schemas/PublishBlocker"}},"request_id":{"type":"string"}}}}},"headers":{"x-request-id":{"description":"Unique id of this request. Quote it to support.","schema":{"type":"string"}},"x-ratelimit-limit":{"description":"Requests allowed per minute for this key.","schema":{"type":"integer"}},"x-ratelimit-remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"x-ratelimit-reset":{"description":"Seconds until the window resets.","schema":{"type":"integer"}}}},"429":{"$ref":"#/components/responses/E429"}},"operationId":"postPassportsByIdPublish","parameters":[{"$ref":"#/components/parameters/IdempotencyKey"},{"$ref":"#/components/parameters/DryRun"}]}},"/passports/publish":{"post":{"tags":["Passports"],"summary":"Publish many passports","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"ids":{"type":"array","items":{"type":"string","minLength":1},"minItems":1,"maxItems":1000}},"required":["ids"]}}}},"responses":{"200":{"description":"Per-passport results.","content":{"application/json":{"schema":{"type":"object"}}},"headers":{"x-request-id":{"description":"Unique id of this request. Quote it to support.","schema":{"type":"string"}},"x-ratelimit-limit":{"description":"Requests allowed per minute for this key.","schema":{"type":"integer"}},"x-ratelimit-remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"x-ratelimit-reset":{"description":"Seconds until the window resets.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/E400"},"401":{"$ref":"#/components/responses/E401"},"402":{"$ref":"#/components/responses/E402"},"403":{"$ref":"#/components/responses/E403"},"422":{"$ref":"#/components/responses/E422"},"429":{"$ref":"#/components/responses/E429"}},"operationId":"postPassportsPublish","parameters":[{"$ref":"#/components/parameters/IdempotencyKey"},{"$ref":"#/components/parameters/DryRun"}]}},"/passports/{id}/events":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Passport id"}],"post":{"tags":["Passports"],"summary":"Record dynamic data","description":"Append-only: state of health, cycle count, state of charge, temperatures, throughput, negative events. The payload is keyed by field name (see /field-catalog, kind `dynamic`). Triggers the `passport.event_recorded` webhook.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"eventType":{"type":"string","enum":["PUT_INTO_SERVICE","REPAIR","SOH_READING","LIFETIME_METRIC","CYCLE_COUNT","STATUS_CHANGE","NEGATIVE_EVENT","OPERATING_CONDITION","PERFORMANCE_VALUE","BMS_SOFTWARE_RESET"]},"payload":{"type":"object","additionalProperties":{}},"bmsHistoryInvalidatedByReset":{"type":"boolean"}},"required":["eventType","payload"]},"example":{"eventType":"SOH_READING","payload":{"stateOfCertifiedEnergy":94,"cycleCount":412}}}}},"responses":{"200":{"$ref":"#/components/responses/DryRun"},"201":{"description":"Recorded.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DynamicEvent"}}},"headers":{"x-request-id":{"description":"Unique id of this request. Quote it to support.","schema":{"type":"string"}},"x-ratelimit-limit":{"description":"Requests allowed per minute for this key.","schema":{"type":"integer"}},"x-ratelimit-remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"x-ratelimit-reset":{"description":"Seconds until the window resets.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/E400"},"401":{"$ref":"#/components/responses/E401"},"403":{"$ref":"#/components/responses/E403"},"404":{"$ref":"#/components/responses/E404"},"429":{"$ref":"#/components/responses/E429"}},"operationId":"postPassportsByIdEvents","parameters":[{"$ref":"#/components/parameters/IdempotencyKey"},{"$ref":"#/components/parameters/DryRun"}]},"get":{"tags":["Passports"],"summary":"Dynamic data history","description":"Append-only readings for this passport, newest first.","parameters":[{"$ref":"#/components/parameters/Limit"},{"$ref":"#/components/parameters/Cursor"},{"name":"since","in":"query","required":false,"schema":{"type":"string","format":"date-time"},"description":"Recorded at or after."},{"name":"event_type","in":"query","required":false,"schema":{"type":"string"},"description":"Only one event type, e.g. SOH_READING."}],"responses":{"200":{"description":"A page of events.","content":{"application/json":{"schema":{"type":"object","required":["data","has_more","next_cursor"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/DynamicEvent"}},"has_more":{"type":"boolean"},"next_cursor":{"type":["string","null"],"description":"Pass as `cursor` to get the next page."}}}}},"headers":{"x-request-id":{"description":"Unique id of this request. Quote it to support.","schema":{"type":"string"}},"x-ratelimit-limit":{"description":"Requests allowed per minute for this key.","schema":{"type":"integer"}},"x-ratelimit-remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"x-ratelimit-reset":{"description":"Seconds until the window resets.","schema":{"type":"integer"}}}},"401":{"$ref":"#/components/responses/E401"},"404":{"$ref":"#/components/responses/E404"},"429":{"$ref":"#/components/responses/E429"}},"operationId":"getPassportsByIdEvents"}},"/passports/{id}/recycle":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Passport id"}],"post":{"tags":["Passports"],"summary":"Mark as recycled","description":"The passport ceases (Art. 77(6)); the public URL then answers 410 Gone.","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"note":{"type":"string","maxLength":500}}}}}},"responses":{"200":{"description":"Recycled.","content":{"application/json":{"schema":{"type":"object"}}},"headers":{"x-request-id":{"description":"Unique id of this request. Quote it to support.","schema":{"type":"string"}},"x-ratelimit-limit":{"description":"Requests allowed per minute for this key.","schema":{"type":"integer"}},"x-ratelimit-remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"x-ratelimit-reset":{"description":"Seconds until the window resets.","schema":{"type":"integer"}}}},"401":{"$ref":"#/components/responses/E401"},"403":{"$ref":"#/components/responses/E403"},"404":{"$ref":"#/components/responses/E404"},"409":{"$ref":"#/components/responses/E409"},"429":{"$ref":"#/components/responses/E429"}},"operationId":"postPassportsByIdRecycle","parameters":[{"$ref":"#/components/parameters/IdempotencyKey"},{"$ref":"#/components/parameters/DryRun"}]}},"/passports/{id}/versions":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Passport id"}],"get":{"tags":["Passports"],"summary":"Published versions","description":"Each publication freezes and hashes the content.","responses":{"200":{"description":"Versions.","content":{"application/json":{"schema":{"type":"object"}}},"headers":{"x-request-id":{"description":"Unique id of this request. Quote it to support.","schema":{"type":"string"}},"x-ratelimit-limit":{"description":"Requests allowed per minute for this key.","schema":{"type":"integer"}},"x-ratelimit-remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"x-ratelimit-reset":{"description":"Seconds until the window resets.","schema":{"type":"integer"}}}},"401":{"$ref":"#/components/responses/E401"},"404":{"$ref":"#/components/responses/E404"},"429":{"$ref":"#/components/responses/E429"}},"operationId":"getPassportsByIdVersions"}},"/passports/{id}/qr.svg":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Passport id"}],"get":{"tags":["Passports"],"summary":"QR code (SVG)","responses":{"200":{"description":"SVG","content":{"image/svg+xml":{}},"headers":{"x-request-id":{"description":"Unique id of this request. Quote it to support.","schema":{"type":"string"}},"x-ratelimit-limit":{"description":"Requests allowed per minute for this key.","schema":{"type":"integer"}},"x-ratelimit-remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"x-ratelimit-reset":{"description":"Seconds until the window resets.","schema":{"type":"integer"}}}},"401":{"$ref":"#/components/responses/E401"},"404":{"$ref":"#/components/responses/E404"},"429":{"$ref":"#/components/responses/E429"}},"operationId":"getPassportsByIdQrSvg"}},"/passports/{id}/qr.png":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Passport id"}],"get":{"tags":["Passports"],"summary":"QR code (PNG, print grade)","responses":{"200":{"description":"PNG","content":{"image/png":{}},"headers":{"x-request-id":{"description":"Unique id of this request. Quote it to support.","schema":{"type":"string"}},"x-ratelimit-limit":{"description":"Requests allowed per minute for this key.","schema":{"type":"integer"}},"x-ratelimit-remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"x-ratelimit-reset":{"description":"Seconds until the window resets.","schema":{"type":"integer"}}}},"401":{"$ref":"#/components/responses/E401"},"404":{"$ref":"#/components/responses/E404"},"429":{"$ref":"#/components/responses/E429"}},"operationId":"getPassportsByIdQrPng"}},"/passports/bulk-lifecycle":{"post":{"tags":["Fleet"],"summary":"Apply a lifecycle event to many passports","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"passportIds":{"type":"array","items":{"type":"string","minLength":1},"minItems":1,"maxItems":1000},"event":{"type":"string","enum":["putInService","waste","recycle"]},"date":{"type":"string","format":"date-time"}},"required":["passportIds","event"]}}}},"responses":{"200":{"description":"Per-passport results.","content":{"application/json":{"schema":{"type":"object"}}},"headers":{"x-request-id":{"description":"Unique id of this request. Quote it to support.","schema":{"type":"string"}},"x-ratelimit-limit":{"description":"Requests allowed per minute for this key.","schema":{"type":"integer"}},"x-ratelimit-remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"x-ratelimit-reset":{"description":"Seconds until the window resets.","schema":{"type":"integer"}}}},"207":{"description":"Some passports were skipped; see results.","headers":{"x-request-id":{"description":"Unique id of this request. Quote it to support.","schema":{"type":"string"}},"x-ratelimit-limit":{"description":"Requests allowed per minute for this key.","schema":{"type":"integer"}},"x-ratelimit-remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"x-ratelimit-reset":{"description":"Seconds until the window resets.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/E400"},"401":{"$ref":"#/components/responses/E401"},"403":{"$ref":"#/components/responses/E403"},"429":{"$ref":"#/components/responses/E429"}},"operationId":"postPassportsBulkLifecycle","parameters":[{"$ref":"#/components/parameters/IdempotencyKey"},{"$ref":"#/components/parameters/DryRun"}]}},"/passports/import-updates":{"post":{"tags":["Fleet"],"summary":"Update many passports from matched rows","description":"Rows are matched by unique identifier or serial number. Set `dryRun` to see how many match and how many are public before writing.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"modelId":{"type":"string","minLength":1},"rows":{"type":"array","items":{"type":"object","properties":{"uniqueIdentifier":{"type":"string"},"serialNumber":{"type":"string"},"putIntoServiceAt":{"type":"string","format":"date-time"},"status":{"type":"string","enum":["waste","recycled"]},"readings":{"type":"object","additionalProperties":{"anyOf":[{"type":"string"},{"type":"number"}]}}}},"minItems":1,"maxItems":1000},"dryRun":{"type":"boolean"}},"required":["modelId","rows"]}}}},"responses":{"200":{"description":"Per-row results.","content":{"application/json":{"schema":{"type":"object"}}},"headers":{"x-request-id":{"description":"Unique id of this request. Quote it to support.","schema":{"type":"string"}},"x-ratelimit-limit":{"description":"Requests allowed per minute for this key.","schema":{"type":"integer"}},"x-ratelimit-remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"x-ratelimit-reset":{"description":"Seconds until the window resets.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/E400"},"401":{"$ref":"#/components/responses/E401"},"403":{"$ref":"#/components/responses/E403"},"404":{"$ref":"#/components/responses/E404"},"429":{"$ref":"#/components/responses/E429"}},"operationId":"postPassportsImportUpdates","parameters":[{"$ref":"#/components/parameters/IdempotencyKey"},{"$ref":"#/components/parameters/DryRun"}]}},"/export":{"get":{"tags":["Data portability"],"summary":"Export all data (JSON)","responses":{"200":{"description":"Everything the organisation holds.","content":{"application/json":{"schema":{"type":"object"}}},"headers":{"x-request-id":{"description":"Unique id of this request. Quote it to support.","schema":{"type":"string"}},"x-ratelimit-limit":{"description":"Requests allowed per minute for this key.","schema":{"type":"integer"}},"x-ratelimit-remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"x-ratelimit-reset":{"description":"Seconds until the window resets.","schema":{"type":"integer"}}}},"401":{"$ref":"#/components/responses/E401"},"429":{"$ref":"#/components/responses/E429"}},"operationId":"getExport"}},"/export/archive":{"get":{"tags":["Data portability"],"summary":"Export archive (ZIP)","description":"Structured data, JSON-LD per passport, document bytes, QR and label artwork, supplier uploads, audit trail, and a SHA-256 manifest.","responses":{"200":{"description":"ZIP","content":{"application/zip":{}},"headers":{"x-request-id":{"description":"Unique id of this request. Quote it to support.","schema":{"type":"string"}},"x-ratelimit-limit":{"description":"Requests allowed per minute for this key.","schema":{"type":"integer"}},"x-ratelimit-remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"x-ratelimit-reset":{"description":"Seconds until the window resets.","schema":{"type":"integer"}}}},"401":{"$ref":"#/components/responses/E401"},"429":{"$ref":"#/components/responses/E429"}},"operationId":"getExportArchive"}},"/models/batch":{"post":{"tags":["Models"],"summary":"Create many models","description":"Up to 500 models in one call, each row shaped like `POST /models`. Rows stand alone: a row that fails validation is listed under `failed` and the rest are created. A name that already exists in the account, or appears earlier in the same call, is listed under `skipped` and left untouched, so sending the same file twice creates nothing the second time. Answers 201 when no row failed and 207 otherwise.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"rows":{"type":"array","items":{"type":"object","additionalProperties":{}},"minItems":1,"maxItems":500}},"required":["rows"]},"example":{"rows":[{"category":"EV","name":"PowerCell EV-90","capacityKwh":90,"chemistry":"Li-ion NMC811","fields":{"manufacturerName":"Nordvolt Energy GmbH"}}]}}}},"responses":{"200":{"$ref":"#/components/responses/DryRun"},"201":{"description":"Per-row results.","content":{"application/json":{"schema":{"type":"object","properties":{"created":{"type":"array","items":{"type":"object"}},"skipped":{"type":"array","items":{"type":"object"}},"failed":{"type":"array","items":{"type":"object"}}}}}},"headers":{"x-request-id":{"description":"Unique id of this request. Quote it to support.","schema":{"type":"string"}},"x-ratelimit-limit":{"description":"Requests allowed per minute for this key.","schema":{"type":"integer"}},"x-ratelimit-remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"x-ratelimit-reset":{"description":"Seconds until the window resets.","schema":{"type":"integer"}}}},"207":{"description":"Some rows failed; see `failed`.","headers":{"x-request-id":{"description":"Unique id of this request. Quote it to support.","schema":{"type":"string"}},"x-ratelimit-limit":{"description":"Requests allowed per minute for this key.","schema":{"type":"integer"}},"x-ratelimit-remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"x-ratelimit-reset":{"description":"Seconds until the window resets.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/E400"},"401":{"$ref":"#/components/responses/E401"},"402":{"$ref":"#/components/responses/E402"},"403":{"$ref":"#/components/responses/E403"},"429":{"$ref":"#/components/responses/E429"}},"operationId":"postModelsBatch","parameters":[{"$ref":"#/components/parameters/IdempotencyKey"},{"$ref":"#/components/parameters/DryRun"}]}},"/models/validate":{"post":{"tags":["Models"],"summary":"Validate a model draft","description":"The same schema and completeness analysis as creating a model, with nothing stored. Use it in your ERP before you send anything — it tells you which required fields, attributes and documents are still missing, and which field names it does not recognise.","requestBody":{"required":true,"content":{"application/json":{"schema":{"allOf":[{"type":"object","properties":{"templateKey":{"type":"string","minLength":1,"default":"battery"},"category":{"type":"string","enum":["LMT","INDUSTRIAL","EV"]},"industrialExternalStorage":{"type":"boolean","default":false},"name":{"type":"string","minLength":1,"maxLength":200},"capacityKwh":{"type":"number","exclusiveMinimum":0},"chemistry":{"type":"string","minLength":1,"maxLength":120},"fields":{"type":"object","additionalProperties":{}}},"required":["category","name","capacityKwh","chemistry"]},{"type":"object","properties":{"documentTypes":{"type":"array","items":{"type":"string"},"description":"Documents you will upload, e.g. `EU Declaration of Conformity`."}}}]}}}},"responses":{"200":{"description":"The analysis.","content":{"application/json":{"schema":{"type":"object","properties":{"valid":{"type":"boolean"},"complete":{"type":"boolean"},"requiredTotal":{"type":"integer"},"requiredFilled":{"type":"integer"},"missing":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"label":{"type":"string"},"point":{"type":"integer","description":"Annex XIII point (1 public … 4 dynamic)."},"annexRef":{"type":"string"},"granularity":{"type":"string","enum":["model","item"]}}}},"conditionalUnset":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"label":{"type":"string"},"point":{"type":"integer","description":"Annex XIII point (1 public … 4 dynamic)."},"annexRef":{"type":"string"},"granularity":{"type":"string","enum":["model","item"]}}}},"unknownFields":{"type":"array","items":{"type":"string"}}}}}},"headers":{"x-request-id":{"description":"Unique id of this request. Quote it to support.","schema":{"type":"string"}},"x-ratelimit-limit":{"description":"Requests allowed per minute for this key.","schema":{"type":"integer"}},"x-ratelimit-remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"x-ratelimit-reset":{"description":"Seconds until the window resets.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/E400"},"401":{"$ref":"#/components/responses/E401"},"429":{"$ref":"#/components/responses/E429"}},"operationId":"postModelsValidate","parameters":[{"$ref":"#/components/parameters/IdempotencyKey"},{"$ref":"#/components/parameters/DryRun"}]}},"/passports":{"get":{"tags":["Passports"],"summary":"List passports","description":"Every passport in the organisation, across models, newest first. For an incremental sync, store the time of your last sync and pass it as `updated_since`: it returns passports whose status changed or that received new dynamic data since then.","parameters":[{"$ref":"#/components/parameters/Limit"},{"$ref":"#/components/parameters/Cursor"},{"name":"model_id","in":"query","required":false,"schema":{"type":"string"},"description":"Only this model's passports."},{"name":"serial","in":"query","required":false,"schema":{"type":"string"},"description":"Exact serial number."},{"name":"unique_identifier","in":"query","required":false,"schema":{"type":"string"},"description":"Exact passport identifier."},{"name":"status","in":"query","required":false,"schema":{"type":"string","enum":["draft","pending","published","attention","repurposed","waste","recycled"]},"description":"Derived display status."},{"name":"published","in":"query","required":false,"schema":{"type":"string","enum":["true","false"]},"description":"Only published, or only draft, passports."},{"name":"created_since","in":"query","required":false,"schema":{"type":"string","format":"date-time"},"description":"Created at or after."},{"name":"updated_since","in":"query","required":false,"schema":{"type":"string","format":"date-time"},"description":"Changed, or given new dynamic data, at or after."}],"responses":{"200":{"description":"A page of passports.","content":{"application/json":{"schema":{"type":"object","required":["data","has_more","next_cursor"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Passport"}},"has_more":{"type":"boolean"},"next_cursor":{"type":["string","null"],"description":"Pass as `cursor` to get the next page."}}}}},"headers":{"x-request-id":{"description":"Unique id of this request. Quote it to support.","schema":{"type":"string"}},"x-ratelimit-limit":{"description":"Requests allowed per minute for this key.","schema":{"type":"integer"}},"x-ratelimit-remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"x-ratelimit-reset":{"description":"Seconds until the window resets.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/E400"},"401":{"$ref":"#/components/responses/E401"},"429":{"$ref":"#/components/responses/E429"}},"operationId":"getPassports"}},"/passports/{id}/status":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Passport id"}],"patch":{"tags":["Passports"],"summary":"Change status (repurpose, re-use, remanufacture, waste)","description":"Annex XIII 4(c). Repurposing, re-using or remanufacturing a battery forks a NEW passport, linked to this one, with its own identifier (201, `forked: true`); `WASTE` changes this passport in place.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","enum":["ORIGINAL","REPURPOSED","REUSED","REMANUFACTURED","WASTE"]},"newResponsibleOrgId":{"type":"string"},"note":{"type":"string","maxLength":500}},"required":["status"]},"example":{"status":"REPURPOSED","note":"Second life as stationary storage"}}}},"responses":{"200":{"description":"Changed in place.","content":{"application/json":{"schema":{"type":"object"}}},"headers":{"x-request-id":{"description":"Unique id of this request. Quote it to support.","schema":{"type":"string"}},"x-ratelimit-limit":{"description":"Requests allowed per minute for this key.","schema":{"type":"integer"}},"x-ratelimit-remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"x-ratelimit-reset":{"description":"Seconds until the window resets.","schema":{"type":"integer"}}}},"201":{"description":"Forked: a new linked passport was issued.","content":{"application/json":{"schema":{"type":"object","properties":{"forked":{"const":true},"childPassport":{"type":"object"},"childUid":{"type":"string"}}}}},"headers":{"x-request-id":{"description":"Unique id of this request. Quote it to support.","schema":{"type":"string"}},"x-ratelimit-limit":{"description":"Requests allowed per minute for this key.","schema":{"type":"integer"}},"x-ratelimit-remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"x-ratelimit-reset":{"description":"Seconds until the window resets.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/E400"},"401":{"$ref":"#/components/responses/E401"},"403":{"$ref":"#/components/responses/E403"},"404":{"$ref":"#/components/responses/E404"},"409":{"$ref":"#/components/responses/E409"},"429":{"$ref":"#/components/responses/E429"}},"operationId":"patchPassportsByIdStatus","parameters":[{"$ref":"#/components/parameters/IdempotencyKey"},{"$ref":"#/components/parameters/DryRun"}]}},"/plants":{"get":{"tags":["Models"],"summary":"List facilities","description":"Manufacturing plants, with how many passports name each.","responses":{"200":{"description":"Facilities.","content":{"application/json":{"schema":{"type":"object"}}},"headers":{"x-request-id":{"description":"Unique id of this request. Quote it to support.","schema":{"type":"string"}},"x-ratelimit-limit":{"description":"Requests allowed per minute for this key.","schema":{"type":"integer"}},"x-ratelimit-remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"x-ratelimit-reset":{"description":"Seconds until the window resets.","schema":{"type":"integer"}}}},"401":{"$ref":"#/components/responses/E401"},"429":{"$ref":"#/components/responses/E429"}},"operationId":"getPlants"},"post":{"tags":["Models"],"summary":"Add a facility","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":200},"location":{"type":"string","minLength":1,"maxLength":300},"esprFacilityId":{"type":"string","maxLength":120}},"required":["name","location"]},"example":{"name":"Leipzig Gigafactory","location":"Leipzig, DE","esprFacilityId":"FAC-LEJ-01"}}}},"responses":{"200":{"$ref":"#/components/responses/DryRun"},"201":{"description":"Created.","content":{"application/json":{"schema":{"type":"object"}}},"headers":{"x-request-id":{"description":"Unique id of this request. Quote it to support.","schema":{"type":"string"}},"x-ratelimit-limit":{"description":"Requests allowed per minute for this key.","schema":{"type":"integer"}},"x-ratelimit-remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"x-ratelimit-reset":{"description":"Seconds until the window resets.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/E400"},"401":{"$ref":"#/components/responses/E401"},"403":{"$ref":"#/components/responses/E403"},"429":{"$ref":"#/components/responses/E429"}},"operationId":"postPlants","parameters":[{"$ref":"#/components/parameters/IdempotencyKey"},{"$ref":"#/components/parameters/DryRun"}]}},"/documents":{"get":{"tags":["Documents"],"summary":"List documents","parameters":[{"$ref":"#/components/parameters/Limit"},{"$ref":"#/components/parameters/Cursor"},{"name":"model_id","in":"query","required":false,"schema":{"type":"string"},"description":"Only this model's documents."},{"name":"type","in":"query","required":false,"schema":{"type":"string"},"description":"Exact document type, case-insensitive."}],"responses":{"200":{"description":"A page of documents.","content":{"application/json":{"schema":{"type":"object","required":["data","has_more","next_cursor"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Document"}},"has_more":{"type":"boolean"},"next_cursor":{"type":["string","null"],"description":"Pass as `cursor` to get the next page."}}}}},"headers":{"x-request-id":{"description":"Unique id of this request. Quote it to support.","schema":{"type":"string"}},"x-ratelimit-limit":{"description":"Requests allowed per minute for this key.","schema":{"type":"integer"}},"x-ratelimit-remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"x-ratelimit-reset":{"description":"Seconds until the window resets.","schema":{"type":"integer"}}}},"401":{"$ref":"#/components/responses/E401"},"429":{"$ref":"#/components/responses/E429"}},"operationId":"getDocuments"}},"/documents/{id}":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Document id"}],"get":{"tags":["Documents"],"summary":"Get a document","responses":{"200":{"description":"The document.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Document"}}},"headers":{"x-request-id":{"description":"Unique id of this request. Quote it to support.","schema":{"type":"string"}},"x-ratelimit-limit":{"description":"Requests allowed per minute for this key.","schema":{"type":"integer"}},"x-ratelimit-remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"x-ratelimit-reset":{"description":"Seconds until the window resets.","schema":{"type":"integer"}}}},"401":{"$ref":"#/components/responses/E401"},"404":{"$ref":"#/components/responses/E404"},"429":{"$ref":"#/components/responses/E429"}},"operationId":"getDocumentsById"}},"/documents/{id}/download":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Document id"}],"get":{"tags":["Documents"],"summary":"Download a document","responses":{"200":{"description":"The file, with its stored content type.","headers":{"x-request-id":{"description":"Unique id of this request. Quote it to support.","schema":{"type":"string"}},"x-ratelimit-limit":{"description":"Requests allowed per minute for this key.","schema":{"type":"integer"}},"x-ratelimit-remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"x-ratelimit-reset":{"description":"Seconds until the window resets.","schema":{"type":"integer"}}}},"401":{"$ref":"#/components/responses/E401"},"404":{"$ref":"#/components/responses/E404"},"429":{"$ref":"#/components/responses/E429"}},"operationId":"getDocumentsByIdDownload"}},"/audit":{"get":{"tags":["Audit"],"summary":"Audit trail","description":"Who changed what, and when (Art. 78(g)), newest first. Changes made over the API are attributed to the member who created the key.","parameters":[{"$ref":"#/components/parameters/Limit"},{"$ref":"#/components/parameters/Cursor"},{"name":"entity","in":"query","required":false,"schema":{"type":"string"},"description":"e.g. BatteryPassport"},{"name":"entity_id","in":"query","required":false,"schema":{"type":"string"},"description":"One record's history."},{"name":"since","in":"query","required":false,"schema":{"type":"string","format":"date-time"},"description":"At or after."},{"name":"actor","in":"query","required":false,"schema":{"type":"string"},"description":"A user id or API key id."},{"name":"source","in":"query","required":false,"schema":{"type":"string","enum":["panel","api","supplier","import","system"]},"description":"Where the change came from."},{"name":"model_id","in":"query","required":false,"schema":{"type":"string"},"description":"Entries filed under one battery model."}],"responses":{"200":{"description":"A page of entries.","content":{"application/json":{"schema":{"type":"object","required":["data","has_more","next_cursor"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/AuditEntry"}},"has_more":{"type":"boolean"},"next_cursor":{"type":["string","null"],"description":"Pass as `cursor` to get the next page."}}}}},"headers":{"x-request-id":{"description":"Unique id of this request. Quote it to support.","schema":{"type":"string"}},"x-ratelimit-limit":{"description":"Requests allowed per minute for this key.","schema":{"type":"integer"}},"x-ratelimit-remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"x-ratelimit-reset":{"description":"Seconds until the window resets.","schema":{"type":"integer"}}}},"401":{"$ref":"#/components/responses/E401"},"403":{"$ref":"#/components/responses/E403"},"429":{"$ref":"#/components/responses/E429"}},"operationId":"getAudit"}},"/upload-links":{"get":{"tags":["Suppliers"],"summary":"List supplier data requests","description":"Each request with its status (sent, opened, responded, accepted, expired, cancelled) and how many uploaded files await review.","responses":{"200":{"description":"Requests.","content":{"application/json":{"schema":{"type":"object"}}},"headers":{"x-request-id":{"description":"Unique id of this request. Quote it to support.","schema":{"type":"string"}},"x-ratelimit-limit":{"description":"Requests allowed per minute for this key.","schema":{"type":"integer"}},"x-ratelimit-remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"x-ratelimit-reset":{"description":"Seconds until the window resets.","schema":{"type":"integer"}}}},"401":{"$ref":"#/components/responses/E401"},"429":{"$ref":"#/components/responses/E429"}},"operationId":"getUploadLinks"},"post":{"tags":["Suppliers"],"summary":"Ask a supplier for data","description":"Creates a password-less link the supplier opens to enter the fields you ask for or upload documents. The response carries the link's `token`; the supplier's page is `/u/{token}` on the public passport host. Their answer triggers `supplier.submitted`; nothing reaches your model until you accept it.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"label":{"type":"string","maxLength":200},"expiresInDays":{"type":"integer","exclusiveMinimum":0,"maximum":365},"supplierName":{"type":"string","maxLength":200},"supplierEmail":{"type":"string","format":"email"},"modelId":{"type":"string"},"requestedFields":{"type":"array","items":{"type":"string","minLength":1},"maxItems":200},"message":{"type":"string","maxLength":2000}}},"example":{"supplierName":"CellCore GmbH","supplierEmail":"qa@cellcore.example","modelId":"<model id>","requestedFields":["criticalRawMaterials","detailedComposition"],"expiresInDays":30,"message":"Please confirm the cathode composition for the 2027 passport."}}}},"responses":{"200":{"$ref":"#/components/responses/DryRun"},"201":{"description":"Created.","content":{"application/json":{"schema":{"type":"object"}}},"headers":{"x-request-id":{"description":"Unique id of this request. Quote it to support.","schema":{"type":"string"}},"x-ratelimit-limit":{"description":"Requests allowed per minute for this key.","schema":{"type":"integer"}},"x-ratelimit-remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"x-ratelimit-reset":{"description":"Seconds until the window resets.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/E400"},"401":{"$ref":"#/components/responses/E401"},"402":{"$ref":"#/components/responses/E402"},"403":{"$ref":"#/components/responses/E403"},"429":{"$ref":"#/components/responses/E429"}},"operationId":"postUploadLinks","parameters":[{"$ref":"#/components/parameters/IdempotencyKey"},{"$ref":"#/components/parameters/DryRun"}]}},"/upload-links/{id}/files":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Request id"}],"get":{"tags":["Suppliers"],"summary":"Files a supplier uploaded","responses":{"200":{"description":"Files with their review status.","content":{"application/json":{"schema":{"type":"object"}}},"headers":{"x-request-id":{"description":"Unique id of this request. Quote it to support.","schema":{"type":"string"}},"x-ratelimit-limit":{"description":"Requests allowed per minute for this key.","schema":{"type":"integer"}},"x-ratelimit-remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"x-ratelimit-reset":{"description":"Seconds until the window resets.","schema":{"type":"integer"}}}},"401":{"$ref":"#/components/responses/E401"},"404":{"$ref":"#/components/responses/E404"},"429":{"$ref":"#/components/responses/E429"}},"operationId":"getUploadLinksByIdFiles"}},"/upload-links/{id}/accept":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Request id"}],"post":{"tags":["Suppliers"],"summary":"Accept a supplier's values into the model","description":"Copies the submitted values you choose into the model and records where each came from.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"fields":{"type":"array","items":{"type":"string","minLength":1},"minItems":1,"maxItems":200}},"required":["fields"]}}}},"responses":{"200":{"description":"Accepted.","content":{"application/json":{"schema":{"type":"object"}}},"headers":{"x-request-id":{"description":"Unique id of this request. Quote it to support.","schema":{"type":"string"}},"x-ratelimit-limit":{"description":"Requests allowed per minute for this key.","schema":{"type":"integer"}},"x-ratelimit-remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"x-ratelimit-reset":{"description":"Seconds until the window resets.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/E400"},"401":{"$ref":"#/components/responses/E401"},"403":{"$ref":"#/components/responses/E403"},"404":{"$ref":"#/components/responses/E404"},"409":{"$ref":"#/components/responses/E409"},"429":{"$ref":"#/components/responses/E429"}},"operationId":"postUploadLinksByIdAccept","parameters":[{"$ref":"#/components/parameters/IdempotencyKey"},{"$ref":"#/components/parameters/DryRun"}]}},"/webhooks":{"get":{"tags":["Webhooks"],"summary":"List webhook endpoints","responses":{"200":{"description":"Endpoints, each with its last delivery.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/WebhookEndpoint"}}}}}},"headers":{"x-request-id":{"description":"Unique id of this request. Quote it to support.","schema":{"type":"string"}},"x-ratelimit-limit":{"description":"Requests allowed per minute for this key.","schema":{"type":"integer"}},"x-ratelimit-remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"x-ratelimit-reset":{"description":"Seconds until the window resets.","schema":{"type":"integer"}}}},"401":{"$ref":"#/components/responses/E401"},"429":{"$ref":"#/components/responses/E429"}},"operationId":"getWebhooks"},"post":{"tags":["Webhooks"],"summary":"Add a webhook endpoint","description":"HTTPS only, never a private address. The response carries the signing secret (`whsec_…`) — the only time it is shown.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"url":{"type":"string","format":"uri","maxLength":2000},"description":{"type":"string","maxLength":200},"events":{"type":"array","items":{"type":"string","enum":["model.created","model.updated","document.uploaded","passport.created","passport.published","passport.status_changed","passport.recycled","passport.event_recorded","supplier.submitted"]},"default":[]}},"required":["url"]},"example":{"url":"https://erp.example.com/dpp/webhooks","description":"SAP passport sync","events":["passport.published","passport.event_recorded"]}}}},"responses":{"200":{"$ref":"#/components/responses/DryRun"},"201":{"description":"Created, with its secret.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/WebhookEndpoint"},{"type":"object","properties":{"secret":{"type":"string"}}}]}}},"headers":{"x-request-id":{"description":"Unique id of this request. Quote it to support.","schema":{"type":"string"}},"x-ratelimit-limit":{"description":"Requests allowed per minute for this key.","schema":{"type":"integer"}},"x-ratelimit-remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"x-ratelimit-reset":{"description":"Seconds until the window resets.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/E400"},"401":{"$ref":"#/components/responses/E401"},"402":{"$ref":"#/components/responses/E402"},"403":{"$ref":"#/components/responses/E403"},"422":{"description":"`invalid_webhook_url` — not https, private, or does not resolve.","headers":{"x-request-id":{"description":"Unique id of this request. Quote it to support.","schema":{"type":"string"}},"x-ratelimit-limit":{"description":"Requests allowed per minute for this key.","schema":{"type":"integer"}},"x-ratelimit-remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"x-ratelimit-reset":{"description":"Seconds until the window resets.","schema":{"type":"integer"}}}},"429":{"$ref":"#/components/responses/E429"}},"operationId":"postWebhooks","parameters":[{"$ref":"#/components/parameters/IdempotencyKey"},{"$ref":"#/components/parameters/DryRun"}]}},"/webhooks/event-types":{"get":{"tags":["Webhooks"],"summary":"Event types","responses":{"200":{"description":"Every event type you can subscribe to.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"string"}}}}}},"headers":{"x-request-id":{"description":"Unique id of this request. Quote it to support.","schema":{"type":"string"}},"x-ratelimit-limit":{"description":"Requests allowed per minute for this key.","schema":{"type":"integer"}},"x-ratelimit-remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"x-ratelimit-reset":{"description":"Seconds until the window resets.","schema":{"type":"integer"}}}},"429":{"$ref":"#/components/responses/E429"}},"operationId":"getWebhooksEventTypes"}},"/webhooks/{id}":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Endpoint id"}],"get":{"tags":["Webhooks"],"summary":"Get an endpoint","responses":{"200":{"description":"The endpoint.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookEndpoint"}}},"headers":{"x-request-id":{"description":"Unique id of this request. Quote it to support.","schema":{"type":"string"}},"x-ratelimit-limit":{"description":"Requests allowed per minute for this key.","schema":{"type":"integer"}},"x-ratelimit-remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"x-ratelimit-reset":{"description":"Seconds until the window resets.","schema":{"type":"integer"}}}},"401":{"$ref":"#/components/responses/E401"},"404":{"$ref":"#/components/responses/E404"},"429":{"$ref":"#/components/responses/E429"}},"operationId":"getWebhooksById"},"patch":{"tags":["Webhooks"],"summary":"Update an endpoint","description":"Change the URL or events, or pause it with `enabled: false`.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"url":{"type":"string","format":"uri","maxLength":2000},"description":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}]},"events":{"type":"array","items":{"type":"string","enum":["model.created","model.updated","document.uploaded","passport.created","passport.published","passport.status_changed","passport.recycled","passport.event_recorded","supplier.submitted"]}},"enabled":{"type":"boolean"}}},"example":{"enabled":false}}}},"responses":{"200":{"description":"Updated.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookEndpoint"}}},"headers":{"x-request-id":{"description":"Unique id of this request. Quote it to support.","schema":{"type":"string"}},"x-ratelimit-limit":{"description":"Requests allowed per minute for this key.","schema":{"type":"integer"}},"x-ratelimit-remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"x-ratelimit-reset":{"description":"Seconds until the window resets.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/E400"},"401":{"$ref":"#/components/responses/E401"},"403":{"$ref":"#/components/responses/E403"},"404":{"$ref":"#/components/responses/E404"},"429":{"$ref":"#/components/responses/E429"}},"operationId":"patchWebhooksById","parameters":[{"$ref":"#/components/parameters/IdempotencyKey"},{"$ref":"#/components/parameters/DryRun"}]}},"/webhooks/{id}/rotate-secret":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Endpoint id"}],"post":{"tags":["Webhooks"],"summary":"Rotate the signing secret","description":"The old secret stops verifying immediately.","responses":{"200":{"description":"The new secret.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"secret":{"type":"string"}}}}},"headers":{"x-request-id":{"description":"Unique id of this request. Quote it to support.","schema":{"type":"string"}},"x-ratelimit-limit":{"description":"Requests allowed per minute for this key.","schema":{"type":"integer"}},"x-ratelimit-remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"x-ratelimit-reset":{"description":"Seconds until the window resets.","schema":{"type":"integer"}}}},"401":{"$ref":"#/components/responses/E401"},"403":{"$ref":"#/components/responses/E403"},"404":{"$ref":"#/components/responses/E404"},"429":{"$ref":"#/components/responses/E429"}},"operationId":"postWebhooksByIdRotateSecret","parameters":[{"$ref":"#/components/parameters/IdempotencyKey"},{"$ref":"#/components/parameters/DryRun"}]}},"/webhooks/{id}/test":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Endpoint id"}],"post":{"tags":["Webhooks"],"summary":"Send a test event","description":"Sends a signed `ping` now and returns what your endpoint answered.","responses":{"200":{"description":"The delivery outcome.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookDelivery"}}},"headers":{"x-request-id":{"description":"Unique id of this request. Quote it to support.","schema":{"type":"string"}},"x-ratelimit-limit":{"description":"Requests allowed per minute for this key.","schema":{"type":"integer"}},"x-ratelimit-remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"x-ratelimit-reset":{"description":"Seconds until the window resets.","schema":{"type":"integer"}}}},"401":{"$ref":"#/components/responses/E401"},"403":{"$ref":"#/components/responses/E403"},"404":{"$ref":"#/components/responses/E404"},"429":{"$ref":"#/components/responses/E429"}},"operationId":"postWebhooksByIdTest","parameters":[{"$ref":"#/components/parameters/IdempotencyKey"},{"$ref":"#/components/parameters/DryRun"}]}},"/webhooks/{id}/deliveries":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Endpoint id"}],"get":{"tags":["Webhooks"],"summary":"Delivery log","parameters":[{"$ref":"#/components/parameters/Limit"},{"$ref":"#/components/parameters/Cursor"},{"name":"status","in":"query","required":false,"schema":{"type":"string","enum":["pending","succeeded","failed"]},"description":"Only one outcome."}],"responses":{"200":{"description":"A page of deliveries.","content":{"application/json":{"schema":{"type":"object","required":["data","has_more","next_cursor"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/WebhookDelivery"}},"has_more":{"type":"boolean"},"next_cursor":{"type":["string","null"],"description":"Pass as `cursor` to get the next page."}}}}},"headers":{"x-request-id":{"description":"Unique id of this request. Quote it to support.","schema":{"type":"string"}},"x-ratelimit-limit":{"description":"Requests allowed per minute for this key.","schema":{"type":"integer"}},"x-ratelimit-remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"x-ratelimit-reset":{"description":"Seconds until the window resets.","schema":{"type":"integer"}}}},"401":{"$ref":"#/components/responses/E401"},"404":{"$ref":"#/components/responses/E404"},"429":{"$ref":"#/components/responses/E429"}},"operationId":"getWebhooksByIdDeliveries"}},"/webhooks/deliveries/{deliveryId}/resend":{"parameters":[{"name":"deliveryId","in":"path","required":true,"schema":{"type":"string"},"description":"Delivery id"}],"post":{"tags":["Webhooks"],"summary":"Resend a delivery","responses":{"200":{"description":"The new outcome.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookDelivery"}}},"headers":{"x-request-id":{"description":"Unique id of this request. Quote it to support.","schema":{"type":"string"}},"x-ratelimit-limit":{"description":"Requests allowed per minute for this key.","schema":{"type":"integer"}},"x-ratelimit-remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"x-ratelimit-reset":{"description":"Seconds until the window resets.","schema":{"type":"integer"}}}},"401":{"$ref":"#/components/responses/E401"},"403":{"$ref":"#/components/responses/E403"},"404":{"$ref":"#/components/responses/E404"},"429":{"$ref":"#/components/responses/E429"}},"operationId":"postWebhooksDeliveriesByDeliveryIdResend","parameters":[{"$ref":"#/components/parameters/IdempotencyKey"},{"$ref":"#/components/parameters/DryRun"}]}}},"components":{"securitySchemes":{"apiKey":{"type":"http","scheme":"bearer","bearerFormat":"dpp_live_<40 hex>","description":"Create a key in the app under Organisation → API keys. It is shown once."}},"schemas":{"Error":{"type":"object","required":["error"],"properties":{"error":{"type":"string"},"message":{"type":"string"},"details":{"type":"object","additionalProperties":{"type":"array","items":{"type":"string"}}}}},"Passport":{"type":"object","description":"A battery passport as listed by the API.","properties":{"id":{"type":"string"},"uniqueIdentifier":{"type":"string","description":"Immutable, resolvable identifier printed in the QR code."},"serialNumber":{"type":["string","null"]},"itemId":{"type":"string"},"modelId":{"type":"string"},"placeOfManufacture":{"type":["string","null"]},"dateOfManufacture":{"type":["string","null"],"format":"date-time"},"status":{"type":"string","enum":["ORIGINAL","REPURPOSED","REUSED","REMANUFACTURED","WASTE"],"description":"Annex XIII 4(c)."},"lifecycleState":{"type":"string","enum":["ACTIVE","CEASED_RECYCLED"]},"displayStatus":{"type":"string","enum":["draft","pending","published","attention","repurposed","waste","recycled"]},"attentionReasons":{"type":"array","items":{"type":"string","enum":["registration_failed","missing_place_of_manufacture","operator_verification_lapsed"]}},"publishedAt":{"type":["string","null"],"format":"date-time"},"registrationStatus":{"type":["string","null"],"enum":["pending","registered","failed",null]},"links":{"type":"object","properties":{"public":{"type":["string","null"],"description":"The URL the QR code encodes."},"publicJson":{"type":"string"},"jsonLd":{"type":"string"},"qrSvg":{"type":"string"},"qrPng":{"type":"string"}}},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"DynamicEvent":{"type":"object","properties":{"id":{"type":"string"},"eventType":{"type":"string","enum":["PUT_INTO_SERVICE","REPAIR","SOH_READING","LIFETIME_METRIC","CYCLE_COUNT","STATUS_CHANGE","NEGATIVE_EVENT","OPERATING_CONDITION","PERFORMANCE_VALUE","BMS_SOFTWARE_RESET"]},"payload":{"type":"object","additionalProperties":true,"description":"Keyed by field name — see /field-catalog, fields of kind `dynamic`."},"recordedAt":{"type":"string","format":"date-time"},"bmsHistoryInvalidatedByReset":{"type":"boolean"}}},"Document":{"type":"object","properties":{"id":{"type":"string"},"modelId":{"type":"string"},"name":{"type":"string"},"type":{"type":"string","examples":["EU Declaration of Conformity","Test Report","Safety Data Sheet"]},"point":{"type":"integer","description":"Annex XIII point: 1 public, 3 authority only."},"mimeType":{"type":"string"},"size":{"type":"integer"},"downloadUrl":{"type":"string"},"createdAt":{"type":"string","format":"date-time"}}},"AuditEntry":{"type":"object","description":"One entry of the integrity log (Art. 78(g)). Hashes let you prove what a record looked like without us storing a copy here.","properties":{"id":{"type":"string"},"entity":{"type":"string","examples":["BatteryModel","BatteryPassport","BatteryItem","Document","ApiKey","WebhookEndpoint"]},"entityId":{"type":"string"},"action":{"type":"string","examples":["create","update","publish","recycle","revoke"]},"beforeHash":{"type":["string","null"],"description":"SHA-256 of the record before the change."},"afterHash":{"type":["string","null"],"description":"SHA-256 of the record after the change."},"at":{"type":"string","format":"date-time"},"entityLabel":{"type":["string","null"],"description":"Human name of the target at the time (model name, passport identifier)."},"modelId":{"type":["string","null"],"description":"The battery model the record belongs to."},"passportId":{"type":["string","null"]},"actor":{"type":["object","null"],"description":"Who did it. Null on entries written before actors were recorded.","properties":{"type":{"type":"string","enum":["USER","API_KEY","SUPPLIER","SYSTEM"]},"id":{"type":["string","null"],"description":"User, API key or supplier link id."},"label":{"type":["string","null"],"description":"The actor's name at the time."}}},"source":{"type":["string","null"],"enum":["panel","api","supplier","import","system",null]},"requestId":{"type":["string","null"],"description":"The x-request-id of the request that made the change."}}},"WebhookEndpoint":{"type":"object","properties":{"id":{"type":"string"},"url":{"type":"string","format":"uri"},"description":{"type":["string","null"]},"events":{"type":"array","items":{"type":"string","enum":["model.created","model.updated","document.uploaded","passport.created","passport.published","passport.status_changed","passport.recycled","passport.event_recorded","supplier.submitted"]},"description":"Empty = every event."},"enabled":{"type":"boolean"},"createdAt":{"type":"string","format":"date-time"},"lastDelivery":{"type":["object","null"]},"failedDeliveries":{"type":"integer"}}},"WebhookDelivery":{"type":"object","properties":{"id":{"type":"string"},"eventId":{"type":"string"},"eventType":{"type":"string"},"status":{"type":"string","enum":["pending","succeeded","failed"]},"attempts":{"type":"integer"},"responseStatus":{"type":["integer","null"]},"responseBody":{"type":["string","null"],"description":"First 2,000 characters of what your endpoint answered."},"lastError":{"type":["string","null"]},"nextAttemptAt":{"type":["string","null"],"format":"date-time"},"createdAt":{"type":"string","format":"date-time"},"deliveredAt":{"type":["string","null"],"format":"date-time"},"payload":{"$ref":"#/components/schemas/WebhookEvent"}}},"WebhookEvent":{"type":"object","required":["id","type","created_at","data"],"properties":{"id":{"type":"string","description":"Stable across retries — use it to de-duplicate."},"type":{"type":"string","enum":["model.created","model.updated","document.uploaded","passport.created","passport.published","passport.status_changed","passport.recycled","passport.event_recorded","supplier.submitted","ping"]},"created_at":{"type":"string","format":"date-time"},"data":{"type":"object","additionalProperties":true}}},"PublishBlocker":{"type":"object","properties":{"reason":{"type":"string","enum":["missing_place_of_manufacture","model_incomplete"]},"message":{"type":"string"},"missing":{"type":"array","items":{"type":"object"}}}},"DryRunResult":{"type":"object","required":["dry_run","valid","operation"],"properties":{"dry_run":{"const":true},"valid":{"type":"boolean"},"operation":{"type":"string","examples":["POST /models"]},"mode":{"type":"string","enum":["live","test"]},"checks":{"type":"array","items":{"type":"string"}},"completeness":{"type":"object","description":"For POST /models: what the new model would still owe."},"would_publish":{"type":"boolean","description":"For publish: whether it would go live."},"blockers":{"type":"array","items":{"$ref":"#/components/schemas/PublishBlocker"}},"message":{"type":"string"}}},"Me":{"type":"object","properties":{"apiKey":{"type":"object","properties":{"name":{"type":"string"},"prefix":{"type":"string"},"scopes":{"type":"array","items":{"type":"string"}},"mode":{"type":"string"}}},"organisation":{"type":"object","properties":{"id":{"type":"string"},"legalName":{"type":"string"},"country":{"type":"string"},"esprOperatorIdentifier":{"type":["string","null"]}}},"plan":{"type":"object","properties":{"key":{"type":"string"},"label":{"type":"string"},"status":{"type":"string"},"features":{"type":"array","items":{"type":"string"}}}},"usage":{"type":"object","properties":{"periodStart":{"type":"string"},"passportsPublished":{"type":"integer"},"includedPassportsPerYear":{"type":["integer","null"]},"models":{"type":"integer"},"includedModels":{"type":["integer","null"]}}},"rateLimit":{"type":"object","properties":{"requestsPerMinute":{"type":"integer"}}},"apiVersion":{"type":"string"}}}},"responses":{"E400":{"description":"Validation failed — `details` names each field.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"E401":{"description":"Missing, invalid or revoked API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"E402":{"description":"Your plan does not include this (e.g. publishing on the Free plan, or a paused Maintenance plan).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"E403":{"description":"`insufficient_scope`, `method_not_allowed_for_api_keys`, or a plan limit.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"E404":{"description":"Not found in your organisation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"E409":{"description":"Conflict, e.g. `organisation_frozen`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"E422":{"description":"A business rule refused the request; `message` says which.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"E429":{"description":"Rate limited — 600 requests per minute per key. See `retry-after`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"DryRun":{"description":"Dry run: validated, nothing stored.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DryRunResult"}}}}},"parameters":{"Limit":{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":200,"default":50},"description":"Page size."},"Cursor":{"name":"cursor","in":"query","required":false,"schema":{"type":"string"},"description":"`next_cursor` from the previous page."},"IdempotencyKey":{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Makes a retry safe: the first answer is stored for 24 h and returned again (with `Idempotent-Replayed: true`). Reusing a key for a different request is refused with 422."},"DryRun":{"name":"X-DPP-Dry-Run","in":"header","required":false,"schema":{"type":"string","enum":["true"]},"description":"Validate this write in full and store nothing. Test keys (`dpp_test_…`) always dry-run."}}},"webhooks":{"model.created":{"post":{"operationId":"webhookModelCreated","summary":"A battery model was created.","description":"Signed: `DPP-Signature: t=<unix seconds>,v1=<hex>` where v1 = HMAC-SHA256(endpoint secret, `<t>.<raw body>`). Also sent: `DPP-Event`, `DPP-Event-Id` (stable across retries — de-duplicate on it), `DPP-Delivery`. Answer 2xx within 10 s; otherwise we retry after 1 min, 5 min, 30 min, 2 h and 6 h.","parameters":[{"name":"DPP-Signature","in":"header","required":true,"schema":{"type":"string"}},{"name":"DPP-Event","in":"header","required":true,"schema":{"type":"string","const":"model.created"}},{"name":"DPP-Event-Id","in":"header","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/WebhookEvent"},{"type":"object","properties":{"type":{"const":"model.created"},"data":{"type":"object","properties":{"model":{"type":"object"}}}}}]}}}},"responses":{"2XX":{"description":"Received."}}}},"model.updated":{"post":{"operationId":"webhookModelUpdated","summary":"A battery model's data changed.","description":"Signed: `DPP-Signature: t=<unix seconds>,v1=<hex>` where v1 = HMAC-SHA256(endpoint secret, `<t>.<raw body>`). Also sent: `DPP-Event`, `DPP-Event-Id` (stable across retries — de-duplicate on it), `DPP-Delivery`. Answer 2xx within 10 s; otherwise we retry after 1 min, 5 min, 30 min, 2 h and 6 h.","parameters":[{"name":"DPP-Signature","in":"header","required":true,"schema":{"type":"string"}},{"name":"DPP-Event","in":"header","required":true,"schema":{"type":"string","const":"model.updated"}},{"name":"DPP-Event-Id","in":"header","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/WebhookEvent"},{"type":"object","properties":{"type":{"const":"model.updated"},"data":{"type":"object","properties":{"model":{"type":"object"}}}}}]}}}},"responses":{"2XX":{"description":"Received."}}}},"document.uploaded":{"post":{"operationId":"webhookDocumentUploaded","summary":"A document was attached to a model.","description":"Signed: `DPP-Signature: t=<unix seconds>,v1=<hex>` where v1 = HMAC-SHA256(endpoint secret, `<t>.<raw body>`). Also sent: `DPP-Event`, `DPP-Event-Id` (stable across retries — de-duplicate on it), `DPP-Delivery`. Answer 2xx within 10 s; otherwise we retry after 1 min, 5 min, 30 min, 2 h and 6 h.","parameters":[{"name":"DPP-Signature","in":"header","required":true,"schema":{"type":"string"}},{"name":"DPP-Event","in":"header","required":true,"schema":{"type":"string","const":"document.uploaded"}},{"name":"DPP-Event-Id","in":"header","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/WebhookEvent"},{"type":"object","properties":{"type":{"const":"document.uploaded"},"data":{"type":"object","properties":{"document":{"$ref":"#/components/schemas/Document"}}}}}]}}}},"responses":{"2XX":{"description":"Received."}}}},"passport.created":{"post":{"operationId":"webhookPassportCreated","summary":"A battery was created; its passport is a draft.","description":"Signed: `DPP-Signature: t=<unix seconds>,v1=<hex>` where v1 = HMAC-SHA256(endpoint secret, `<t>.<raw body>`). Also sent: `DPP-Event`, `DPP-Event-Id` (stable across retries — de-duplicate on it), `DPP-Delivery`. Answer 2xx within 10 s; otherwise we retry after 1 min, 5 min, 30 min, 2 h and 6 h.","parameters":[{"name":"DPP-Signature","in":"header","required":true,"schema":{"type":"string"}},{"name":"DPP-Event","in":"header","required":true,"schema":{"type":"string","const":"passport.created"}},{"name":"DPP-Event-Id","in":"header","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/WebhookEvent"},{"type":"object","properties":{"type":{"const":"passport.created"},"data":{"type":"object","properties":{"passport":{"type":"object"}}}}}]}}}},"responses":{"2XX":{"description":"Received."}}}},"passport.published":{"post":{"operationId":"webhookPassportPublished","summary":"A passport went live on its public URL.","description":"Signed: `DPP-Signature: t=<unix seconds>,v1=<hex>` where v1 = HMAC-SHA256(endpoint secret, `<t>.<raw body>`). Also sent: `DPP-Event`, `DPP-Event-Id` (stable across retries — de-duplicate on it), `DPP-Delivery`. Answer 2xx within 10 s; otherwise we retry after 1 min, 5 min, 30 min, 2 h and 6 h.","parameters":[{"name":"DPP-Signature","in":"header","required":true,"schema":{"type":"string"}},{"name":"DPP-Event","in":"header","required":true,"schema":{"type":"string","const":"passport.published"}},{"name":"DPP-Event-Id","in":"header","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/WebhookEvent"},{"type":"object","properties":{"type":{"const":"passport.published"},"data":{"type":"object","properties":{"passport":{"type":"object"}}}}}]}}}},"responses":{"2XX":{"description":"Received."}}}},"passport.status_changed":{"post":{"operationId":"webhookPassportStatusChanged","summary":"Status changed (Annex XIII 4(c)). For repurposed, re-used or remanufactured batteries `forked` names the new linked passport; a change to waste carries none.","description":"Signed: `DPP-Signature: t=<unix seconds>,v1=<hex>` where v1 = HMAC-SHA256(endpoint secret, `<t>.<raw body>`). Also sent: `DPP-Event`, `DPP-Event-Id` (stable across retries — de-duplicate on it), `DPP-Delivery`. Answer 2xx within 10 s; otherwise we retry after 1 min, 5 min, 30 min, 2 h and 6 h.","parameters":[{"name":"DPP-Signature","in":"header","required":true,"schema":{"type":"string"}},{"name":"DPP-Event","in":"header","required":true,"schema":{"type":"string","const":"passport.status_changed"}},{"name":"DPP-Event-Id","in":"header","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/WebhookEvent"},{"type":"object","properties":{"type":{"const":"passport.status_changed"},"data":{"type":"object","properties":{"passport":{"type":"object"},"status":{"type":"string"},"forked":{"type":"object"}}}}}]}}}},"responses":{"2XX":{"description":"Received."}}}},"passport.recycled":{"post":{"operationId":"webhookPassportRecycled","summary":"The passport ceased; its public URL now answers 410.","description":"Signed: `DPP-Signature: t=<unix seconds>,v1=<hex>` where v1 = HMAC-SHA256(endpoint secret, `<t>.<raw body>`). Also sent: `DPP-Event`, `DPP-Event-Id` (stable across retries — de-duplicate on it), `DPP-Delivery`. Answer 2xx within 10 s; otherwise we retry after 1 min, 5 min, 30 min, 2 h and 6 h.","parameters":[{"name":"DPP-Signature","in":"header","required":true,"schema":{"type":"string"}},{"name":"DPP-Event","in":"header","required":true,"schema":{"type":"string","const":"passport.recycled"}},{"name":"DPP-Event-Id","in":"header","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/WebhookEvent"},{"type":"object","properties":{"type":{"const":"passport.recycled"},"data":{"type":"object","properties":{"passport":{"type":"object"}}}}}]}}}},"responses":{"2XX":{"description":"Received."}}}},"passport.event_recorded":{"post":{"operationId":"webhookPassportEventRecorded","summary":"New dynamic data was recorded.","description":"Signed: `DPP-Signature: t=<unix seconds>,v1=<hex>` where v1 = HMAC-SHA256(endpoint secret, `<t>.<raw body>`). Also sent: `DPP-Event`, `DPP-Event-Id` (stable across retries — de-duplicate on it), `DPP-Delivery`. Answer 2xx within 10 s; otherwise we retry after 1 min, 5 min, 30 min, 2 h and 6 h.","parameters":[{"name":"DPP-Signature","in":"header","required":true,"schema":{"type":"string"}},{"name":"DPP-Event","in":"header","required":true,"schema":{"type":"string","const":"passport.event_recorded"}},{"name":"DPP-Event-Id","in":"header","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/WebhookEvent"},{"type":"object","properties":{"type":{"const":"passport.event_recorded"},"data":{"type":"object","properties":{"passport":{"type":"object"},"event":{"$ref":"#/components/schemas/DynamicEvent"}}}}}]}}}},"responses":{"2XX":{"description":"Received."}}}},"supplier.submitted":{"post":{"operationId":"webhookSupplierSubmitted","summary":"A supplier answered a data request (values or a file).","description":"Signed: `DPP-Signature: t=<unix seconds>,v1=<hex>` where v1 = HMAC-SHA256(endpoint secret, `<t>.<raw body>`). Also sent: `DPP-Event`, `DPP-Event-Id` (stable across retries — de-duplicate on it), `DPP-Delivery`. Answer 2xx within 10 s; otherwise we retry after 1 min, 5 min, 30 min, 2 h and 6 h.","parameters":[{"name":"DPP-Signature","in":"header","required":true,"schema":{"type":"string"}},{"name":"DPP-Event","in":"header","required":true,"schema":{"type":"string","const":"supplier.submitted"}},{"name":"DPP-Event-Id","in":"header","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/WebhookEvent"},{"type":"object","properties":{"type":{"const":"supplier.submitted"},"data":{"type":"object","properties":{"request":{"type":"object"},"fields":{"type":"array","items":{"type":"string"}},"file":{"type":"object"}}}}}]}}}},"responses":{"2XX":{"description":"Received."}}}}}}