API B2B HandiRepère

# Guide développeur — API B2B HandiRepère

## 1. Obtenir une clé

1. Connectez-vous à HandiRepère (compte ADMIN de votre organisation lieux).
2. Ouvrez l’organisation → **API / Intégrations**.
3. Créez un **client API**, puis une **clé**.
4. Copiez le secret affiché **une seule fois** (`hr_live_<préfixe>_<secret>`).

## 2. Premier appel

```http
GET /api/v1/b2b/places?q=lyon&limit=10
Authorization: Bearer hr_live_xxxxxxxx_yyyyyyyyyyyyyyyyyyyyyyyy
Accept: application/json
```

Réponse enveloppe :

```json
{
  "api_version": "2026-09-28",
  "data_generated_at": "…",
  "data": { "items": [], "next_cursor": null, "has_more": false }
}
```

## 3. Scopes

| Scope | Usage |
|-------|--------|
| `places:read` | Recherche / détail lieux |
| `territories:read` | Territoires, stats, couverture |
| `trust:read` | Faits + confiance sur détail lieu |
| `incidents:read` | Incidents actifs |
| `compatibility:evaluate` | POST évaluation compatibilité |

Sans le scope requis → **403**.

## 4. Quotas

Profils : `DEVELOPMENT`, `STANDARD`, `HIGH_VOLUME` (limites configurables côté serveur).

Dépassement → **429** + `Retry-After`.

Headers utiles : `X-RateLimit-Remaining`, `X-RateLimit-Remaining-Day`.

## 5. Lieux

- `GET /api/v1/b2b/places` — pagination **cursor** (`cursor`, `limit`, `next_cursor`)
- `GET /api/v1/b2b/places/{id}` — détail + provenance / licences sources

## 6. Trust / provenance

Les faits exposent `trust` (`CONFIRMED` | `PROBABLE` | `STALE` | `CONFLICTING` | `UNKNOWN`) **sans promotion**.

`UNKNOWN` ≠ accessible. `PROBABLE` ≠ `CONFIRMED`.

## 7. Territoires

- `GET /api/v1/b2b/territories/search?q=`
- `GET /api/v1/b2b/territories/{type}/{code}`
- `GET /api/v1/b2b/territories/{type}/{code}/stats`
- `GET /api/v1/b2b/territories/{type}/{code}/places`
- `GET /api/v1/b2b/territories/coverage?level=department|region`

### Cache (stats / coverage)

| `cache.cache_status` | Signification |
|----------------------|---------------|
| `fresh` | Entrée dans le TTL (~15 min) |
| `stale` | TTL dépassé ; payload **servi immédiatement** avec `data_generated_at` réel ; refresh asynchrone (`revalidating=true`) |
| `miss` | Aucune entrée utilisable → calcul synchrone (rare après warm) |

`data_generated_at` / `cache.generated_at` = horodatage **réel** de génération du payload (jamais réécrit pour faire croire un refresh).

### Coverage lite (B2B)

Le mode commercial est **lite** (`mode: "lite"`, `trust_metrics_available: false`) :
pas de jointure `place_fact_trust` (trop coûteuse).

| Champ | Lite | Full (interne) |
|-------|------|----------------|
| `resolved_places` | compté | compté |
| `unknown_facts` / `stale_facts` / `conflicting_facts` | **`null`** | entier (≥0) |

**Règle** : métrique non calculée ≠ `0`. Un `0` n’est autorisé que si `trust_metrics_available=true`.

Disclaimer : `coverage_reflects_handirepere_documented_places_only`.

## 8. Erreurs

| HTTP | Code typique |
|------|----------------|
| 401 | Clé absente / inconnue / révoquée / expirée |
| 403 | Scope manquant / client suspendu |
| 404 | Ressource absente |
| 429 | Quota |

## 9. Staging vs production — auth

**Production (partenaire)** : une seule en-tête

```http
Authorization: Bearer hr_live_<prefix>_<secret>
```

**Staging HandiRepère** : le reverse-proxy / edge exige **en plus** une Basic Auth
d’accès au site de préproduction (`STAGING_BASIC_AUTH_*`). C’est une **protection
d’environnement**, pas une seconde authentification B2B. Après le Basic edge, la clé
API reste Bearer (ou `X-Api-Key` si un client HTTP refuse deux schémas `Authorization`).

Le design production B2B **n’impose pas** de Basic HandiRepère aux partenaires.

## 10. Conditions de réutilisation

Respectez les `licence_identifier` / `attribution_text` des sources dans `provenance`.  
HandiRepère ne certifie pas l’accessibilité d’un établissement.

## 11. Spec OpenAPI

Voir `docs/openapi/b2b-v1.yaml`.