# Passports and versions

> The passport of a unit, its statuses, its signed and immutable versions, the differences between them and the exports.

Every unit has exactly one passport. Each publication adds a numbered version that never changes afterwards.
When the data of a unit changes, the passport is published again and gets a new version; the old versions stay
readable as the passport's history.

## The passport

Read a unit's passport with [`getPassport`](https://passport.kabin.sh/docs/en/api-reference/passports/get-passport).

| Field                                         | Meaning                                                                                                                                                                |
| --------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `passport_id`                                 | The permanent identifier `urn:dpp:{uuid}`, assigned when the identifiers are locked or at the first publication. Public operations take the UUID part as `passportId`. |
| `status`                                      | See below.                                                                                                                                                             |
| `gs1_digital_link`                            | The link on the QR code ([GS1 Digital Link](https://passport.kabin.sh/docs/en/concepts/digital-link)); fixed once the identifiers are locked.                        |
| `gtin`, `serial_number`                       | The unit's identifiers as locked.                                                                                                                                      |
| `current_version`                             | Summary of the version that is online now.                                                                                                                             |
| `first_published_at`, `identifiers_locked_at` | When the passport went online for the first time, and when its identifiers were fixed.                                                                                 |
| `public_url`                                  | The public passport page, once published.                                                                                                                              |
| `withdrawn_at`, `withdrawn_reason`            | Set when the passport was taken offline.                                                                                                                               |

A unit whose identifiers are not locked and that was never published has a passport in status `draft` without
`passport_id`.

## Statuses

```mermaid
stateDiagram-v2
  [*] --> draft
  draft --> qr_locked: identifiers locked
  draft --> published: first publication
  qr_locked --> published: first publication
  published --> update_needed: data or registry changed
  update_needed --> published: published again
  published --> withdrawn: withdrawn with a reason
```

| `status`                        | Online | Meaning                                                                                                                                                                                           |
| ------------------------------- | ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `draft`                         | No     | Nothing published yet, no identifier.                                                                                                                                                             |
| `qr_locked`                     | No     | Identifiers locked so labels can be printed before the first publication. Public reads return the status without content.                                                                         |
| `published`                     | Yes    | The current version is public.                                                                                                                                                                    |
| `update_needed`                 | Yes    | Still online with its current version, but needs to be published again: the registry changed, the unit moved to another model version, or an automatic publication of condition data was blocked. |
| `withdrawn`                     | No     | Taken offline by an admin or owner, with a reason. Public reads return the status without content.                                                                                                |
| `suspended`, `deleted_recycled` | No     | Defined in the contract for later use; the current release does not set them.                                                                                                                     |

## Versions

A version is created by a publication. Reviewers publish in the portal, with a reason; condition data can
also publish a version automatically ([Condition data and lifecycle](https://passport.kabin.sh/docs/en/concepts/condition-and-lifecycle)).
Publishing unchanged content adds no version.

Each version stores, immutably:

- the **snapshot**: every field of both levels in every tier, with its value, unit, status and provenance
  (source, revision, reviewer, review or measurement time, documents);
- the **public document**: the `public` tier projection of the snapshot;
- a [signature](https://passport.kabin.sh/docs/en/concepts/signatures) of each, with the hashes `canonical_hash` and `public_hash` and
  the `key_id`;
- the BatteryPass v2.0 export and its schema report (advisory: it does not block publication).

| Operation                                                                                                          | Returns                                                                                                   |
| ------------------------------------------------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------- |
| [`listPassportVersions`](https://passport.kabin.sh/docs/en/api-reference/passports/list-passport-versions)       | Version summaries, newest first. With `at`, the first item is the version that was valid at that instant. |
| [`getPassportVersion`](https://passport.kabin.sh/docs/en/api-reference/passports/get-passport-version)           | One version with `snapshot`, `public_document`, both signatures and the `batterypass_v2` report.          |
| [`getPublicPassportVersion`](https://passport.kabin.sh/docs/en/api-reference/public/get-public-passport-version) | The public passport as it was at `at`, without a key.                                                     |

A summary carries `version_no`, `published_at`, `reason`, `published_by_name` (absent when the system
published), `registry_version`, the hashes, `key_id` and `valid_until`. `valid_until` is set when a later
version replaces this one, so the version valid at time `t` is the one with `published_at ≤ t < valid_until`.

## Differences between versions

[`getPassportVersionDiff`](https://passport.kabin.sh/docs/en/api-reference/passports/get-passport-version-diff) compares two signed
snapshots field by field. By default it compares a version with the one before it; `against` names another
version number.

| `fields[].change` | Meaning                                                    |
| ----------------- | ---------------------------------------------------------- |
| `added`           | The field has a value in this version and had none before. |
| `removed`         | The field had a value before and has none now.             |
| `changed`         | The value changed.                                         |
| `provenance`      | Same value, newer revision: re-approved or measured again. |

Each change has `before` and `after` with value, unit, tier, source, revision, `measured_at` and the titles of
the documents. `metadata[]` lists changes of `model_version`, `registry_version`, `category`, `facility`,
`operator` and `predecessor`.

```bash title="cURL"
curl -s "$BATTERYPASS_URL/api/v1/batteries/$BATTERY_ID/passport/versions/3/diff" \
  -H "Authorization: Bearer $BATTERYPASS_API_KEY"
```

## Exports

| Export           | Operation                                                                                                | Content                                                                                                                                                  |
| ---------------- | -------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- |
| BatteryPass JSON | [`exportPassportJson`](https://passport.kabin.sh/docs/en/api-reference/passports/export-passport-json) | The BatteryPass v2.0 document of a version, all tiers, as stored at publication. Sent as an attachment.                                                  |
| PDF              | [`exportPassportPdf`](https://passport.kabin.sh/docs/en/api-reference/passports/export-passport-pdf)   | Every tier with restricted rows tagged, the signature and the QR code; `lang=de` or `lang=en`.                                                           |
| QR code          | [`getPassportQr`](https://passport.kabin.sh/docs/en/api-reference/passports/get-passport-qr)           | The GS1 Digital Link as PNG (`size` 128 to 2048 pixels, default 512) or SVG (`format=svg`). Only once the identifiers are locked; `409 conflict` before. |
| Public JSON      | [`getPublicPassport`](https://passport.kabin.sh/docs/en/api-reference/public/get-public-passport)      | The signed public document of the current version, without a key.                                                                                        |

> [!WARNING]
> The BatteryPass JSON and the PDF contain the restricted tiers. Treat these files as confidential and do not
> publish them; the public JSON is the version meant for everyone ([Access tiers](https://passport.kabin.sh/docs/en/concepts/access-tiers)).

## EU registry

[`getRegistrySubmissionStatus`](https://passport.kabin.sh/docs/en/api-reference/passports/get-registry-submission-status) reports the
passport's registration with the EU registry. The EU registry offers no interface for economic operators yet,
so BatteryPass submits nothing and the state is `not_available`. A passport is never shown as registered
without the registry's confirmation.

> [!NOTE]
> Publishing and locking identifiers are portal actions for reviewers; withdrawing a passport is one for admins
> and owners. An API key reads passports and their versions, but never publishes or withdraws.
