# Référence

Schéma complet : [openapi.json](openapi.json). Toutes les routes `/v1` exigent `Authorization: Bearer tel_…`.

| Méthode | Route | Rôle | Succès |
|---|---|---|---|
| GET | `/health` | État du service (sans clé) | 200 |
| GET | `/health/profond` | Santé détaillée pour le monitoring : base (latence) et planificateur ; 503 si KO (sans clé) | 200 |
| GET | `/v1/account` | Solde, plafonds et `avertissements` (signalements reçus sur tes appels, 90 jours : référence, motif, mission, statut `en_examen`/`avertissement`/`suspension`, message) | 200 |
| POST | `/v1/inscription` | Créer un compte (sans clé) : `email`, `mot_de_passe` (10 car. min.), `telephone` (mobile 06/07), `type` `particulier`/`pro`, `entreprise` (`raison_sociale`, `siren`, `tva`, `adresse`), `accepte_cgu_cgv` (**obligatoire**, `true` : case CGU/CGV, horodatée et versionnée ; sinon 422 `cgu_cgv_non_acceptees`), `demande_execution_immediate` (particulier : case unique « recharges utilisables immédiatement », distincte, voir « Recharges et abonnements ») → session web + envoi du code SMS | 201 |
| POST | `/v1/connexion` | E-mail + mot de passe → session web (30 jours) | 200 |
| POST | `/v1/deconnexion` | Ferme la session web courante | 200 |
| GET | `/v1/profil` | Profil (type, nom, adresse, téléphone vérifié, entreprise : raison sociale, SIRET, SIREN, TVA ; `consentement_recharges` : `requis`, `coche_le`, `version`, `texte` ; `cgu_cgv` : `requis`, `version`, `texte`, `acceptees_le`) | 200 |
| POST | `/v1/profil/cgu-cgv` | Compte existant (créé avant le 03/11/2026, ou nouvelle version des conditions) : `{"accepte_cgu_cgv": true, "version": "2026-11-03"}` ; horodatée, versionnée ; 409 `version_perimee` si la version lue n'est plus en vigueur | 200 |
| PUT | `/v1/profil/facturation` | Coordonnées de facturation : `{type?, nom?, adresse?, entreprise?: {raison_sociale, siret?, siren?, tva?, adresse?}}` (factures déjà émises inchangées) | 200 |
| GET | `/v1/tableau-de-bord` | Accueil de l'espace client en un appel : solde (crédits, minutes, valeur en centimes), attente offerte, numéro offert, offres de recharge, 5 derniers appels (statut, résumé, extrait de transcription), 5 dernières factures / avoirs | 200 |
| POST | `/v1/telephone/code` | (Ré)envoyer le code SMS (3 / heure) | 200 |
| POST | `/v1/telephone/verifier` | `{"code": "123456"}` (10 min, 5 essais) | 200 |
| GET | `/v1/liste-noire` | Numéros que tes agents ne doivent jamais appeler | 200 |
| POST | `/v1/liste-noire` | `{"numero": "+33…", "motif": "…"}` | 201 |
| DELETE | `/v1/liste-noire/{numero}` | Retirer un numéro de ta liste (pas une opposition) | 200 |
| GET | `/v1/factures` | Factures et avoirs du compte (numéro, type `facture`/`avoir`, date, montant, crédits, payée, facture d'origine, lien PDF) | 200 |
| GET | `/v1/factures/{numero}/pdf` | Facture ou avoir PDF | 200 |
| POST | `/v1/factures/{numero}/envoyer` | « Recevoir par e-mail » : envoie la facture ou l'avoir (PDF joint) à l'adresse du compte → `{ok, numero, email, envoye}` (`envoye: false` : en file d'attente) ; 10 envois par heure au plus (429 `trop_d_envois`) | 200 |
| GET | `/v1/voix` | Catalogue des voix (sans clé) : `id` 1-5, `nom`, `genre`, `gamme` `eco`/`premium`, `langues`, `style`, `apercus` (URL MP3 par langue) | 200 |
| GET | `/v1/reglages` | Réglages du compte : `voix_defaut`, `langue_defaut`, `nom_annonce`, `webhook_url_defaut`, `reglages_voix` (voix et conversation : classique `forme_adresse`, `expressivite`, `hesitations`, `ambiance`, `repondeur` ; avancé borné `delai_reponse` 0,7-1,5 s, `relance_silence` 4-10 s, `interruption_min` 0,3-1,0 s, `stabilite` 0,30-0,60, `similarite` 0,50-0,90, `style` 0-0,30, `vitesse` 0,90-1,10, `volume_ambiance` 0,03-0,20, `tics` 0,05-0,40 ; `null` = réglages recommandés) | 200 |
| PUT | `/v1/reglages` | Remplace les réglages ; appliqués aux missions qui ne précisent pas `voix`, `langue`, `client` (nom annoncé) ou `webhook_url` (l'identité de l'agent n'est pas touchée) | 200 |
| GET | `/v1/reglages/identite?lang=fr` | Identité de l'agent : réglages actuels, réglages recommandés, `ecarts`, `phrases` (ce que l'agent dira : ouverture, « de la part de qui », réponse « vous êtes un robot ? »), `avertissement` `{version, texte, texte_en}`, `acceptation`, `garde_fou` (voir « Identité de l'agent ») | 200 |
| PUT | `/v1/reglages/identite` | Remplace l'identité : `prenom_agent`, `ton`, `ouverture`, `de_la_part`, `presentation`, `annonce_ia_ouverture` ; un écart aux réglages recommandés exige `accepte_responsabilite: true` + `version_avertissement` (sinon 409 `acceptation_responsabilite_requise`, rien ne change) ; texte qui prétend que l'agent est humain ou le présente comme police, administration ou banque → 422 `identite_refusee` | 200 |
| GET | `/v1/cles` | Clés API actives (préfixe, nom, date) | 200 |
| POST | `/v1/cles` | Nouvelle clé API, affichée une seule fois (téléphone vérifié requis) | 201 |
| DELETE | `/v1/cles/{prefixe}` | Révoquer une clé | 200 |
| GET | `/v1/applications` | Applications connectées en OAuth (ChatGPT, Claude…) | 200 |
| DELETE | `/v1/applications/{client_id}` | Révoquer l'accès d'une application OAuth | 200 |
| POST | `/v1/missions` | Créer une mission. En-tête facultatif `Idempotency-Key` (1-64 car. : lettres, chiffres, `- _ . :`) : la même requête renvoyée avec la même clé dans les 24 h rend la mission déjà créée (200, `Idempotent-Replayed: true`) au lieu d'appeler deux fois ; même clé pour un autre numéro/mission → 409 `idempotency_key_reutilisee` | 201 |
| POST | `/v1/missions/analyse` | Langage naturel → champs de mission (`numero`, `mission`, `langue`, `voix`, `quand`, `manque`), sans lancer d'appel | 200 |
| GET | `/v1/missions` | Historique : `q` (recherche dans objectif, résumé, transcription, numéro), `statut`, `resultat`, `depuis`, `jusqu_au`, `limite` (≤ 200), `page` | 200 |
| GET | `/v1/missions/export/{fmt}` | Export (`fmt` = `csv` ou `json`) avec les mêmes filtres (CSV `;` compatible Excel, ou JSON avec transcriptions), 5 000 missions max | 200 |
| GET | `/v1/missions/{id}` | Statut et résultat ; `qualite_appel` du dernier appel fini : `delai_median_s`, `delai_pire_s` (temps de réponse ressenti de l'agent), `repondeur`, `relances_silence` | 200 |
| POST | `/v1/missions/{id}/answer` | Réponse à une question de l'agent : en cours d'appel, ou après l'appel tant que le rappel prévu n'est pas parti (voir « Question restée ouverte ») | 200 |
| POST | `/v1/missions/{id}/rappel` | Programmer un rappel d'une mission terminée (`{"quand": "2026-10-20T15:00"}`), à l'heure exacte demandée ; 409 `rappels_programmes_desactives` en mode 05 | 200 |
| POST | `/v1/missions/{id}/rappeler` | « Rappeler » : relance tout de suite, d'un clic, une mission terminée (même numéro, même mission) ; à toute heure, mêmes contrôles qu'un nouvel appel. Seul moyen de rappeler en mode 05 | 200 |
| POST | `/v1/missions/{id}/cancel` | Annuler (en cours ou planifiée) | 200 |
| POST | `/v1/missions/{id}/transfer` | « Prendre l'appel » : `{"numero": "+336…", "mode": "pont"}` — `pont` (défaut) : l'agent t'appelle et te met en relation sans coupure puis se retire ; `refer` : transfert SIP REFER (502 `transfert_impossible` si la ligne refuse) | 202 |
| GET | `/v1/compte/export` | Droit d'accès RGPD : toutes les données du compte en JSON (missions, transcriptions encore conservées, crédits, factures) | 200 |
| GET | `/v1/compte/remboursement-cloture` | Estimation du remboursement du solde si tu fermes le compte maintenant : par recharge, part non utilisée (`brut_cents`), frais déduits (`frais_cents` = `frais_paiement_cents` + `autres_frais_cents` ; toujours 0 pour un particulier), net (`rembourse_cents`), `type` du compte | 200 |
| DELETE | `/v1/compte` | Droit à l'effacement : `{"confirmation": "SUPPRIMER MON COMPTE", "rembourser_solde": true}` — supprime missions, transcriptions et clés, anonymise le compte (factures gardées 10 ans) ; rembourse le crédit de recharges non utilisé (`remboursement_solde`, voir « Clôture et remboursement du solde ») sauf `rembourser_solde: false` ; 409 si un appel est en cours | 200 |
| GET | `/v1/missions/{id}/direct?apres=<id>` | Suivi en direct : statut, question ouverte, événements depuis le curseur `apres` (transcription ligne à ligne, décroché, attente, question, transfert, fin) | 200 |
| POST | `/v1/signalements` | Signaler un appel abusif (public, sans clé) : `{numero_appele?, reference?, motif, description, contact?, ne_plus_etre_appele?}` ; `motif` = `fraude`, `usurpation`, `menace`, `harcelement`, `demarchage`, `opposition_ignoree`, `autre` → `{reference: "sig_…"}`. Le numéro signalant ne peut plus être appelé par ce client, qui reçoit un avertissement ; examen humain sous 24 h ouvrées (voir « Signalements ») | 201 |
| GET | `/v1/retractation` | « Renoncer au contrat ici » : recharges encore rétractables (14 jours, achetées en tant que particulier) avec la part non consommée remboursable | 200 |
| POST | `/v1/retractation` | `{"recharge_id": 12}` : rétractation — crédits non consommés retirés, part non consommée remboursée intégralement, avoir, accusé de réception par e-mail | 200 |
| POST | `/v1/abonnement/retractation` | Rétractation de l'abonnement d'un particulier (14 jours après le 1er paiement ; `GET /v1/retractation` → `abonnement` donne la date limite et le montant) : arrêt immédiat, minutes restantes retirées, remboursement **intégral** si la case d'exécution immédiate n'a pas été cochée, sinon part non consommée ; avoir, accusé de réception | 200 |
| GET | `/v1/missions/{id}/direct/flux` | Le même suivi en flux SSE (`text/event-stream`) : un événement par ligne, `event: fin` à la fin de la mission | 200 |
| GET | `/v1/offres` | Grille publique des 3 offres (`particulier`, `pro`, `entreprise`), identique à `GET /v1/tarifs` → `offres` (sans clé). Entreprise : `sur_devis: true`, prix `null` | 200 |
| GET | `/v1/offre` | Offre du compte : `offre`, `limites`, `usage` (appels en cours, appels sur 24 h glissantes), `fonctions`, `contrat` (Entreprise), souscription Pro — voir [offres.md](offres.md) | 200 |
| POST | `/v1/offre/pro/checkout` | Passer au Pro (99 €/mois, paiement Stripe en mode abonnement) ; propriétaire seulement ; 422 `compte_pro_requis` sans raison sociale, 409 `deja_pro`, 503 `paiement_indisponible` | 200 |
| POST | `/v1/offre/pro/resilier` | Résilier le Pro : effectif à la fin de la période payée ; propriétaire seulement | 200 |
| GET | `/v1/essai` | État de l'essai de 5 minutes (voir [offres.md](offres.md#essai-de-5-minutes)) | 200 |
| GET | `/v1/equipe` | Membres, rôles, invitations en cours, places restantes (Pro : 5 membres, propriétaire compris) | 200 |
| POST | `/v1/equipe/membres` | Inviter `{email, role}` (`admin` ou `membre`) → lien d'invitation valable 7 jours ; 409 `trop_de_membres`, 409 `email_deja_compte` | 201 |
| PATCH | `/v1/equipe/membres/{membre_id}` | Changer le rôle `{role}` (propriétaire ; un admin gère les membres) | 200 |
| DELETE | `/v1/equipe/membres/{membre_id}` | Retirer un membre (ses sessions sont fermées) | 200 |
| POST | `/v1/equipe/rejoindre` | Accepter une invitation (sans clé) : `{jeton, mot_de_passe, nom?}` → session ; 409 `invitation_invalide` | 200 |
| POST | `/v1/lots` | Appels en lot (Pro, Entreprise) : une mission, jusqu'à 100 numéros — voir [lots.md](lots.md) | 201 |
| GET | `/v1/lots` | Lots du compte | 200 |
| GET | `/v1/lots/{lot_id}` | Avancement d'un lot et ses appels | 200 |
| POST | `/v1/lots/{lot_id}/cancel` | Annule les appels du lot pas encore lancés | 200 |
| GET | `/v1/factures/export.csv` | Export comptable CSV (`depuis`, `jusqu_au`) ; Pro et Entreprise, propriétaire ou admin | 200 |
| GET | `/v1/numeros` | Numéros du compte (lecture seule) | 200 |
| POST | `/v1/missions/{id}/question/prolonger` | Demande 60 s de plus pour répondre à la question en cours ; l'agent vocal demande d'abord l'accord de l'interlocuteur (une seule fois par question) — voir [questions.md](questions.md) | 200 |
| GET | `/v1/demo/config` | Démo live du site (public, sans clé) : mode (`live`, `simulation`, `indisponible` + `raison`), durée maximale (120 s), places libres, captcha, voix, suggestions, tons, réglages | 200 |
| POST | `/v1/demo/session` | Démo live du site (public, sans clé) : ouvre une session (jeton LiveKit éphémère, 120 s au plus, + `cle` de session) ou refus motivé (`indisponible`, `limite`, `budget`) | 200 |
| POST | `/v1/demo/session/{session_id}/reglages` | Démo live du site : change le ton et les réglages de voix pendant l'appel (`cle` de la session ; mêmes bornes que `reglages_voix`, 422 sinon) | 200 |

## Erreurs
Corps : `{"detail": "…"}`.

| Code | `detail` | Cause |
|---|---|---|
| 401 | `Clé API invalide` | Clé absente, fausse ou révoquée |
| 402 | `credits_insuffisants` | Solde à 0 (les crédits réservés par les appels en cours ne sont pas disponibles) |
| 404 | `Mission inconnue` | Id inexistant ou d'un autre compte |
| 409 | `Mission non en cours (…)` | Annulation/transfert sur une mission terminée ; réponse sans question ouverte, à une question déjà répondue ou expirée |
| 422 | message de validation | Numéro non E.164 FR, mission hors 10–2000 caractères, `webhook_url` non HTTPS public, `annonce_ia_confirmation_requise` |
| 429 | `trop_d_appels_simultanes` / `plafond_journalier_atteint` | Limites de l'offre : Particulier 1 appel à la fois et 20 par 24 h glissantes, Pro 5 et 300 ; en-tête `Retry-After`. Toutes les erreurs de limite et d'offre : [offres.md](offres.md#codes-d-erreur) |

## Anti-abus
Contrôlé à la création de chaque mission, avant toute réservation de crédits :
| Code | `detail` | Cause |
|---|---|---|
| 422 | `numero_surtaxe` | Numéros surtaxés 081, 082, 088, 089 (les numéros gratuits 0800-0805 sont autorisés) |
| 422 | `numero_du_service` | Un de nos propres numéros (boucle) |
| 403 | `numero_bloque` | Liste noire de ton compte, numéro qui a signalé un de tes appels (pour ton compte), ou opposition : la personne a demandé à ne plus être appelée (définitif, tous clients) |
| 422 | `mission_interdite : …` | Refus légaux : menace ou harcèlement, usurpation de l'identité d'un tiers ou d'une autorité (police, banque…), démarchage ou appels en masse. Refus anti-fraude (02/11/2026) : fausse qualité d'autorité ou de banque ; demander au correspondant ses codes, mots de passe ou données de carte ; lui demander un virement, un paiement, des cartes cadeaux ou des cryptos (réclamer une somme qui t'est due reste permis) ; dicter un code de paiement ou une carte complète avec son cryptogramme |
| 403 | `compte_suspendu` | Compte suspendu (fraude détectée sur un appel signalé, signalements répétés ou décision du support) : plus d'appel ni de paiement jusqu'à la levée par le support |
| 429 | `mission_en_double` | Même numéro moins de 2 min après une autre mission de ton compte |
| 429 | `numero_trop_sollicite` | Plus de 3 missions / 24 h vers ce numéro depuis ton compte, ou 5 tous clients confondus |
Les numéros d'urgence (15, 17, 18, 112, 114, 115, 119, 196, 197) ne sont jamais composables (format +33 à 9 chiffres obligatoire).
Pendant l'appel, si l'interlocuteur demande à ne plus être appelé (ou refuse la transcription), l'agent met fin poliment à
l'appel : le numéro passe en opposition (tous clients), la transcription est supprimée, `resultat` = `opposition`
(webhook `appel.fin` avec `opposition: true`) et tu reçois un e-mail.
Codes et données de carte (politique du 31/10/2026) : c'est toi qui décides. Un code de vérification, un mot de passe
ou un numéro de carte dans la mission ou dans une réponse (`/answer`) est transmis par l'agent. Écris la valeur
`[secret: 482913]` : l'agent dit la valeur, et nous ne gardons qu'un repère masqué (`[secret masqué #1]`) dans la
mission, la transcription, le résumé, les événements et les webhooks ; les numéros de carte (Luhn) sont masqués
d'office (`[carte masquée #2 …0366]`). Les valeurs sont gardées chiffrées le temps de la mission (relances, rappel promis), puis effacées. Une réponse (`/answer`) est
refusée (`422 reponse_interdite`) pour les mêmes motifs que la mission.
Carte bancaire : le numéro et la date d'expiration passent ; le cryptogramme jamais (mission avec la VALEUR du
cryptogramme → `mission_interdite`, réponse à une question sur le cryptogramme → `reponse_interdite`). Citer le mot
(« s'ils demandent le cryptogramme, je paierai moi-même ») ne bloque rien. Si le commerçant exige le cryptogramme,
l'agent dit que tu finaliseras le paiement toi-même et poursuit la mission.

## Signalements
- Toute personne appelée peut signaler un appel (`POST /v1/signalements`, `/app/#/signaler`). Effets immédiats : son
  numéro ne peut plus être appelé depuis ton compte (`numero_bloque`), tu reçois un avertissement (e-mail et
  `GET /v1/account` → `avertissements`) qui rappelle la règle, et le signalement est examiné par une personne sous
  24 h ouvrées. « Ne plus être appelé » coché : opposition pour tous les clients.
- Suspension automatique seulement si nos filtres anti-fraude ont détecté une fraude sur le même appel (réponse
  refusée pour fraude, tâche refusée par le filtre), ou si 3 numéros différents signalent ton compte en 7 jours.
  Sinon, un premier écart vaut avertissement ; l'examen humain peut conclure à un avertissement, une suspension ou
  un rejet.
- Motifs graves (examinés en priorité) : arnaque ou fraude, usurpation d'identité, menaces, harcèlement, appels répétés
  après une opposition.
- **Deux signalements indépendants en 24 h** (deux numéros appelés différents ; le même numéro qui signale deux fois
  compte pour un) encore en attente d'examen : ton compte ne peut plus appeler de **nouveaux** numéros jusqu'à
  l'examen (403 `restriction_nouveaux_numeros` ; appels planifiés vers un nouveau numéro annulés sans frais). Les
  numéros déjà appelés restent possibles. Tu es prévenu par e-mail et dans `GET /v1/account` → `restriction` ; la
  limite est levée dès que plus aucun signalement n'attend d'examen.

## Identité de l'agent
- **Réglages recommandés (par défaut)** : « Bonjour, ici Léa, l'assistante virtuelle de [nom annoncé]. Je vous appelle
  pour… » ; si on demande de la part de qui : « J'appelle de la part de [nom annoncé]. » ; si on demande si c'est un
  robot ou une IA : oui. Le prénom par défaut est celui de la voix (Solène, Gaspard…, accord au masculin pour une voix
  d'homme) ; le nom annoncé est `client` de la mission, sinon le réglage `nom_annonce`, sinon la raison sociale d'un
  compte pro (sinon « une assistante virtuelle », « de la part d'un client »).
- **Personnalisation** (`PUT /v1/reglages/identite`, écran « Voix et réglages » de `/app/`, outil MCP
  `configure_agent_identity`) : prénom et ton librement ; formulation de l'ouverture, réponse « de la part de qui »,
  présentation et mention de l'IA dans l'ouverture = **écarts** aux réglages recommandés. Un écart exige d'accepter
  l'avertissement (`accepte_responsabilite: true`, `version_avertissement`) : ces réglages relèvent alors de ta
  responsabilité (CGU 6.4, CGV 15.7). Acceptation journalisée (horodatage, version, réglages, IP, canal). Les textes
  sont dits tels quels (variables `{prenom}`, `{operateur}`) : écris-les dans la langue de tes appels.
- **Seul garde-fou non modifiable** : l'agent ne nie jamais être une IA quand on le lui demande (AI Act art. 50). Un
  texte qui le ferait passer pour un humain, ou pour la police, une administration ou une banque, est refusé (422).
- L'identité est figée sur la mission à sa création (un rappel garde la même) ; retrait de la mention IA tracé à chaque
  lancement (`annonce_ia_desactivee`, origine `identite`).

## Annonce IA (mission par mission)
- Par défaut (`annonce_ia: "standard"`), l'agent dit dès l'ouverture qu'il est une assistante virtuelle (réglages
  d'identité ci-dessus ; AI Act art. 50, applicable depuis le 02/08/2026). L'`accroche` éventuelle vient après.
- `annonce_ia: "interlocuteur_deja_informe"` retire cette mention de l'accroche, UNIQUEMENT si la personne appelée sait
  déjà qu'elle parlera à une IA (par exemple un proche que tu as prévenu) : exception de l'art. 50(1) « sauf si
  c'est évident vu le contexte ». Déconseillé dans les autres cas. `annonce_ia_confirmation` (10-300 caractères) est
  obligatoire : qui est la personne et comment elle a été prévenue ; sans elle → 422 `annonce_ia_confirmation_requise`
  (`annonce_ia: false` est aussi refusé).
- Même alors, l'agent ne nie jamais être une IA, répond la vérité si on le lui demande, et s'annonce comme assistant
  vocal automatique si quelqu'un d'autre décroche. Chaque retrait est journalisé (`ANNONCE_IA_DESACTIVEE` : ta
  confirmation, horodatage, compte, mission), au lancement de chaque tentative et en fin d'appel.

## Crédits
- 100 crédits = 1 minute ; débit à la seconde, arrondi au crédit supérieur (1 crédit = 0,6 s).
- Au lancement de chaque tentative, nous réservons min(solde, 6000) crédits (60 min) ; la durée maximale de
  l'appel est limitée à ce que couvre la réservation. En fin d'appel, la réservation est rendue et seules les
  secondes de conversation sont débitées.
- Gratuit : occupé, non décroché, échec de lancement de notre côté.
- Plafonds techniques par appel : 60 min de conversation, 2 h d'attente.
- **Crédits sans expiration** : les crédits d'une recharge n'expirent jamais. Les minutes d'un abonnement restent
  utilisables pendant leur mois et le mois suivant (report d'un mois) et sont **consommées en premier** (les plus
  anciennes d'abord) ; les crédits sans expiration ne sont touchés qu'ensuite. Une réservation annulée ou rendue
  revient aux lots d'où elle venait.
  `GET /v1/account` donne le détail : `credits` (total utilisable), `credits_sans_expiration`,
  `credits_abonnement`, `credits_abonnement_expirent_le` (ISO 8601 UTC, ou `null`).

## Tarifs
Grille complète et lisible par machine : `GET /v1/tarifs` (public).
- **Offres** (détail : [offres.md](offres.md)) : Particulier 0 €/mois, Pro 99 €/mois, Entreprise sur devis. La qualité
  est la même partout ; le Pro ajoute de la capacité et des outils d'équipe.
- **Minute parlée : 0,20 €** en Particulier (100 crédits, 1 crédit = 0,002 €), **0,17 €** en Pro (85 crédits),
  négociée en Entreprise ; décomptée à la seconde. Franchise de TVA (art. 293 B du CGI) : le prix payé est le prix HT.
- **Essai** : 5 minutes offertes une fois, après la vérification du téléphone (voir [offres.md](offres.md#essai-de-5-minutes)).
- **Recharges** (paiement unique, crédit sans expiration, pour toutes les offres) : 10 € = 50 min · 20 € = 100 min ·
  50 € = 250 min · 100 € = 500 min en Particulier (en Pro, le même crédit donne plus de minutes : 10 € ≈ 58 min ;
  `GET /v1/tarifs` → `recharges[].minutes_par_offre`). Chaque recharge ajoute aussi un quota d'attente offert, sans expiration : 30 min · 1 h · 3 h · 8 h.
- **Abonnement mensuel de minutes** aux mêmes montants (`abo-10`, `abo-20`, `abo-50`, `abo-100`) : mêmes minutes et
  même quota d'attente chaque mois, minutes non utilisées reportées d'un mois. Indépendant de l'offre Pro (dont les
  99 €/mois ne contiennent pas de minutes).
- **Attente** (musique, file d'attente ; l'IA est en veille) : consommée d'abord sur le quota du mois d'abonnement,
  puis sur le quota des recharges, puis facturée **0,04 €/min** (20 crédits/min). `GET /v1/abonnement` donne
  `attente_offerte_restante_min`.
- **Numéro dédié offert** tant que le compte est actif (crédit restant ou abonnement en cours), sans frais mensuels.
  Compte inactif (crédit à zéro, sans abonnement) → numéro en **veille 60 jours** (conservé, une recharge le
  réactive), puis libéré après un préavis par e-mail envoyé au moins 7 jours avant. État dans `GET /v1/abonnement` →
  `ligne` (`aucune`, `active`, `veille`, `liberee`).
- **Royaume-Uni** (ouverture prévue au 1er trimestre 2027) : 0,15 £/min HT (0,18 £ TTC pour les particuliers), annoncé
  dans `GET /v1/tarifs` → `international` (non disponible pour l'instant).

## Horaires et relances
- Décision du 03/11/2026 : **aucune plage horaire imposée** aux appels que tu demandes, de jour comme de nuit, tous les
  jours : tout de suite, à la date `quand`, d'un clic (`/rappeler`) ou à l'heure exacte d'un rappel programmé (`/rappel`).
  Les anciens champs `planifier` et `hors_horaires` sont acceptés et ignorés. Les numéros surtaxés, l'opposition et les
  limites anti-abus s'appliquent toujours.
> **Fonctionnement actuel de la ligne** (`RAPPELS_MODE=notification`, tant que nos appels partent d'un numéro en 05) :
> **aucune relance automatique et aucun rappel programmé**. Un appel occupé, non décroché ou qui se termine sur une
> demande de rappel donne l'événement `rappel_suggere` (webhook `appel.rappel_suggere` : `motif`, `tentative`,
> `suggere_le` si l'interlocuteur a donné une heure, `question_ouverte` s'il restait une question) ; tu relances d'un
> clic avec `POST /v1/missions/{id}/rappeler`, et l'agent reprend avec le contexte de l'appel précédent.
> `POST /v1/missions/{id}/rappel` répond alors 409 `rappels_programmes_desactives`. Les règles ci-dessous
> s'appliquent au mode automatique (`RAPPELS_MODE=auto`), qui n'est pas activé aujourd'hui.

- Relances AUTOMATIQUES (mode `auto` seulement : occupé / non décroché, créneau de rappel proposé par l'agent, rappel
  faute de réponse de ta part) : seulement de 8 h à 21 h à l'heure de la personne appelée (heure de Paris pour un +33), dimanches et jours
  fériés compris ; relance à +15 min (repoussée au prochain créneau si besoin), 2 tentatives au total, webhook
  `appel.rappel`.
- Rappel à une heure **donnée par l'interlocuteur lui-même** (« rappelez-moi à 22 h ») : respecté tel quel, même hors
  8 h–21 h (c'est son choix ; décision du 03/11/2026).

## Statuts
| `statut` | Sens |
|---|---|
| `planifiee` | En attente de son créneau |
| `en_cours` | Appel lancé |
| `relance_planifiee` | Occupé / non décroché, nouvelle tentative prévue |
| `terminee` | Fini : voir `resultat` |
| `annulee` | Annulée par toi |
| `erreur` | Non lancé (`erreur_infrastructure` ou `credits_insuffisants`), non facturé |

| `resultat` | Sens |
|---|---|
| `reussi` | Objectif atteint |
| `echec` | Réponse négative ou objectif impossible |
| `repondeur` | Messagerie (message laissé si la mission le permet) |
| `pas_de_reponse` | Non décroché |
| `occupe` | Ligne occupée |
| `rappel_demande` | L'interlocuteur demande un rappel, ou question restée sans réponse ; si une heure est donnée (« rappelez à 15 h »), le rappel est programmé automatiquement |

## Rappels programmés
- **Demandés par l'interlocuteur** (« rappelez après 15 h ») : l'agent note l'heure, la mission passe en `relance_planifiee`
  et le webhook `appel.rappel` (`motif: "rappel_demande"`) donne `prevu_le`. Sans heure précise : mission `terminee`.
- **Question restée ouverte** : si l'appel se termine pendant que l'agent attend ta réponse, il convient d'un rappel
  avec l'interlocuteur (`relance_planifiee`, webhook `appel.rappel` avec `question_ouverte` `{question_id, question}` ;
  `question` de la mission garde `{id, texte, apres_appel: true}`). Réponds quand même avec `POST /v1/missions/{id}/answer` :
  la réponse est stockée (200, `apres_appel: true`, `rappel_prevu_le`) et l'agent la transmet dès le début du rappel. Renvoyer
  la même réponse est sans effet (`deja_recue: true`) ; une autre réponse → 409. Sans réponse, le rappel a lieu quand même et
  l'agent te repose la question en direct (annule avec `/cancel` si tu préfères). La question expire quand le rappel part,
  si la mission est annulée, ou si aucun rappel n'a pu être programmé (quota, 14 jours) : 409.
- **Demandés par toi** : `POST /v1/missions/{id}/rappel` sur une mission `terminee` (même numéro, même script).
- Règles : heure sans fuseau = heure de Paris ; demandé par toi : heure respectée telle quelle (aucune plage imposée) ;
  heure donnée par l'interlocuteur lui-même : respectée telle quelle ; créneau proposé par l'agent : dans la plage
  8 h-21 h (heure de l'appelé) ; au plus 14 jours à l'avance ;
  3 rappels programmés maximum par mission ; lancement au plus 15 s après l'heure prévue. Annulable avec `/cancel`.

## Rappels entrants
Si l'interlocuteur rappelle le numéro qui l'a appelé, l'agent décroche et **reprend la mission la plus récente vers ce numéro**
(7 jours max, mission `terminee` ou `relance_planifiee` — une relance prévue est alors annulée). La mission repasse `en_cours`
(webhook `appel.entrant`), le temps actif est facturé comme un appel sortant et le résultat arrive par `appel.fin`.
Sans mission correspondante, l'agent se présente et prend un message.

## Suivi en direct
- Chaque phrase de l'agent et de l'interlocuteur arrive quelques centaines de millisecondes après avoir été dite
  (`type: "transcription"`, `data: {"role": "agent" | "interlocuteur", "texte": "…"}`).
- Polling : rappelle `/direct?apres=<dernier id reçu>` toutes les 1-2 s. Flux : `/direct/flux` (SSE, lecture avec
  `fetch` + en-tête `Authorization`, ou `curl -N`). Le flux se ferme sur `event: fin` (statut, résultat, résumé).
- Les lignes de transcription ne déclenchent pas de webhook (trop fréquentes) ; la transcription complète reste dans
  `GET /v1/missions/{id}` et `appel.fin`.
- **Prendre l'appel** : `POST /transfer` avec ton numéro. Mode `pont` (défaut) : l'agent prévient l'interlocuteur
  (qui entend la tonalité), t'appelle, dit « vous êtes en ligne avec votre correspondant, au sujet de … », puis se
  tait ; l'appel se termine quand l'un de vous deux raccroche. Pendant une attente, il n'y a pas d'annonce : tu attends
  à la place de l'agent. Si tu ne décroches pas sous 30 s, l'agent reprend la conversation. Événements `transfert`
  (`etat` : `demande`, `sonnerie`, `connecte`, `echec`) dans `/direct` et webhook `appel.transfert`. Mode `refer` :
  transfert SIP REFER (l'appel quitte la plateforme). Interface web : `/app/` (bouton « Prendre l'appel ») ; MCP :
  outil `transfer_call_to_user`.

## Interface web
- `/app/` : connexion par clé API (gardée dans l'onglet), **nouvelle mission en langage naturel** (« Appelle le
  garage Dupont au 01 42 00 00 00 demain à 15h pour décaler ma révision » → numéro, date, langue, voix et mission
  pré-remplis et modifiables), puis **suivi en direct** (transcription, attente, question à laquelle répondre,
  « Prendre l'appel », raccrocher).
- L'analyse (`/v1/missions/analyse`) est déterministe : numéros FR (`01 42…`, `+33 6…`, `06.12…`), jours
  (aujourd'hui, demain, après-demain, lundi…), heures (`15h`, `10h30`), langue (« en anglais »), voix (« voix 5 »).

## Comptes
- Inscription en libre-service sur `/app/` ou `POST /v1/inscription`. Le **téléphone doit être vérifié** (code SMS)
  avant de lancer un appel (`403 telephone_non_verifie`) ou de créer une clé API. Comptes créés par nos soins : dispensés.
- Compte **pro** : raison sociale obligatoire ; SIRET, SIREN et TVA intracommunautaire facultatifs mais contrôlés s'ils
  sont fournis (clé de Luhn, SIRET ⊃ SIREN, TVA FR ↔ SIREN) ; adresse de facturation — reprises sur les factures.
  Modifiables ensuite par `PUT /v1/profil/facturation`.
- Particulier : une case expresse, distincte des CGU/CGV, cochée une fois à l'inscription (`demande_execution_immediate`)
  ou, à défaut, à la première recharge : « Je demande que mes recharges soient utilisables immédiatement et je reconnais
  perdre mon droit de rétractation sur les minutes que j'aurai consommées. » Horodatée, versionnée, IP conservée,
  confirmée par e-mail ; `GET /v1/profil` → `consentement_recharges`.
- Limites selon l'offre (Particulier : 1 appel à la fois, 20 par 24 h glissantes ; Pro : 5 et 300 ; Entreprise : négociées) : voir [offres.md](offres.md).
- Mots de passe hashés (scrypt) ; codes SMS hashés ; une session web est une clé `tel_…` qui expire au bout de 30 jours.

## Factures
- Présentation personnalisable depuis l'administration (logo, couleur, nom commercial, coordonnées en plus, mentions
  libres, pied de page, préfixe de numérotation) : les mentions obligatoires restent toujours imprimées, chaque facture
  garde la présentation de son émission, et le préfixe ne remet jamais le compteur à zéro (`VOC-F2026-000043` suit
  `F2026-000042`).
- Une facture par achat (recharge, abonnement), numérotation continue par année (`F2026-000001`…), PDF
  téléchargeable. Un remboursement donne un **avoir** (série continue `A2026-000001`…) qui cite la facture d'origine ;
  les crédits correspondants sont retirés au prorata. Montants HT = TTC : « TVA non applicable, art. 293 B du CGI » (franchise en base).
- Mentions : vendeur complet, client (SIREN + TVA intracommunautaire pour les pros), désignation, quantité, prix
  unitaire, totaux, date de la prestation, catégorie (prestation de services), acquittement, pénalités de retard
  et indemnité de 40 € pour les pros. Une facture émise n'est jamais modifiée (droits base en lecture/insertion seules).

## Voix et réglages
- `GET /v1/voix` est public : il sert l'écran « Voix et réglages » et permet à un agent de choisir une voix. Chaque voix a un
  aperçu MP3 en français et en anglais (`apercus.fr`, `apercus.en`). Voix 1-4 : gamme éco (ElevenLabs) ; voix 5 : premium (ElevenLabs).
- `PUT /v1/reglages` : `voix_defaut` inconnue ou `langue_defaut` hors `fr`/`en`/`auto` → 422 ; `reglages_voix` hors bornes ou hors pas (ex. `delai_reponse` 1,05) → 422 ; `webhook_url_defaut` non HTTPS public → 422.
- Ordre de priorité à la création d'une mission : valeur de la mission, sinon réglage du compte, sinon voix 1 / français.
  `nom_annonce` est ajouté comme `client` (« … pour le compte de <nom> ») quand la mission n'en donne pas.


## Données personnelles (RGPD)
- Aucun audio n'est enregistré. Les **transcriptions** (et résumés, questions) sont effacées automatiquement après
  `conservation_jours` (réglage `PUT /v1/reglages`, 90 par défaut ; 1 à 90 en Particulier, 1 à 365 en Pro, négocié
  en Entreprise) ; durées, crédits et factures
  restent. Après clôture du compte, l'identité minimale (nom, e-mail, téléphone vérifié) est gardée 5 ans à part, comme
  les preuves de consentement (CGU/CGV, cases d'exécution immédiate, acceptation des réglages d'identité).
- Export : `GET /v1/compte/export`. Effacement : `DELETE /v1/compte`.

## Clôture et remboursement du solde
- À la clôture (`DELETE /v1/compte`), le crédit de recharges acheté et non utilisé est remboursé sur le moyen de
  paiement d'origine, sous 30 jours, sauf `rembourser_solde: false`. Estimation : `GET /v1/compte/remboursement-cloture`.
- Particulier : les minutes restantes de chaque recharge sont remboursées **entièrement, sans aucun frais** (une recharge
  encore dans son délai de 14 jours est traitée comme une rétractation, C. conso. L221-24).
- Pro : part non utilisée de chaque recharge, moins les frais de paiement non récupérables de la recharge d'origine
  (montant réellement facturé par Stripe quand il est connu, sinon 1,5 % + 0,25 €, tarif carte UE) et d'éventuels
  autres frais non récupérables ; jamais négatif. Le type retenu est celui du compte au moment de l'achat.
- Minutes d'abonnement, attente offerte et crédits gratuits ou promotionnels : non remboursables. Un avoir est émis
  (pro : ligne « Frais de paiement non remboursables ») et un récapitulatif envoyé par e-mail.

## Recharges et abonnements
- `GET /v1/tarifs` (public) : grille complète (minute, recharges, abonnements, attente hors quota, numéro offert, tarif UK annoncé).
- `GET /v1/abonnement/offres` (public) : `offres` (abonnements : prix, `minutes_incluses`, `credits_mensuels`,
  `attente_incluse_min`) et `recharges` ; `paiement_disponible`.
- `POST /v1/recharge/checkout` `{offre, demande_execution_immediate?}` (`recharge-10`, `recharge-20`, `recharge-50`,
  `recharge-100`) → `{url, recharge, consentement}` : page de paiement sécurisée (Stripe Checkout). Chaque recharge est
  un contrat distinct. Particulier : la case unique (voir « Comptes ») doit avoir été cochée une fois ; sinon, la cocher
  ici avec `demande_execution_immediate: true` (une seule fois, 422 `consentement_requis` sans elle). Elle est recopiée
  sur chaque recharge et rappelée dans la confirmation envoyée par e-mail. L'ancien format
  `{execution_immediate: true, perte_retractation: true}` reste accepté (pour cette recharge seulement). Pro : aucune
  case. Une fois payée : crédits sans
  expiration, quota d'attente, numéro activé (offert) et facture. 404 `offre_inconnue`, 503
  `paiement_indisponible`, 503 `facturation_indisponible` (paiements réels sans SIRET configuré), 403 `compte_suspendu`.
- `POST /v1/abonnement/checkout` `{offre, demande_execution_immediate?}` (`abo-10` … `abo-100`) → `{url,
  execution_immediate?}`. Particulier : case « Je demande que mon abonnement commence immédiatement (minutes utilisables
  dès le paiement) et je reconnais perdre mon droit de rétractation sur les minutes que j'aurai consommées. »
  (horodatée, versionnée, IP ; distincte des CGU/CGV). Cochée : rétractation possible 14 jours, part non consommée
  remboursée. Non cochée : rétractation possible 14 jours avec remboursement **intégral**, sans aucune somme due. Le
  contrat est conclu au 1er paiement (confirmation par e-mail avec la date limite). 409 `deja_abonne`, 404
  `offre_inconnue`, 503 `paiement_indisponible`.
- `GET /v1/abonnement` : offre, statut (`en_attente`, `actif`, `impaye`, `resilie`, `expire`), période en cours, attente
  utilisée / incluse, quota d'attente des recharges restant, état de la ligne, crédits (abonnement / sans expiration).
- `POST /v1/abonnement/portail` → `{url}` (moyen de paiement, factures) ; `POST /v1/abonnement/resilier` : résiliation
  en ligne, effective à la fin de la période, accusé de réception par e-mail (une 2e demande renvoie `deja_demandee`).
- Rétractation : `GET /v1/retractation` puis `POST /v1/retractation` `{recharge_id}` (recharges) ou
  `POST /v1/abonnement/retractation` (abonnement d'un particulier) — voir le tableau des routes.
- Renouvellement : à chaque échéance payée, les minutes du mois sont créditées (utilisables jusqu'à la fin du mois
  suivant) ; le quota d'attente du mois repart à zéro ; une facture est émise. À la fin d'un abonnement, le numéro
  reste offert tant qu'il reste du crédit.
