# Security and data protection

> How BatteryPass protects API access and passport data, and what your integration should do and avoid.

This page describes the technical measures that apply to integrations and what you are responsible for on
your side. It is a description, not a certification or an audit statement.

## Transport

Production installations of BatteryPass are served over HTTPS; the reference deployment terminates TLS at its
reverse proxy and sends `Strict-Transport-Security`. Send API keys only to your BatteryPass address over HTTPS, and do not disable
certificate checks in your HTTP client.

## API keys

| Measure     | Detail                                                                                                                                             |
| ----------- | -------------------------------------------------------------------------------------------------------------------------------------------------- |
| Secret      | `bp_live_` followed by 43 base64url characters (32 random bytes)                                                                                   |
| Storage     | BatteryPass stores only the SHA-256 of the key. The key is shown once, when an owner creates it in the portal; it cannot be displayed again.       |
| Recognition | The first 12 characters (`bp_live_` and four more) are kept as a prefix, so owners can tell keys apart in the portal.                              |
| Header only | Keys are accepted only in `Authorization: Bearer`, never in a URL. A request that carries both a session cookie and a key is refused with `401`.   |
| Lifetime    | Keys have no expiry. Revoking is the only way to stop one; a revoked key never works again. Rotate by creating a new key and revoking the old one. |
| Number      | At most 25 active keys per organisation.                                                                                                           |

Owners create and revoke keys in the portal and see when each key was last used. See
[Authentication](https://passport.kabin.sh/docs/en/authentication) and [Secure key handling](https://passport.kabin.sh/docs/en/guides/secure-key-handling).

## What a key may do

- **Scopes.** A key has one or more of `read`, `condition` and `import`. Each operation names its scope in `x-api-key-scope`; a key
  without that scope gets `403 forbidden`. Give each system only the scope it needs.
- **Viewer rights.** A key acts in its organisation with the rights of a viewer. It never changes declared data,
  approves values, publishes or withdraws passports, and never manages members, keys or settings.
- **Organisation isolation.** Every request is scoped to the key's organisation. Ids of another organisation's
  resources behave as if they did not exist (`404 not_found`).

## Rate limits

| Limit                      | Applies to                                                                   |
| -------------------------- | ---------------------------------------------------------------------------- |
| 600 requests per minute    | All keys of one organisation together                                        |
| 30 attempts per 15 minutes | Unknown or revoked keys, per client address                                  |
| 300 requests per minute    | Public passport reads, public documents and the resolver, per client address |

A limited request gets `429 rate_limited` with a `Retry-After` header in seconds
([Rate limits](https://passport.kabin.sh/docs/en/rate-limits)).

## Audit

Every write made with a key (a condition update or a lifecycle event) is recorded in the organisation's audit
log with the actor `api_key` and the key's id, in the same transaction as the change. The values and events it
creates carry `source` `api`; the lifecycle event of each update names the key (`api_key`). Creating and revoking keys is audited with the member who did
it. Reads with a key are not audited.

## Passport data

- Public operations and the resolver serve only the stored `public` projection of a version
  ([Access tiers](https://passport.kabin.sh/docs/en/concepts/access-tiers)). Restricted tiers never appear in a public response, and
  restricted documents are never linked from one.
- Reading restricted tiers as a third party is a separate portal feature behind a switch that is off by default;
  every such read is audited.
- Each published version is signed, so changes after publication are detectable
  ([Signatures](https://passport.kabin.sh/docs/en/concepts/signatures)).
- Errors are Problem Details with a stable `code` and a `request_id`; they contain no SQL, stack traces or
  upstream error texts ([Errors](https://passport.kabin.sh/docs/en/errors)).

## Data protection for integrations

BatteryPass is about batteries, not people, and your integration should keep it that way.

> [!WARNING]
> Do not send personal data in free text: the `note` of a condition update and the `description` of a lifecycle
> event. Write "Module 3 replaced" rather than the technician's or the end customer's name, address, phone number
> or vehicle registration. Events and measurements cannot be edited or deleted through the API, every member of
> your organisation can read them, and they are part of the organisation's full export.

What you read can contain personal data too: provenance names members (`recorded_by`, `reviewed_by`,
`responsible`, `published_by_name`), and an event reported by a service partner can carry the partner's email
address. If your integration copies such data into another system, that system needs a legal basis and a
retention rule for it. Copy only what you need.

## This documentation

The documentation pages load no analytics, advertising or third-party tracking scripts. The menu entries that
open a page in an AI assistant send the page's address to that service only when you click them.

## Reporting a security problem

If you suspect a key has leaked, ask an owner of your organisation to revoke it at once and create a new one.
Report a suspected vulnerability directly to the operator of your BatteryPass installation, not in a shared
channel ([Support](https://passport.kabin.sh/docs/en/general/support)).
