# Condition data and lifecycle events

> How measured condition data reaches a passport without a review step, how the re-publication policy works, and what lifecycle events record.

A battery's passport does not stop at the factory. Two kinds of information follow it through its life:
**condition data**, the measured state of health and usage of a unit, and **lifecycle events**, the record of
what happened to it. Both can be reported through the API with a key that has the `condition` scope.

## Condition data

Condition data are the registry's dynamic fields (the section `condition`, Annex XIII point 4): measured values
of one unit, such as `condition.capacity_fade`, `condition.remaining_capacity`,
`condition.number_of_full_cycles` or, for EV batteries, `condition.state_of_certified_energy`. Which fields apply
depends on the battery category; [`getCondition`](https://passport.kabin.sh/docs/en/api-reference/lifecycle/get-condition) lists them in
`field_keys`, with their current values and `measured_at`.

In the current registry all condition fields are in the `legitimate_interest` tier, so they never appear in the
public JSON ([Access tiers](https://passport.kabin.sh/docs/en/concepts/access-tiers)).

### Measurements, not declarations

What a battery management system measured is not something a reviewer can verify better than the device. A
condition update is therefore accepted as a measurement, without the review step that declared data needs:

- each value is stored directly as `approved`, with its `measured_at`, its `source` (`api` for a key,
  `supplier` for a service partner's report, `manual` for a member); a member is named in `recorded_by`, a key
  in the `api_key` of the update's lifecycle event (values carry no key);
- `reviewed_at` is the time of acceptance, and there is no reviewer, so the four-eyes rule does not apply;
- every accepted update records a `condition_update` lifecycle event and an audit entry.

Condition values that a member types into the unit editor or imports from a spreadsheet keep the normal review
([Provenance and review](https://passport.kabin.sh/docs/en/concepts/provenance-and-review)).

### Reporting an update

[`updateCondition`](https://passport.kabin.sh/docs/en/api-reference/lifecycle/update-condition) merges the values you send into the
unit's condition data:

```bash title="cURL"
curl -s -X PATCH "$BATTERYPASS_URL/api/v1/batteries/$BATTERY_ID/condition" \
  -H "Authorization: Bearer $BATTERYPASS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "measured_at": "2026-10-24T06:00:00Z",
    "note": "Weekly BMS reading",
    "values": [
      { "field_key": "condition.capacity_fade", "value": 3.2 },
      { "field_key": "condition.number_of_full_cycles", "value": 412 }
    ]
  }'
```

| Rule                       | Effect                                                                                                                                                       |
| -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| Merge                      | Only the named fields change; `null` clears a field. At most 50 values per request.                                                                          |
| `measured_at`              | Each value has its own or the request's. It must not lie in the future or before the unit's manufacturing date.                                              |
| Older or equal measurement | A value measured before the stored one, or at the same time with the same value, is skipped and listed in `skipped[]` (`older_measurement`, `unchanged`).    |
| All or nothing             | A field that is not a dynamic field of the unit (`unknown_field`), an invalid value, or merged data that fails a cross-field check refuses the whole update. |

The response lists `accepted` values, `skipped` ones, the recorded `event` and the `publication` outcome.

### Re-publication policy

When the unit's passport is published, accepted condition data has to reach a new passport version. The
organisation chooses when, in its settings in the portal (`condition_republish`, returned by `getCondition` as
`republish`):

| Policy                | Behaviour                                                                                                                                                        |
| --------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `immediate` (default) | The same request publishes the next version, with the reason `condition update` and no member as publisher.                                                      |
| `daily`               | A daily job at 02:00 UTC publishes every published passport whose unit received condition data after its current version, so a day's updates become one version. |

`publication.outcome` in the response tells you what happened:

| `outcome`       | Meaning                                                                                                                      |
| --------------- | ---------------------------------------------------------------------------------------------------------------------------- |
| `published`     | A new version was published in this request.                                                                                 |
| `unchanged`     | Nothing in the passport changed, so no version was added.                                                                    |
| `scheduled`     | The daily job will publish it.                                                                                               |
| `blocked`       | The publish gate refused (see `blockers`); the update stays accepted and the passport becomes `update_needed`, still online. |
| `not_published` | The unit has no published passport yet.                                                                                      |

## Lifecycle events

A lifecycle event records something that happened to a unit on a given day. Report one with
[`createLifecycleEvent`](https://passport.kabin.sh/docs/en/api-reference/lifecycle/create-lifecycle-event) and read the history, newest
first, with [`listLifecycleEvents`](https://passport.kabin.sh/docs/en/api-reference/lifecycle/list-lifecycle-events).

| Type you can report (`ReportedEventType`) | Typical use                                    |
| ----------------------------------------- | ---------------------------------------------- |
| `placed_on_market`                        | The battery was placed on the market           |
| `put_into_service`                        | The battery was put into service               |
| `inspection`                              | An inspection or diagnosis                     |
| `repair`                                  | A repair                                       |
| `component_replaced`                      | A module, cell or other component was replaced |
| `condition_update`                        | A condition reading worth recording on its own |
| `waste`                                   | The battery became waste                       |
| `recycled`                                | The battery was recycled                       |
| `custom`                                  | Anything else, described in `description`      |

BatteryPass records two more kinds itself: `condition_update` for every accepted condition update, and
`repurposed`, `reused` or `remanufactured` when a member creates a second-life battery in the portal.

An event has `occurred_on` (a date between the manufacturing date and today), an optional `description` (up to
2000 characters) and up to 20 `evidence_ids`, documents that already exist in the evidence library such as a
repair protocol. Events reported with a key carry `source` `api` and name the key in `api_key`.

> [!WARNING]
> Events are records: they change no data of the unit. A `put_into_service` event does not set the unit's
> `putting_into_service` date, and `waste` or `recycled` does not change its battery status or end its passport.
> Report measured values with `updateCondition`; members change unit data in the portal. Events cannot be edited
> or deleted afterwards.

## Next steps

[**Push condition data**](https://passport.kabin.sh/docs/en/guides/push-condition-data): Report measurements from a battery management system.

[**Record lifecycle events**](https://passport.kabin.sh/docs/en/guides/record-lifecycle-events): Report repairs, inspections and other events.
