{
  "openapi": "3.0.3",
  "info": {
    "title": "API Adralis",
    "version": "0.1",
    "description": "Normalisation des adresses postales françaises selon la norme AFNOR NF Z10-011, à partir de la Base Adresse Nationale et de la base officielle des codes postaux.\n\nLe guide d'intégration (démarrage, lecture des réponses, erreurs et limites) est en haut de cette page. Ci-dessous, la référence complète de chaque route ; le bouton **Try it out** envoie de vrais appels.",
    "contact": {
      "name": "Nubelo",
      "email": "contact@nubelo.fr"
    }
  },
  "servers": [
    {
      "url": "/",
      "description": "Ce serveur"
    }
  ],
  "tags": [
    {
      "name": "Normalisation",
      "description": "Vérifier, corriger et remettre aux normes une ou plusieurs adresses."
    },
    {
      "name": "Saisie assistée",
      "description": "Proposer communes et voies pendant la frappe, pour une adresse juste dès la saisie (sans clé, sans crédits)."
    },
    {
      "name": "Informations",
      "description": "Codes retour, référentiel chargé, état du service."
    }
  ],
  "components": {
    "securitySchemes": {
      "cleApi": {
        "type": "apiKey",
        "in": "header",
        "name": "X-API-Key",
        "description": "Clé fournie par Nubelo (contact@nubelo.fr). Facultative pour l'essai (une adresse à la fois, limité) ; obligatoire pour les lots."
      }
    },
    "schemas": {
      "AdresseIn": {
        "type": "object",
        "description": "Une adresse, en lignes **ou** en texte libre. Taille totale : 2 000 caractères au plus.",
        "properties": {
          "lignes": {
            "type": "array",
            "maxItems": 7,
            "items": {
              "type": "string"
            },
            "description": "Les 7 lignes de la norme AFNOR NF Z10-011 : 1 civilité et nom, 2 appartement, étage, 3 bâtiment, résidence, 4 numéro et voie, 5 lieu-dit, boîte postale, 6 code postal et localité, 7 pays. Les lignes vides peuvent être omises en fin de tableau. Une ligne mal placée est remise à sa place."
          },
          "adresse": {
            "type": "string",
            "description": "Adresse en texte libre, d'un seul tenant (prioritaire sur `lignes`). Les virgules aident au découpage mais ne sont pas obligatoires."
          },
          "ref": {
            "type": "string",
            "description": "Identifiant libre (numéro de client, de commande…), renvoyé tel quel dans le résultat."
          }
        },
        "example": {
          "ref": "client-1042",
          "lignes": [
            "",
            "",
            "",
            "15 QUAI DES CHARTRONS",
            "",
            "33000 BORDEAUX",
            ""
          ]
        }
      },
      "Code": {
        "type": "object",
        "description": "Un code retour : ce qui a été constaté ou modifié, et sur quelle ligne.",
        "properties": {
          "code": {
            "type": "string",
            "example": "CP_COMPLETE",
            "description": "Identifiant stable, à utiliser dans vos traitements (liste : `GET /v1/adresses/codes`)."
          },
          "ligne": {
            "type": "integer",
            "description": "Ligne concernée, 1 à 7 ; 0 = l'adresse entière."
          },
          "libelle": {
            "type": "string",
            "example": "Code postal complété : 33000",
            "description": "Texte lisible, suivi de la modification effectuée quand il en décrit une. Peut évoluer : ne pas s'en servir comme clé."
          },
          "gravite": {
            "type": "string",
            "enum": [
              "info",
              "correction",
              "alerte",
              "erreur"
            ],
            "description": "`info` : constat sans conséquence. `correction` : l'adresse a été modifiée. `alerte` : doute à lever. `erreur` : l'adresse ne peut pas être validée."
          }
        }
      },
      "Correspondance": {
        "type": "object",
        "description": "Ce qui a été retrouvé dans le référentiel.",
        "properties": {
          "precision": {
            "type": "string",
            "enum": [
              "",
              "commune",
              "voie",
              "numero"
            ],
            "description": "Niveau atteint : `numero` (adresse exacte, coordonnées du numéro), `voie` (voie trouvée, numéro absent de la BAN), `commune` (commune seulement), vide (rien de sûr)."
          },
          "code_insee": {
            "type": "string",
            "description": "Code officiel de la commune (COG)."
          },
          "code_postal": {
            "type": "string"
          },
          "commune": {
            "type": "string",
            "description": "Nom de la commune."
          },
          "libelle_acheminement": {
            "type": "string",
            "description": "Nom de localité utilisé par La Poste (ligne 6)."
          },
          "voie": {
            "type": "string"
          },
          "id_voie": {
            "type": "string",
            "description": "Identifiant de la voie dans la BAN."
          },
          "numero": {
            "type": "string"
          },
          "id_ban": {
            "type": "string",
            "description": "Identifiant de l'adresse dans la BAN."
          },
          "lat": {
            "type": "number",
            "description": "Latitude (WGS 84) du numéro, à défaut de la voie."
          },
          "lon": {
            "type": "number",
            "description": "Longitude (WGS 84)."
          },
          "similarite_voie": {
            "type": "number",
            "description": "Ressemblance entre la voie saisie et la voie retenue, de 0 à 1."
          }
        }
      },
      "Proposition": {
        "type": "object",
        "description": "Une adresse candidate, quand le moteur ne peut pas choisir seul.",
        "properties": {
          "commune": {
            "type": "object",
            "properties": {
              "code_insee": {
                "type": "string"
              },
              "code_postal": {
                "type": "string"
              },
              "commune": {
                "type": "string"
              },
              "libelle_acheminement": {
                "type": "string"
              },
              "ligne5": {
                "type": "string",
                "description": "Lieu-dit ou ancienne commune à écrire en ligne 5."
              }
            }
          },
          "voie": {
            "type": "object",
            "properties": {
              "libelle": {
                "type": "string"
              },
              "id_voie": {
                "type": "string"
              },
              "ligne3": {
                "type": "string",
                "description": "Résidence à écrire en ligne 3, quand l'entrée de la BAN mêle résidence et adresse."
              },
              "numero_voie": {
                "type": "string",
                "description": "Numéro sur la voie dans ce même cas (le numéro saisi est alors celui de la maison dans la résidence)."
              }
            }
          },
          "numero": {
            "type": "object",
            "description": "Numéro saisi, cherché sur la voie proposée (informatif).",
            "properties": {
              "trouve": {
                "type": "boolean"
              },
              "numero": {
                "type": "string"
              },
              "id_ban": {
                "type": "string"
              },
              "code_postal": {
                "type": "string"
              },
              "lat": {
                "type": "number"
              },
              "lon": {
                "type": "number"
              }
            }
          }
        }
      },
      "Resultat": {
        "type": "object",
        "properties": {
          "ref": {
            "type": "string",
            "description": "Votre identifiant, s'il a été fourni."
          },
          "statut": {
            "type": "string",
            "enum": [
              "VALIDE",
              "CORRIGEE",
              "INCERTAINE",
              "INDETERMINEE",
              "REJETEE"
            ],
            "description": "`VALIDE` : conforme, rien à corriger. `CORRIGEE` : corrigée avec certitude. `INCERTAINE` : une réponse est rendue, avec un doute à vérifier. `INDETERMINEE` : aucune réponse choisie, la voie ou la localité ne peut pas être déterminée (plusieurs possibilités, voir `propositions`) ou la voie manque. `REJETEE` : impossible à valider."
          },
          "indice_confiance": {
            "type": "integer",
            "minimum": 0,
            "maximum": 100,
            "description": "En % : 100 moins les points retirés pour chaque correction ou doute (détail dans `detail_indice_confiance`)."
          },
          "entree": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Les 7 lignes telles que reçues (texte libre : en ligne 1)."
          },
          "sortie": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Les 7 lignes normalisées : majuscules, sans accents, 38 caractères au plus. À utiliser telles quelles pour l'envoi."
          },
          "codes": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Code"
            }
          },
          "correspondance": {
            "$ref": "#/components/schemas/Correspondance"
          },
          "propositions": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Proposition"
            },
            "description": "Adresses candidates quand la commune ou la voie est ambiguë (statut INDETERMINEE) : à faire choisir par l'utilisateur."
          },
          "alternatives": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "deprecated": true,
            "description": "Ancienne forme texte de `propositions`, conservée pour compatibilité."
          },
          "detail_indice_confiance": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "libelle": {
                  "type": "string"
                },
                "points": {
                  "type": "integer"
                }
              }
            },
            "description": "Points retirés à l'indice de confiance, et pourquoi."
          },
          "duree_us": {
            "type": "integer",
            "description": "Temps de traitement, en microsecondes."
          },
          "version_logiciel": {
            "type": "string",
            "description": "Version du logiciel (pour un lot : au niveau du lot)."
          },
          "version_referentiel": {
            "type": "string",
            "description": "Version du référentiel (pour un lot : au niveau du lot)."
          }
        }
      },
      "Lot": {
        "type": "object",
        "properties": {
          "resultats": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Resultat"
            },
            "description": "Un résultat par adresse, dans l'ordre d'envoi."
          },
          "duree_ms": {
            "type": "number",
            "description": "Temps de traitement du lot, en millisecondes."
          },
          "version_logiciel": {
            "type": "string"
          },
          "version_referentiel": {
            "type": "string"
          }
        }
      },
      "Erreur": {
        "type": "object",
        "properties": {
          "erreur": {
            "type": "string",
            "description": "Explication, en français."
          }
        }
      }
    }
  },
  "paths": {
    "/v1/adresses/normalisation": {
      "post": {
        "tags": [
          "Normalisation"
        ],
        "summary": "Normaliser une adresse",
        "description": "Vérifie une adresse, la corrige si besoin et la restitue sur 7 lignes aux normes de La Poste. Sans clé, accessible pour l'essai, en volume limité.",
        "security": [
          {
            "cleApi": []
          },
          {}
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AdresseIn"
              },
              "examples": {
                "lignes": {
                  "summary": "En lignes",
                  "value": {
                    "ref": "client-1042",
                    "lignes": [
                      "",
                      "",
                      "",
                      "15 QUAI DES CHARTRONS",
                      "",
                      "33000 BORDEAUX",
                      ""
                    ]
                  }
                },
                "texte_libre": {
                  "summary": "En texte libre",
                  "value": {
                    "ref": "client-1043",
                    "adresse": "15 qu des chartrons bdx"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Résultat (toujours 200, même pour une adresse rejetée : lire `statut`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Resultat"
                },
                "examples": {
                  "valide": {
                    "summary": "VALIDE : adresse conforme",
                    "value": {
                      "ref": "client-1042",
                      "statut": "VALIDE",
                      "indice_confiance": 100,
                      "entree": [
                        "",
                        "",
                        "",
                        "15 QUAI DES CHARTRONS",
                        "",
                        "33000 BORDEAUX",
                        ""
                      ],
                      "sortie": [
                        "",
                        "",
                        "",
                        "15 QUAI DES CHARTRONS",
                        "",
                        "33000 BORDEAUX",
                        ""
                      ],
                      "codes": [
                        {
                          "code": "PAYS_FRANCE",
                          "ligne": 7,
                          "libelle": "Pays : France",
                          "gravite": "info"
                        },
                        {
                          "code": "VILLE_PLURIDISTRIBUEE",
                          "ligne": 6,
                          "libelle": "Ville pluridistribuée (plusieurs codes postaux)",
                          "gravite": "info"
                        }
                      ],
                      "correspondance": {
                        "precision": "numero",
                        "code_insee": "33063",
                        "code_postal": "33000",
                        "commune": "BORDEAUX",
                        "libelle_acheminement": "BORDEAUX",
                        "voie": "QUAI DES CHARTRONS",
                        "id_voie": "33063_2000",
                        "numero": "15",
                        "id_ban": "33063_2000_00015",
                        "lat": 44.849567,
                        "lon": -0.570466,
                        "similarite_voie": 1
                      },
                      "detail_indice_confiance": [],
                      "duree_us": 276,
                      "version_logiciel": "0.1.0+65f0e8c",
                      "version_referentiel": "BAN-2026-10-17"
                    }
                  },
                  "corrigee": {
                    "summary": "CORRIGEE : type de voie, code postal et ville corrigés",
                    "value": {
                      "ref": "client-1043",
                      "statut": "CORRIGEE",
                      "indice_confiance": 94,
                      "entree": [
                        "15 qu des chartrons bdx",
                        "",
                        "",
                        "",
                        "",
                        "",
                        ""
                      ],
                      "sortie": [
                        "",
                        "",
                        "",
                        "15 QUAI DES CHARTRONS",
                        "",
                        "33000 BORDEAUX",
                        ""
                      ],
                      "codes": [
                        {
                          "code": "SAISIE_LIBRE_STRUCTUREE",
                          "ligne": 0,
                          "libelle": "Adresse saisie en texte libre, découpée en lignes",
                          "gravite": "info"
                        },
                        {
                          "code": "PAYS_FRANCE",
                          "ligne": 7,
                          "libelle": "Pays : France",
                          "gravite": "info"
                        },
                        {
                          "code": "TYPE_VOIE_NORMALISE",
                          "ligne": 4,
                          "libelle": "Type de voie normalisé",
                          "gravite": "correction"
                        },
                        {
                          "code": "CP_COMPLETE",
                          "ligne": 6,
                          "libelle": "Code postal complété : 33000",
                          "gravite": "correction"
                        },
                        {
                          "code": "ACHEMINEMENT_CORRIGE",
                          "ligne": 6,
                          "libelle": "Libellé d'acheminement corrigé : BDX → BORDEAUX",
                          "gravite": "correction"
                        },
                        {
                          "code": "VILLE_PLURIDISTRIBUEE",
                          "ligne": 6,
                          "libelle": "Ville pluridistribuée (plusieurs codes postaux)",
                          "gravite": "info"
                        }
                      ],
                      "correspondance": {
                        "precision": "numero",
                        "code_insee": "33063",
                        "code_postal": "33000",
                        "commune": "BORDEAUX",
                        "libelle_acheminement": "BORDEAUX",
                        "voie": "QUAI DES CHARTRONS",
                        "id_voie": "33063_2000",
                        "numero": "15",
                        "id_ban": "33063_2000_00015",
                        "lat": 44.849567,
                        "lon": -0.570466,
                        "similarite_voie": 1
                      },
                      "detail_indice_confiance": [
                        {
                          "libelle": "Code postal complété : 33000",
                          "points": -3
                        },
                        {
                          "libelle": "Libellé d'acheminement corrigé : BDX → BORDEAUX",
                          "points": -3
                        }
                      ],
                      "duree_us": 290,
                      "version_logiciel": "0.1.0+65f0e8c",
                      "version_referentiel": "BAN-2026-10-17"
                    }
                  },
                  "incertaine": {
                    "summary": "INCERTAINE : plusieurs communes possibles (10 propositions, 3 affichées)",
                    "value": {
                      "statut": "INCERTAINE",
                      "indice_confiance": 0,
                      "entree": [
                        "12 rue des ecoles st medard",
                        "",
                        "",
                        "",
                        "",
                        "",
                        ""
                      ],
                      "sortie": [
                        "",
                        "",
                        "",
                        "12 RUE DES ECOLES",
                        "",
                        "ST MEDARD",
                        ""
                      ],
                      "codes": [
                        {
                          "code": "SAISIE_LIBRE_STRUCTUREE",
                          "ligne": 0,
                          "libelle": "Adresse saisie en texte libre, découpée en lignes",
                          "gravite": "info"
                        },
                        {
                          "code": "PAYS_FRANCE",
                          "ligne": 7,
                          "libelle": "Pays : France",
                          "gravite": "info"
                        },
                        {
                          "code": "VOIE_INCONNUE",
                          "ligne": 4,
                          "libelle": "Voie inconnue du référentiel",
                          "gravite": "alerte"
                        },
                        {
                          "code": "CP_A_PRECISER",
                          "ligne": 6,
                          "libelle": "Code postal à préciser (plusieurs possibles)",
                          "gravite": "alerte"
                        },
                        {
                          "code": "INDECISION_ACHEMINEMENT",
                          "ligne": 6,
                          "libelle": "Plusieurs localités possibles, aucune choisie",
                          "gravite": "alerte"
                        }
                      ],
                      "correspondance": {
                        "precision": ""
                      },
                      "alternatives": [
                        "16170 VAL D AUGE",
                        "16300 ST MEDARD DE BARBEZIEUX",
                        "17500 ST MEDARD"
                      ],
                      "propositions": [
                        {
                          "commune": {
                            "code_insee": "16339",
                            "code_postal": "16170",
                            "commune": "VAL D AUGE",
                            "libelle_acheminement": "VAL D AUGE",
                            "ligne5": "ST MEDARD"
                          }
                        },
                        {
                          "commune": {
                            "code_insee": "16338",
                            "code_postal": "16300",
                            "commune": "ST MEDARD",
                            "libelle_acheminement": "ST MEDARD DE BARBEZIEUX"
                          }
                        },
                        {
                          "commune": {
                            "code_insee": "17372",
                            "code_postal": "17500",
                            "commune": "ST MEDARD",
                            "libelle_acheminement": "ST MEDARD"
                          }
                        }
                      ],
                      "detail_indice_confiance": [
                        {
                          "libelle": "Voie inconnue du référentiel",
                          "points": -48
                        },
                        {
                          "libelle": "Code postal à préciser (plusieurs possibles)",
                          "points": -30
                        },
                        {
                          "libelle": "Plusieurs localités possibles, aucune choisie",
                          "points": -30
                        }
                      ],
                      "duree_us": 386,
                      "version_logiciel": "0.1.0+65f0e8c",
                      "version_referentiel": "BAN-2026-10-17"
                    }
                  },
                  "rejetee": {
                    "summary": "REJETEE : code postal incomplet, commune introuvable",
                    "value": {
                      "statut": "REJETEE",
                      "indice_confiance": 0,
                      "entree": [
                        "5 rue du chateau 33",
                        "",
                        "",
                        "",
                        "",
                        "",
                        ""
                      ],
                      "sortie": [
                        "",
                        "",
                        "",
                        "5 RUE DU CHATEAU 33",
                        "",
                        "",
                        ""
                      ],
                      "codes": [
                        {
                          "code": "SAISIE_LIBRE_STRUCTUREE",
                          "ligne": 0,
                          "libelle": "Adresse saisie en texte libre, découpée en lignes",
                          "gravite": "info"
                        },
                        {
                          "code": "PAYS_FRANCE",
                          "ligne": 7,
                          "libelle": "Pays : France",
                          "gravite": "info"
                        },
                        {
                          "code": "CP_INCONNU",
                          "ligne": 6,
                          "libelle": "Code postal et localité non identifiés",
                          "gravite": "erreur"
                        },
                        {
                          "code": "VOIE_NON_CONTROLEE",
                          "ligne": 4,
                          "libelle": "Voie non contrôlée (commune non identifiée)",
                          "gravite": "alerte"
                        }
                      ],
                      "correspondance": {
                        "precision": ""
                      },
                      "detail_indice_confiance": [
                        {
                          "libelle": "Code postal et localité non identifiés",
                          "points": -100
                        }
                      ],
                      "duree_us": 734,
                      "version_logiciel": "0.1.0+65f0e8c",
                      "version_referentiel": "BAN-2026-10-17"
                    }
                  }
                }
              }
            },
            "headers": {
              "X-Credits-Restants": {
                "description": "Crédits restants après l'appel (formule du mois et recharges). Absent pour l'essai sans clé.",
                "schema": {
                  "type": "integer"
                }
              }
            }
          },
          "400": {
            "description": "Corps de requête qui n'est pas un JSON valide, ou champ inconnu.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erreur"
                },
                "example": {
                  "erreur": "JSON invalide : json: unknown field \"adress\""
                }
              }
            }
          },
          "401": {
            "description": "Clé d'API absente ou invalide, ou lot envoyé sans clé.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erreur"
                },
                "example": {
                  "erreur": "clé d'API absente ou invalide (en-tête X-API-Key)"
                }
              }
            }
          },
          "402": {
            "description": "Crédits épuisés : il n'en reste pas assez pour toutes les adresses de l'appel, rien n'est débité. Passer à une formule supérieure ou acheter une recharge.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erreur"
                },
                "example": {
                  "erreur": "crédits épuisés : 1 nécessaires (formule supérieure ou recharge : contact@nubelo.fr)"
                }
              }
            }
          },
          "422": {
            "description": "Adresse vide, plus de 7 lignes ou plus de 2 000 caractères.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erreur"
                },
                "example": {
                  "erreur": "renseigner « lignes » ou « adresse »"
                }
              }
            }
          },
          "429": {
            "description": "Limite de débit ou limite d'essai atteinte. Attendre le nombre de secondes indiqué par l'en-tête `Retry-After`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erreur"
                },
                "example": {
                  "erreur": "limite d'essai atteinte : réessayez dans quelques instants, ou demandez une clé d'API à contact@nubelo.fr"
                }
              }
            },
            "headers": {
              "Retry-After": {
                "description": "Secondes à attendre avant de réessayer",
                "schema": {
                  "type": "integer"
                },
                "example": 6
              }
            }
          }
        }
      }
    },
    "/v1/adresses/normalisation/lot": {
      "post": {
        "tags": [
          "Normalisation"
        ],
        "summary": "Normaliser jusqu'à 1 000 adresses",
        "description": "Traite jusqu'à 1 000 adresses en un appel (8 Mo au plus), réparties sur tous les processeurs du serveur. Clé d'API obligatoire. Pour un fichier plus gros, l'envoyer par tranches de 1 000. Chaque adresse coûte 1 crédit.",
        "security": [
          {
            "cleApi": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "adresses"
                ],
                "properties": {
                  "adresses": {
                    "type": "array",
                    "minItems": 1,
                    "maxItems": 1000,
                    "items": {
                      "$ref": "#/components/schemas/AdresseIn"
                    }
                  }
                }
              },
              "example": {
                "adresses": [
                  {
                    "ref": "1",
                    "adresse": "15 qu des chartrons bdx"
                  },
                  {
                    "ref": "2",
                    "lignes": [
                      "",
                      "",
                      "",
                      "12 AV DE GRADIGNAN",
                      "",
                      "33850 LEOGNAN",
                      ""
                    ]
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Résultats, dans l'ordre d'envoi.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Lot"
                },
                "example": {
                  "resultats": [
                    {
                      "ref": "1",
                      "statut": "CORRIGEE",
                      "indice_confiance": 94,
                      "entree": [
                        "15 qu des chartrons bdx",
                        "",
                        "",
                        "",
                        "",
                        "",
                        ""
                      ],
                      "sortie": [
                        "",
                        "",
                        "",
                        "15 QUAI DES CHARTRONS",
                        "",
                        "33000 BORDEAUX",
                        ""
                      ],
                      "codes": [
                        {
                          "code": "SAISIE_LIBRE_STRUCTUREE",
                          "ligne": 0,
                          "libelle": "Adresse saisie en texte libre, découpée en lignes",
                          "gravite": "info"
                        },
                        {
                          "code": "PAYS_FRANCE",
                          "ligne": 7,
                          "libelle": "Pays : France",
                          "gravite": "info"
                        },
                        {
                          "code": "TYPE_VOIE_NORMALISE",
                          "ligne": 4,
                          "libelle": "Type de voie normalisé",
                          "gravite": "correction"
                        },
                        {
                          "code": "CP_COMPLETE",
                          "ligne": 6,
                          "libelle": "Code postal complété : 33000",
                          "gravite": "correction"
                        },
                        {
                          "code": "ACHEMINEMENT_CORRIGE",
                          "ligne": 6,
                          "libelle": "Libellé d'acheminement corrigé : BDX → BORDEAUX",
                          "gravite": "correction"
                        },
                        {
                          "code": "VILLE_PLURIDISTRIBUEE",
                          "ligne": 6,
                          "libelle": "Ville pluridistribuée (plusieurs codes postaux)",
                          "gravite": "info"
                        }
                      ],
                      "correspondance": {
                        "precision": "numero",
                        "code_insee": "33063",
                        "code_postal": "33000",
                        "commune": "BORDEAUX",
                        "libelle_acheminement": "BORDEAUX",
                        "voie": "QUAI DES CHARTRONS",
                        "id_voie": "33063_2000",
                        "numero": "15",
                        "id_ban": "33063_2000_00015",
                        "lat": 44.849567,
                        "lon": -0.570466,
                        "similarite_voie": 1
                      },
                      "detail_indice_confiance": [
                        {
                          "libelle": "Code postal complété : 33000",
                          "points": -3
                        },
                        {
                          "libelle": "Libellé d'acheminement corrigé : BDX → BORDEAUX",
                          "points": -3
                        }
                      ],
                      "duree_us": 215
                    },
                    {
                      "ref": "2",
                      "statut": "CORRIGEE",
                      "indice_confiance": 100,
                      "entree": [
                        "",
                        "",
                        "",
                        "12 AV DE GRADIGNAN",
                        "",
                        "33850 LEOGNAN",
                        ""
                      ],
                      "sortie": [
                        "",
                        "",
                        "",
                        "12 AVENUE DE GRADIGNAN",
                        "",
                        "33850 LEOGNAN",
                        ""
                      ],
                      "codes": [
                        {
                          "code": "PAYS_FRANCE",
                          "ligne": 7,
                          "libelle": "Pays : France",
                          "gravite": "info"
                        },
                        {
                          "code": "TYPE_VOIE_NORMALISE",
                          "ligne": 4,
                          "libelle": "Type de voie normalisé",
                          "gravite": "correction"
                        },
                        {
                          "code": "NUMERO_INCONNU",
                          "ligne": 4,
                          "libelle": "Numéro absent de la BAN : voie validée, sans les informations du numéro",
                          "gravite": "info"
                        }
                      ],
                      "correspondance": {
                        "precision": "voie",
                        "code_insee": "33238",
                        "code_postal": "33850",
                        "commune": "LEOGNAN",
                        "libelle_acheminement": "LEOGNAN",
                        "voie": "AVENUE DE GRADIGNAN",
                        "id_voie": "33238_0271",
                        "lat": 44.735889,
                        "lon": -0.612575,
                        "similarite_voie": 1
                      },
                      "detail_indice_confiance": [],
                      "duree_us": 169
                    }
                  ],
                  "duree_ms": 0.247,
                  "version_logiciel": "0.1.0+65f0e8c",
                  "version_referentiel": "BAN-2026-10-17"
                }
              }
            },
            "headers": {
              "X-Credits-Restants": {
                "description": "Crédits restants après l'appel (formule du mois et recharges). Absent pour l'essai sans clé.",
                "schema": {
                  "type": "integer"
                }
              }
            }
          },
          "400": {
            "description": "Corps de requête qui n'est pas un JSON valide, ou champ inconnu.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erreur"
                },
                "example": {
                  "erreur": "JSON invalide : json: unknown field \"adress\""
                }
              }
            }
          },
          "401": {
            "description": "Clé d'API absente ou invalide, ou lot envoyé sans clé.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erreur"
                },
                "example": {
                  "erreur": "clé d'API absente ou invalide (en-tête X-API-Key)"
                }
              }
            }
          },
          "402": {
            "description": "Crédits épuisés : il n'en reste pas assez pour toutes les adresses de l'appel, rien n'est débité. Passer à une formule supérieure ou acheter une recharge.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erreur"
                },
                "example": {
                  "erreur": "crédits épuisés : 1 nécessaires (formule supérieure ou recharge : contact@nubelo.fr)"
                }
              }
            }
          },
          "422": {
            "description": "Lot vide ou de plus de 1 000 adresses, ou adresse invalide (son rang est indiqué).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erreur"
                },
                "example": {
                  "erreur": "le lot doit contenir entre 1 et 1000 adresses"
                }
              }
            }
          },
          "429": {
            "description": "Limite de débit ou limite d'essai atteinte. Attendre le nombre de secondes indiqué par l'en-tête `Retry-After`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erreur"
                },
                "example": {
                  "erreur": "limite d'essai atteinte : réessayez dans quelques instants, ou demandez une clé d'API à contact@nubelo.fr"
                }
              }
            },
            "headers": {
              "Retry-After": {
                "description": "Secondes à attendre avant de réessayer",
                "schema": {
                  "type": "integer"
                },
                "example": 6
              }
            }
          },
          "503": {
            "description": "Trop de lots en cours sur le serveur : réessayer quelques instants plus tard.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erreur"
                },
                "example": {
                  "erreur": "serveur occupé : réessayez dans quelques instants"
                }
              }
            }
          }
        }
      }
    },
    "/v1/adresses/suggestions/communes": {
      "get": {
        "tags": [
          "Saisie assistée"
        ],
        "summary": "Communes, par début de nom ou de code postal",
        "description": "À appeler pendant la frappe dans le champ ville ou code postal.",
        "parameters": [
          {
            "name": "q",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "leog",
            "description": "Début du nom de la commune, ou du code postal."
          },
          {
            "name": "cp",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Restreint aux codes postaux commençant par cette valeur."
          },
          {
            "name": "limite",
            "in": "query",
            "schema": {
              "type": "integer",
              "maximum": 20,
              "default": 8
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Propositions, les plus probables d'abord.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "properties": {
                      "code_postal": {
                        "type": "string"
                      },
                      "libelle": {
                        "type": "string",
                        "description": "Libellé d'acheminement La Poste."
                      },
                      "commune": {
                        "type": "string"
                      },
                      "code_insee": {
                        "type": "string",
                        "description": "À passer à `/v1/adresses/suggestions/voies`."
                      }
                    }
                  }
                },
                "example": [
                  {
                    "code_postal": "33850",
                    "libelle": "LEOGNAN",
                    "commune": "LEOGNAN",
                    "code_insee": "33238"
                  }
                ]
              }
            }
          }
        }
      }
    },
    "/v1/adresses/suggestions/voies": {
      "get": {
        "tags": [
          "Saisie assistée"
        ],
        "summary": "Voies d'une commune",
        "description": "À appeler pendant la frappe de la ligne « numéro et voie », une fois la commune choisie.",
        "parameters": [
          {
            "name": "q",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "12 av de gra",
            "description": "Saisie en cours, numéro compris ; les abréviations sont reconnues."
          },
          {
            "name": "insee",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "example": "33238",
            "description": "Code INSEE de la commune (donné par `/v1/adresses/suggestions/communes`)."
          },
          {
            "name": "cp",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Code postal, à défaut de code INSEE."
          },
          {
            "name": "limite",
            "in": "query",
            "schema": {
              "type": "integer",
              "maximum": 20,
              "default": 8
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Propositions.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "properties": {
                      "voie": {
                        "type": "string"
                      },
                      "codes_postaux": {
                        "type": "array",
                        "items": {
                          "type": "string"
                        }
                      },
                      "code_insee": {
                        "type": "string"
                      },
                      "commune": {
                        "type": "string"
                      }
                    }
                  }
                },
                "example": [
                  {
                    "voie": "AVENUE DE GRADIGNAN",
                    "codes_postaux": [
                      "33850"
                    ],
                    "code_insee": "33238",
                    "commune": "LEOGNAN"
                  }
                ]
              }
            }
          }
        }
      }
    },
    "/v1/adresses/codes": {
      "get": {
        "tags": [
          "Informations"
        ],
        "summary": "Liste des codes retour",
        "description": "Tous les codes que peut renvoyer la normalisation, avec leur ligne et leur gravité.",
        "responses": {
          "200": {
            "description": "Codes retour.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Code"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/adresses/referentiel": {
      "get": {
        "tags": [
          "Informations"
        ],
        "summary": "Référentiel chargé",
        "description": "Version et volumétrie du référentiel en service (mis à jour chaque semaine).",
        "responses": {
          "200": {
            "description": "Référentiel.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "version": {
                      "type": "string"
                    },
                    "version_logiciel": {
                      "type": "string"
                    },
                    "construit_le": {
                      "type": "string",
                      "format": "date-time"
                    },
                    "localites": {
                      "type": "integer"
                    },
                    "voies": {
                      "type": "integer"
                    },
                    "numeros": {
                      "type": "integer"
                    },
                    "cedex": {
                      "type": "integer"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/sante": {
      "get": {
        "tags": [
          "Informations"
        ],
        "summary": "État du service",
        "description": "Pour la supervision : répond 200 tant que le service fonctionne.",
        "responses": {
          "200": {
            "description": "Service disponible.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "statut": {
                      "type": "string",
                      "example": "ok"
                    },
                    "depuis": {
                      "type": "string",
                      "format": "date-time",
                      "description": "Démarrage du service."
                    },
                    "version_logiciel": {
                      "type": "string"
                    },
                    "version_referentiel": {
                      "type": "string"
                    }
                  }
                },
                "example": {
                  "depuis": "2026-10-24T14:28:29Z",
                  "statut": "ok",
                  "version_logiciel": "0.1.0+65f0e8c",
                  "version_referentiel": "BAN-2026-10-17",
                  "detail_indice_confiance": []
                }
              }
            }
          }
        }
      }
    }
  }
}
