{
  "openapi": "3.0.3",
  "info": {
    "title": "NEXE API",
    "version": "1.0.0",
    "description": "API d'accès aux données publiques d'entreprises françaises : Sirene (INSEE) et Registre national des entreprises (INPI).\n\nAuthentification : `Authorization: Bearer nexe_live_…`.\n\nLicences : Licence Ouverte 2.0 pour Sirene, Licence RNE 2024 pour l'INPI. Les entreprises ayant refusé la diffusion commerciale au RNE renvoient un HTTP 451.",
    "contact": {
      "name": "NEXE Solutions",
      "email": "adrien@nexe-solutions.fr",
      "url": "https://nexe-solutions.fr"
    }
  },
  "servers": [
    {
      "url": "/",
      "description": "Serveur courant"
    }
  ],
  "tags": [
    { "name": "Service", "description": "État du service et informations de quota." },
    { "name": "Entreprises", "description": "Entités légales Sirene et données RNE consolidées." },
    { "name": "Établissements", "description": "Établissements et adresses." },
    { "name": "Dirigeants", "description": "Dirigeants, associés et représentants légaux issus du RNE." },
    { "name": "GAEC", "description": "Membres des groupements agricoles d'exploitation en commun." },
    { "name": "Recherche", "description": "Recherche lexicale tolérante." }
  ],
  "security": [
    { "bearerAuth": [] }
  ],
  "paths": {
    "/api/v1/ping": {
      "get": {
        "tags": ["Service"],
        "summary": "Vérifier le service et le quota",
        "operationId": "ping",
        "description": "Retourne l'état du service, le client authentifié, les scopes du token et son quota mensuel.",
        "responses": {
          "200": {
            "description": "Service disponible.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/PingResponse" }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "429": { "$ref": "#/components/responses/TooManyRequests" }
        }
      }
    },
    "/api/v1/entreprises/{siren}": {
      "get": {
        "tags": ["Entreprises"],
        "summary": "Fiche entreprise consolidée",
        "operationId": "getEntreprise",
        "description": "Retourne l'unité légale Sirene, son siège et, si disponible, les données RNE. Les données RNE non diffusibles ne sont jamais exposées.",
        "parameters": [
          { "$ref": "#/components/parameters/Siren" }
        ],
        "responses": {
          "200": {
            "description": "Entreprise trouvée.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": { "$ref": "#/components/schemas/Entreprise" }
                  }
                }
              }
            }
          },
          "404": { "$ref": "#/components/responses/NotFound" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "429": { "$ref": "#/components/responses/TooManyRequests" }
        }
      }
    },
    "/api/v1/entreprises/{siren}/etablissements": {
      "get": {
        "tags": ["Établissements"],
        "summary": "Lister les établissements d'une entreprise",
        "operationId": "getEntrepriseEtablissements",
        "parameters": [
          { "$ref": "#/components/parameters/Siren" },
          { "$ref": "#/components/parameters/Page" },
          { "$ref": "#/components/parameters/PerPage" }
        ],
        "responses": {
          "200": {
            "description": "Liste paginée des établissements.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": { "$ref": "#/components/schemas/Etablissement" }
                    },
                    "meta": {
                      "type": "object",
                      "properties": {
                        "siren": { "type": "string" },
                        "pagination": { "$ref": "#/components/schemas/Pagination" }
                      }
                    },
                    "links": { "$ref": "#/components/schemas/Links" }
                  }
                }
              }
            }
          },
          "404": { "$ref": "#/components/responses/NotFound" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "429": { "$ref": "#/components/responses/TooManyRequests" }
        }
      }
    },
    "/api/v1/etablissements/{siret}": {
      "get": {
        "tags": ["Établissements"],
        "summary": "Fiche établissement",
        "operationId": "getEtablissement",
        "parameters": [
          { "$ref": "#/components/parameters/Siret" }
        ],
        "responses": {
          "200": {
            "description": "Établissement trouvé.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": { "$ref": "#/components/schemas/Etablissement" }
                  }
                }
              }
            }
          },
          "404": { "$ref": "#/components/responses/NotFound" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "429": { "$ref": "#/components/responses/TooManyRequests" }
        }
      }
    },
    "/api/v1/entreprises/{siren}/dirigeants": {
      "get": {
        "tags": ["Dirigeants"],
        "summary": "Lister les dirigeants et associés",
        "operationId": "getDirigeants",
        "description": "Pouvoirs issus du RNE. Si la diffusion commerciale est refusée, l'API répond 451 sans exposer les personnes.",
        "parameters": [
          { "$ref": "#/components/parameters/Siren" }
        ],
        "responses": {
          "200": {
            "description": "Dirigeants et associés.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "entreprise": {
                          "type": "object",
                          "properties": {
                            "siren": { "type": "string" },
                            "denomination": { "type": "string", "nullable": true }
                          }
                        },
                        "diffusion_commerciale": { "type": "boolean" },
                        "total": { "type": "integer" },
                        "dirigeants": {
                          "type": "array",
                          "items": { "$ref": "#/components/schemas/Personne" }
                        },
                        "source": { "$ref": "#/components/schemas/SourceRne" }
                      }
                    },
                    "meta": {
                      "type": "object",
                      "properties": {
                        "avertissement": { "type": "string" }
                      }
                    }
                  }
                }
              }
            }
          },
          "404": { "$ref": "#/components/responses/NotFound" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "429": { "$ref": "#/components/responses/TooManyRequests" },
          "451": { "$ref": "#/components/responses/LegalRestriction" }
        }
      }
    },
    "/api/v1/gaec/{identifiant}/membres": {
      "get": {
        "tags": ["GAEC"],
        "summary": "Lister les membres d'un GAEC",
        "operationId": "getGaecMembres",
        "description": "Accepte un SIREN ou un SIRET. Vérifie que l'entreprise est un GAEC et que sa diffusion commerciale est autorisée.",
        "parameters": [
          {
            "name": "identifiant",
            "in": "path",
            "required": true,
            "description": "SIREN (9 chiffres) ou SIRET (14 chiffres).",
            "schema": { "type": "string", "pattern": "^(?:[0-9]{9}|[0-9]{14})$" }
          }
        ],
        "responses": {
          "200": {
            "description": "Membres du GAEC.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "siren": { "type": "string" },
                        "identifiant_interroge": { "type": "string" },
                        "denomination": { "type": "string", "nullable": true },
                        "est_gaec": { "type": "boolean" },
                        "membres": {
                          "type": "array",
                          "items": { "$ref": "#/components/schemas/Personne" }
                        },
                        "total_membres": { "type": "integer" },
                        "source": { "type": "object", "additionalProperties": true }
                      }
                    },
                    "meta": {
                      "type": "object",
                      "properties": {
                        "avertissement": { "type": "string" }
                      }
                    }
                  }
                }
              }
            }
          },
          "404": { "$ref": "#/components/responses/NotFound" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "429": { "$ref": "#/components/responses/TooManyRequests" },
          "451": { "$ref": "#/components/responses/LegalRestriction" }
        }
      }
    },
    "/api/v1/recherche": {
      "get": {
        "tags": ["Recherche"],
        "summary": "Rechercher des entreprises",
        "operationId": "searchEntreprises",
        "description": "Recherche normalisée (sans accents, insensible à la casse) sur la dénomination, la commune, le code postal et l'activité. Utilise pg_trgm sur PostgreSQL. Au moins un critère parmi `q`, `code_postal` ou `activite` est requis.",
        "parameters": [
          {
            "name": "q",
            "in": "query",
            "required": false,
            "description": "Terme de recherche (2 caractères minimum s'il est fourni).",
            "schema": { "type": "string", "minLength": 2, "example": "gaec clisson" }
          },
          {
            "name": "code_postal",
            "in": "query",
            "required": false,
            "description": "Code postal du siège (les caractères non numériques sont ignorés).",
            "schema": { "type": "string", "example": "44190" }
          },
          {
            "name": "activite",
            "in": "query",
            "required": false,
            "description": "Code d'activité principale (préfixe accepté, avec ou sans point).",
            "schema": { "type": "string", "example": "01.50" }
          },
          {
            "name": "agricole",
            "in": "query",
            "required": false,
            "description": "Restreint aux activités agricoles.",
            "schema": { "type": "boolean" }
          },
          {
            "name": "active_only",
            "in": "query",
            "required": false,
            "description": "Restreint aux établissements en état administratif actif.",
            "schema": { "type": "boolean" }
          },
          { "$ref": "#/components/parameters/Page" },
          { "$ref": "#/components/parameters/PerPage" }
        ],
        "responses": {
          "200": {
            "description": "Résultats paginés.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": { "$ref": "#/components/schemas/Entreprise" }
                    },
                    "meta": {
                      "type": "object",
                      "properties": {
                        "criteres": { "type": "object", "additionalProperties": true },
                        "source": { "type": "string" },
                        "pagination": { "$ref": "#/components/schemas/Pagination" }
                      }
                    },
                    "links": { "$ref": "#/components/schemas/Links" }
                  }
                }
              }
            }
          },
          "422": { "$ref": "#/components/responses/ValidationError" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "429": { "$ref": "#/components/responses/TooManyRequests" }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "nexe_live_…",
        "description": "Token généré depuis l'administration. Envoyez `Authorization: Bearer <token>`."
      }
    },
    "parameters": {
      "Siren": {
        "name": "siren",
        "in": "path",
        "required": true,
        "description": "Numéro SIREN à 9 chiffres.",
        "schema": { "type": "string", "pattern": "^[0-9]{9}$", "example": "912345678" }
      },
      "Siret": {
        "name": "siret",
        "in": "path",
        "required": true,
        "description": "Numéro SIRET à 14 chiffres.",
        "schema": { "type": "string", "pattern": "^[0-9]{14}$", "example": "91234567800012" }
      },
      "Page": {
        "name": "page",
        "in": "query",
        "required": false,
        "schema": { "type": "integer", "minimum": 1, "default": 1 }
      },
      "PerPage": {
        "name": "per_page",
        "in": "query",
        "required": false,
        "schema": { "type": "integer", "minimum": 1, "maximum": 100, "default": 20 }
      }
    },
    "responses": {
      "Unauthorized": {
        "description": "Token absent, inconnu, révoqué ou expiré.",
        "content": {
          "application/json": {
            "schema": { "$ref": "#/components/schemas/ErrorResponse" }
          }
        }
      },
      "Forbidden": {
        "description": "Scope manquant pour cet endpoint.",
        "content": {
          "application/json": {
            "schema": { "$ref": "#/components/schemas/ErrorResponse" }
          }
        }
      },
      "NotFound": {
        "description": "Ressource introuvable.",
        "content": {
          "application/json": {
            "schema": { "$ref": "#/components/schemas/ErrorResponse" }
          }
        }
      },
      "ValidationError": {
        "description": "Paramètres invalides.",
        "content": {
          "application/json": {
            "schema": { "$ref": "#/components/schemas/ErrorResponse" }
          }
        }
      },
      "TooManyRequests": {
        "description": "Quota mensuel épuisé ou débit par minute dépassé.",
        "content": {
          "application/json": {
            "schema": { "$ref": "#/components/schemas/ErrorResponse" }
          }
        }
      },
      "LegalRestriction": {
        "description": "Diffusion commerciale refusée par l'entreprise (licence RNE).",
        "content": {
          "application/json": {
            "schema": { "$ref": "#/components/schemas/ErrorResponse" }
          }
        }
      }
    },
    "schemas": {
      "ErrorResponse": {
        "type": "object",
        "required": ["error"],
        "properties": {
          "error": {
            "type": "object",
            "required": ["code", "message"],
            "properties": {
              "code": { "type": "string", "example": "missing_scope" },
              "message": { "type": "string" },
              "details": { "type": "object", "nullable": true, "additionalProperties": true }
            }
          }
        }
      },
      "Pagination": {
        "type": "object",
        "properties": {
          "page": { "type": "integer" },
          "per_page": { "type": "integer" },
          "total": { "type": "integer" },
          "last_page": { "type": "integer" }
        }
      },
      "Links": {
        "type": "object",
        "properties": {
          "first": { "type": "string", "nullable": true },
          "prev": { "type": "string", "nullable": true },
          "next": { "type": "string", "nullable": true },
          "last": { "type": "string", "nullable": true }
        }
      },
      "FormeJuridique": {
        "type": "object",
        "properties": {
          "code": { "type": "string", "nullable": true },
          "libelle": { "type": "string", "nullable": true }
        }
      },
      "Adresse": {
        "type": "object",
        "properties": {
          "adresse": { "type": "string", "nullable": true },
          "code_postal": { "type": "string", "nullable": true },
          "commune": { "type": "string", "nullable": true },
          "code_commune": { "type": "string", "nullable": true },
          "latitude": { "type": "number", "nullable": true },
          "longitude": { "type": "number", "nullable": true }
        }
      },
      "SourceSirene": {
        "type": "object",
        "properties": {
          "nom": { "type": "string", "example": "INSEE – Sirene" },
          "licence": { "type": "string", "example": "Licence Ouverte 2.0 (Etalab)" },
          "attribution": { "type": "string", "example": "Source : INSEE – Sirene" }
        }
      },
      "SourceRne": {
        "type": "object",
        "properties": {
          "nom": { "type": "string", "example": "INPI – Registre national des entreprises" },
          "licence": { "type": "string", "example": "Licence RNE (INPI, 2024)" },
          "synchronise_le": { "type": "string", "format": "date-time", "nullable": true }
        }
      },
      "Etablissement": {
        "type": "object",
        "properties": {
          "siret": { "type": "string" },
          "siren": { "type": "string" },
          "nic": { "type": "string", "nullable": true },
          "enseignes": { "type": "array", "items": { "type": "string" } },
          "nom_commercial": { "type": "string", "nullable": true },
          "adresse": {
            "type": "object",
            "properties": {
              "ligne": { "type": "string", "nullable": true },
              "complement": { "type": "string", "nullable": true },
              "code_postal": { "type": "string", "nullable": true },
              "commune": { "type": "string", "nullable": true },
              "code_commune": { "type": "string", "nullable": true },
              "pays": { "type": "string", "nullable": true }
            }
          },
          "adresse_masquee": { "type": "boolean" },
          "latitude": { "type": "number", "nullable": true },
          "longitude": { "type": "number", "nullable": true },
          "activite_principale": { "type": "string", "nullable": true },
          "nomenclature_activite": { "type": "string", "nullable": true },
          "date_creation": { "type": "string", "format": "date", "nullable": true },
          "date_derniere_maj": { "type": "string", "format": "date", "nullable": true },
          "etat_administratif": { "type": "string", "nullable": true },
          "est_siege": { "type": "boolean" },
          "caractere_employeur": { "type": "boolean" },
          "tranche_effectifs": { "type": "string", "nullable": true },
          "annee_effectifs": { "type": "integer", "nullable": true },
          "statut_diffusion": { "type": "string", "nullable": true },
          "source": { "$ref": "#/components/schemas/SourceSirene" }
        }
      },
      "Rne": {
        "type": "object",
        "properties": {
          "siren": { "type": "string" },
          "denomination": { "type": "string", "nullable": true },
          "forme_juridique": { "$ref": "#/components/schemas/FormeJuridique" },
          "capital": {
            "type": "object",
            "nullable": true,
            "properties": {
              "montant": { "type": "number" },
              "devise": { "type": "string" }
            }
          },
          "date_immatriculation": { "type": "string", "format": "date", "nullable": true },
          "date_radiation": { "type": "string", "format": "date", "nullable": true },
          "adresse_siege": { "type": "object", "additionalProperties": true },
          "activite_principale": { "type": "string", "nullable": true },
          "est_gaec": { "type": "boolean" },
          "indicateur_actif_agricole": { "type": "boolean" },
          "diffusion_commerciale": { "type": "boolean" },
          "source": { "$ref": "#/components/schemas/SourceRne" }
        }
      },
      "Entreprise": {
        "type": "object",
        "properties": {
          "siren": { "type": "string" },
          "denomination": { "type": "string", "nullable": true },
          "nom_complet": { "type": "string", "nullable": true },
          "nom": { "type": "string", "nullable": true },
          "prenom": { "type": "string", "nullable": true },
          "sigle": { "type": "string", "nullable": true },
          "forme_juridique": { "$ref": "#/components/schemas/FormeJuridique" },
          "activite_principale": { "type": "string", "nullable": true },
          "nomenclature_activite": { "type": "string", "nullable": true },
          "date_creation": { "type": "string", "format": "date", "nullable": true },
          "date_derniere_maj": { "type": "string", "format": "date", "nullable": true },
          "etat_administratif": { "type": "string", "nullable": true },
          "tranche_effectifs": { "type": "string", "nullable": true },
          "annee_effectifs": { "type": "integer", "nullable": true },
          "categorie_entreprise": { "type": "string", "nullable": true },
          "caractere_employeur": { "type": "boolean" },
          "est_association": { "type": "boolean" },
          "est_agricole": { "type": "boolean" },
          "est_gaec": { "type": "boolean" },
          "statut_diffusion": { "type": "string", "nullable": true },
          "masque": { "type": "boolean" },
          "adresse_siege": { "$ref": "#/components/schemas/Adresse" },
          "siege": { "allOf": [{ "$ref": "#/components/schemas/Etablissement" }], "nullable": true },
          "etablissements": {
            "type": "object",
            "properties": {
              "nombre": { "type": "integer" },
              "url": { "type": "string" }
            }
          },
          "rne": { "allOf": [{ "$ref": "#/components/schemas/Rne" }], "nullable": true },
          "restrictions": {
            "type": "array",
            "items": { "type": "string" }
          },
          "liens": {
            "type": "object",
            "properties": {
              "self": { "type": "string" },
              "dirigeants": { "type": "string" },
              "etablissements": { "type": "string" }
            }
          },
          "source": {
            "type": "object",
            "properties": {
              "sirene": { "$ref": "#/components/schemas/SourceSirene" },
              "rne": { "allOf": [{ "$ref": "#/components/schemas/SourceRne" }], "nullable": true }
            }
          }
        }
      },
      "Personne": {
        "type": "object",
        "properties": {
          "id": { "type": "integer" },
          "type": { "type": "string", "enum": ["physique", "morale"] },
          "nom": { "type": "string", "nullable": true },
          "prenoms": { "type": "array", "items": { "type": "string" } },
          "denomination": { "type": "string", "nullable": true },
          "nom_complet": { "type": "string", "nullable": true },
          "qualite": { "type": "string", "nullable": true },
          "role_code": { "type": "string", "nullable": true },
          "annee_naissance": { "type": "integer", "nullable": true },
          "pays_naissance": { "type": "string", "nullable": true },
          "nationalite": { "type": "string", "nullable": true },
          "representant_legal": { "type": "boolean" },
          "actif": { "type": "boolean" }
        }
      },
      "PingResponse": {
        "type": "object",
        "properties": {
          "data": {
            "type": "object",
            "properties": {
              "service": { "type": "string", "example": "NEXE API" },
              "version": { "type": "string", "example": "v1" },
              "statut": { "type": "string", "example": "ok" },
              "heure_serveur": { "type": "string", "format": "date-time" },
              "client": {
                "type": "object",
                "properties": {
                  "nom": { "type": "string" },
                  "plan": { "type": "string", "nullable": true }
                }
              },
              "token": {
                "type": "object",
                "properties": {
                  "nom": { "type": "string" },
                  "prefixe": { "type": "string" },
                  "scopes": { "type": "array", "items": { "type": "string" } },
                  "expire_le": { "type": "string", "format": "date-time", "nullable": true }
                }
              },
              "quota": {
                "type": "object",
                "properties": {
                  "limite": { "type": "integer" },
                  "consomme": { "type": "integer" },
                  "restant": { "type": "integer" },
                  "reinitialisation": { "type": "integer" }
                }
              },
              "sources": { "type": "object", "additionalProperties": true }
            }
          }
        }
      }
    }
  }
}
