# ContactProof API V1.3.1

ContactProof applique un profil conservateur **France B2C de prospection commerciale par téléphone hors automate d’appel**. Un gate `favorable` est un contrôle technique documenté, jamais une autorisation juridique.

## Pour la majorité des clients : kit d’installation

Le chemin recommandé n’est plus de recoder cette API à la main. Dans **Espace client > Technique > Installation 5 min**, l’administrateur :

1. configure son profil métier ;
2. génère un kit personnalisé ;
3. dépose le connecteur PHP côté serveur ;
4. ouvre `contactproof-test.php` une fois ;
5. utilise les helpers `contactproof_check()`, `contactproof_event()` et `contactproof_cancel()`.

La clé API n’est jamais exposée dans le navigateur. Le kit gère les `Idempotency-Key` à partir de l’identifiant métier de la tentative.

## Test d’installation

`GET /contactproof/api/v1/installation-test.php`

```http
Authorization: Bearer ctp_...
```

Ce test valide l’authentification, le client et la connectivité sans créer de CHECK ni consommer un slot. L’événement remonte dans le CRM et le Super Admin.

## Identité fonctionnelle obligatoire

- `consumer_ref` : référence CRM stable de la **personne**, réutilisée pour tous ses numéros connus.
- `professional_ref` : référence stable du **même professionnel/personne morale bénéficiaire**, indépendamment de la marque, campagne ou call center.
- `consumer_identity_scope_confirmed=true` et `professional_identity_scope_confirmed=true` sont obligatoires.

Le plafond 4/30 est calculé par consommateur + professionnel. L’empreinte du téléphone reste utilisée pour empêcher une réintroduction silencieuse d’un numéro opposé sous un nouvel ID CRM.

## Idempotence

`Idempotency-Key` est **obligatoire** sur CHECK, EVENT et CANCEL. Une même clé rejouée avec le même payload renvoie la même opération ; la même clé avec un payload différent produit `idempotency_conflict`.

## CHECK

`POST /contactproof/api/v1/check.php`

```http
Authorization: Bearer ctp_...
Idempotency-Key: crm-123-check-1
Content-Type: application/json
```

```json
{
  "phone": "0612345678",
  "consumer_ref": "CRM-CONTACT-12345",
  "consumer_identity_scope_confirmed": true,
  "consumer_timezone": "Europe/Paris",
  "professional_ref": "SIREN-123456789",
  "professional_identity_scope_confirmed": true,
  "sector_code": "general",
  "legal_basis": "prior_consent",
  "basis_evidence_ref": "CP-...",
  "basis_scope_confirmed": true,
  "consent_received_at": "2026-09-01T10:15:00+02:00",
  "consent_valid_until": "2027-09-01T10:15:00+02:00",
  "consent_positive_action_confirmed": true,
  "consent_required_information_confirmed": true,
  "consent_not_withdrawn_confirmed": true
}
```

`sector_code` : `general`, `energy_renovation`, `home_adaptation`, `cpf`, `insurance`, `mutual_insurance`, `financial_services`.

`legal_basis` : `prior_consent`, `ongoing_contract`, `press_exception`, `consumer_information_request`, `cpf_ongoing_action`.

Un CHECK favorable crée une **réservation conservatrice** du slot de fréquence.

## EVENT

`POST /contactproof/api/v1/event.php`

```json
{
  "check_ref": "CHK-...",
  "outcome": "answered"
}
```

Outcomes : `attempted`, `answered`, `no_answer`, `callback`, `offer_declined`, `offer_accepted_pending_durable_confirmation`, `opposition`, `consent_withdrawal`, `recording_refused`, `error`.

### Rappel précis hors plage horaire

Si, pendant l'appel, le consommateur demande explicitement à être rappelé à une **date et une heure précises**, l'EVENT `callback` peut enregistrer ce rendez-vous directement dans ContactProof :

```json
{
  "check_ref": "CHK-...",
  "outcome": "callback",
  "callback_authorized_at": "2026-09-17T20:30:00+02:00",
  "callback_explicit_confirmed": true,
  "callback_evidence_ref": "CRM-RDV-8472"
}
```

Le fuseau utilisé est celui du consommateur déjà contrôlé lors du CHECK. Une référence de preuve (`callback_evidence_ref`) est requise pour créer le créneau ; le helper d’installation réutilise automatiquement le `callRef` si aucune autre référence CRM/appel n’est fournie. Si les éléments sont cohérents, l'EVENT renvoie `created_special_slot_ref`.

Au moment exact convenu, un nouveau CHECK retrouve ce rendez-vous ContactProof et peut franchir le contrôle jour/horaire. Le rendez-vous est **à usage unique** : il est réservé par ce CHECK, consommé dès la tentative enregistrée par EVENT, et libéré par CANCEL seulement si le numéro n'a finalement pas été composé. Une tentative sans réponse consomme donc le rendez-vous et compte dans le plafond 4/30.

Ce rendez-vous n'est pas stocké dans ConsentProof : ConsentProof reste la preuve du consentement préalable à la prospection issu de la collecte du lead.

## CANCEL

`POST /contactproof/api/v1/cancel.php`

À utiliser **uniquement si le numéro n’a pas été composé** afin de libérer le slot réservé par CHECK.

```json
{
  "check_ref": "CHK-...",
  "reason": "not_dialed"
}
```

## Fail-closed

Le verrou de fréquence est atomique par client + consommateur + professionnel. S’il ne peut pas être acquis, ContactProof renvoie `503 lock_unavailable` avec `retryable:true` et ne délivre jamais de gate favorable dégradé.

## Portée

Le JSON conserve `decision=allowed|blocked` pour compatibilité. `allowed` ne signifie jamais « autorisé juridiquement ». Utiliser `gate=favorable|unfavorable` et `not_a_legal_authorization=true`.
