# Support

> How to get help with an integration, what to include in a request, and where the status of features is documented.

## Who to contact

| Question                                                                  | Contact                                                                    |
| ------------------------------------------------------------------------- | -------------------------------------------------------------------------- |
| API keys, scopes, organisation settings such as the re-publication policy | An owner of your organisation, in the portal                               |
| Data in a passport, review, publication                                   | The members of your organisation responsible for the data                  |
| Errors you cannot explain, outages, suspected security problems           | Your BatteryPass contact, or the operator of your BatteryPass installation |

Support channels and response times are agreed with the operator of your installation; this documentation does
not define them.

## Check first

- The Problem's `code`, `detail` and `errors[]` usually name the cause; [Errors](https://passport.kabin.sh/docs/en/errors) explains
  every code, and [Handle errors](https://passport.kabin.sh/docs/en/guides/handle-errors) shows how to react to them.
- `429 rate_limited`: wait for `Retry-After` seconds ([Rate limits](https://passport.kabin.sh/docs/en/rate-limits)).
- `403 forbidden` with a key: the key lacks the operation's scope, or the operation needs more than a viewer's
  rights ([Authentication](https://passport.kabin.sh/docs/en/authentication)).

## Quote the request id

Every response, successful or not, carries an `X-Request-Id` header. Error responses repeat it as `request_id`
in the Problem body. With this id the operator finds your request in the logs. BatteryPass ignores an
`X-Request-Id` you send and always assigns its own, so log the one from the response.

```bash title="cURL"
curl -s -D - -o /dev/null "$BATTERYPASS_URL/api/v1/battery-models?limit=1" \
  -H "Authorization: Bearer $BATTERYPASS_API_KEY" | grep -i '^x-request-id'
```

```ts title="TypeScript"
const base = process.env.BATTERYPASS_URL;
const key = process.env.BATTERYPASS_API_KEY;

const res = await fetch(`${base}/api/v1/battery-models?limit=1`, {
  headers: { Authorization: `Bearer ${key}` },
});
const requestId = res.headers.get('X-Request-Id');
if (res.ok) {
  console.log(`ok request_id=${requestId}`);
} else {
  const problem = await res.json();
  console.error(`${res.status} ${problem.code} request_id=${problem.request_id ?? requestId}`);
}
```

```python title="Python"
import os

import requests

base = os.environ["BATTERYPASS_URL"]
key = os.environ["BATTERYPASS_API_KEY"]

res = requests.get(
    f"{base}/api/v1/battery-models",
    params={"limit": 1},
    headers={"Authorization": f"Bearer {key}"},
    timeout=30,
)
request_id = res.headers.get("X-Request-Id")
if res.ok:
    print(f"ok request_id={request_id}")
else:
    problem = res.json()
    print(f"{res.status_code} {problem.get('code')} request_id={problem.get('request_id', request_id)}")
```

```go title="Go"
package main

import (
	"encoding/json"
	"fmt"
	"log"
	"net/http"
	"os"
)

func main() {
	req, err := http.NewRequest(http.MethodGet, os.Getenv("BATTERYPASS_URL")+"/api/v1/battery-models?limit=1", nil)
	if err != nil {
		log.Fatal(err)
	}
	req.Header.Set("Authorization", "Bearer "+os.Getenv("BATTERYPASS_API_KEY"))
	res, err := http.DefaultClient.Do(req)
	if err != nil {
		log.Fatal(err)
	}
	defer res.Body.Close()

	requestID := res.Header.Get("X-Request-Id")
	if res.StatusCode >= 400 {
		var problem struct {
			Code string `json:"code"`
		}
		_ = json.NewDecoder(res.Body).Decode(&problem)
		log.Printf("%d %s request_id=%s", res.StatusCode, problem.Code, requestID)
		return
	}
	fmt.Println("ok request_id=" + requestID)
}
```

## What to include

1. **Identify the request**

   The `request_id`, the time in UTC, the operation (for example `updateCondition`, or method and path) and the
   HTTP status with the Problem's `code`, `detail` and `errors[]`.

2. **Identify the key and the data**

   The key's prefix (its first 12 characters, as the portal shows it) and the ids involved: battery id,
   passport UUID, version number.

3. **Describe the case**

   What you expected, what happened, and whether it happens every time or only sometimes.

> [!WARNING]
> Never send the full API key, and leave out personal data and exports that contain restricted tiers (the
> BatteryPass JSON and the PDF of a passport version). The request id and the ids are enough to find the request.

## Status of features

- The [changelog](https://passport.kabin.sh/docs/en/changelog) lists what changed in the API and in this documentation, also as an
  [RSS feed](https://passport.kabin.sh/docs/en/changelog/rss.xml).
- The published contract states its version in `info.version`; download it as [JSON](https://passport.kabin.sh/docs/openapi.json) or
  [YAML](https://passport.kabin.sh/docs/openapi.yaml).
- [`getRegistryInfo`](https://passport.kabin.sh/docs/en/api-reference/registry/get-registry-info) and
  [`getRegistryStatus`](https://passport.kabin.sh/docs/en/api-reference/registry/get-registry-status) report the field registry in use
  and how many passports need an update after a registry change.
- [`getRegistrySubmissionStatus`](https://passport.kabin.sh/docs/en/api-reference/passports/get-registry-submission-status) reports the
  EU registry state of a passport; it is `not_available` while the EU registry has no interface for economic
  operators.
