{
 "openapi": "3.1.0",
 "info": {
  "title": "API de la plateforme de gestion des organismes de formation",
  "version": "1.0.0",
  "description": "API REST de l'organisme : catalogue, dossiers, indicateurs qualité, BPF, pilotage, calendrier éditorial et dépôt de demandes. Authentification par clé d'intégration (`Authorization: Bearer s4mk_…`), créée par un administrateur dans Organisme → Intégrations (API et MCP). Chaque clé est limitée à son organisme et à ses permissions. La même clé ouvre le serveur MCP (`/mcp`) pour les assistants IA."
 },
 "servers": [
  {
   "url": "https://votre-espace/api/v1"
  }
 ],
 "security": [
  {
   "cle": []
  }
 ],
 "components": {
  "securitySchemes": {
   "cle": {
    "type": "http",
    "scheme": "bearer",
    "bearerFormat": "s4mk_…",
    "description": "`organisme:lecture` : Identité publique de l'organisme (raison sociale, NDA, certificat) ; `catalogue:lecture` : Catalogue des formations ; `sessions:lecture` : Sessions disponibles à la vente (dates, lieux, places restantes, prix) ; `qualite:lecture` : Indicateurs qualité, BPF et pilotage (chiffres agrégés, sans donnée personnelle) ; `dossiers:lecture` : Dossiers de formation (contient des noms d'apprenants : données personnelles) ; `leads:ecriture` : Déposer une demande (prospect, contact) dans la boîte de réception ; `editorial:lecture` : Calendrier éditorial des réseaux sociaux (contenus prévus, validés, publiés)"
   }
  },
  "responses": {
   "Erreur": {
    "description": "Erreur (message en français, code stable).",
    "content": {
     "application/json": {
      "schema": {
       "type": "object",
       "properties": {
        "erreur": {
         "type": "string"
        },
        "code": {
         "type": "string",
         "enum": [
          "non_authentifie",
          "interdit",
          "introuvable",
          "invalide",
          "conflit",
          "trop_de_requetes"
         ]
        }
       }
      }
     }
    }
   }
  },
  "schemas": {
   "Lead": {
    "type": "object",
    "required": [
     "prenom",
     "nom",
     "email",
     "objectif"
    ],
    "properties": {
     "prenom": {
      "type": "string",
      "maxLength": 80
     },
     "nom": {
      "type": "string",
      "maxLength": 80
     },
     "email": {
      "type": "string",
      "format": "email"
     },
     "telephone": {
      "type": "string",
      "maxLength": 30
     },
     "formation_souhaitee": {
      "type": "string",
      "maxLength": 400
     },
     "objectif": {
      "type": "string",
      "minLength": 5,
      "maxLength": 1000
     },
     "message": {
      "type": "string",
      "maxLength": 2500
     },
     "source": {
      "type": "string",
      "maxLength": 120,
      "description": "Outil ou campagne d'origine (par défaut : le nom de la clé)."
     }
    }
   }
  }
 },
 "paths": {
  "/organisme": {
   "get": {
    "operationId": "lireOrganisme",
    "summary": "Identité publique de l'organisme (NDA, certificat Qualiopi, référent handicap)",
    "security": [
     {
      "cle": [
       "organisme:lecture"
      ]
     }
    ],
    "responses": {
     "200": {
      "description": "Identité de l'organisme",
      "content": {
       "application/json": {
        "schema": {
         "type": "object"
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Erreur"
     },
     "403": {
      "$ref": "#/components/responses/Erreur"
     },
     "429": {
      "$ref": "#/components/responses/Erreur"
     }
    }
   }
  },
  "/formations": {
   "get": {
    "operationId": "listerFormations",
    "summary": "Catalogue des formations",
    "security": [
     {
      "cle": [
       "catalogue:lecture"
      ]
     }
    ],
    "parameters": [
     {
      "name": "archivees",
      "in": "query",
      "schema": {
       "type": "string",
       "enum": [
        "oui",
        "non"
       ],
       "default": "non"
      }
     }
    ],
    "responses": {
     "200": {
      "description": "Formations",
      "content": {
       "application/json": {
        "schema": {
         "type": "object"
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Erreur"
     },
     "403": {
      "$ref": "#/components/responses/Erreur"
     },
     "429": {
      "$ref": "#/components/responses/Erreur"
     }
    }
   }
  },
  "/sessions": {
   "get": {
    "operationId": "listerSessionsDisponibles",
    "summary": "Sessions disponibles à la vente (inter et intra) : dates, lieu, places restantes, prix HT en euros",
    "security": [
     {
      "cle": [
       "sessions:lecture"
      ]
     }
    ],
    "parameters": [
     {
      "name": "formation_id",
      "in": "query",
      "schema": {
       "type": "string"
      }
     },
     {
      "name": "du",
      "in": "query",
      "schema": {
       "type": "string",
       "format": "date"
      },
      "description": "Sessions qui commencent à partir de cette date."
     },
     {
      "name": "au",
      "in": "query",
      "schema": {
       "type": "string",
       "format": "date"
      },
      "description": "Sessions qui commencent au plus tard à cette date."
     },
     {
      "name": "modalite",
      "in": "query",
      "schema": {
       "type": "string",
       "enum": [
        "presentiel",
        "distanciel",
        "mixte"
       ]
      }
     },
     {
      "name": "lieu",
      "in": "query",
      "schema": {
       "type": "string"
      },
      "description": "Texte cherché dans le nom et l'adresse du lieu."
     },
     {
      "name": "places",
      "in": "query",
      "schema": {
       "type": "integer",
       "minimum": 1
      },
      "description": "Places restantes minimales."
     },
     {
      "name": "type",
      "in": "query",
      "schema": {
       "type": "string",
       "enum": [
        "inter",
        "intra"
       ]
      }
     }
    ],
    "responses": {
     "200": {
      "description": "Sessions vendables",
      "content": {
       "application/json": {
        "schema": {
         "type": "object"
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Erreur"
     },
     "403": {
      "$ref": "#/components/responses/Erreur"
     },
     "429": {
      "$ref": "#/components/responses/Erreur"
     }
    }
   }
  },
  "/organisme/identite": {
   "get": {
    "operationId": "lireIdentiteOrganisme",
    "summary": "Design system de l'organisme : palette (contrastes AA), typographies, rayons, boutons",
    "security": [
     {
      "cle": [
       "organisme:lecture"
      ]
     }
    ],
    "responses": {
     "200": {
      "description": "Design system",
      "content": {
       "application/json": {
        "schema": {
         "type": "object"
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Erreur"
     },
     "403": {
      "$ref": "#/components/responses/Erreur"
     },
     "429": {
      "$ref": "#/components/responses/Erreur"
     }
    }
   }
  },
  "/organisme/dossier-documentaire": {
   "get": {
    "operationId": "lireDossierDocumentaire",
    "summary": "Dossier documentaire de l'organisme : activité, formations repérées, coordonnées publiques de fonction, ton éditorial (aucune donnée de personne physique)",
    "security": [
     {
      "cle": [
       "organisme:lecture"
      ]
     }
    ],
    "responses": {
     "200": {
      "description": "Dossier documentaire",
      "content": {
       "application/json": {
        "schema": {
         "type": "object"
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Erreur"
     },
     "403": {
      "$ref": "#/components/responses/Erreur"
     },
     "429": {
      "$ref": "#/components/responses/Erreur"
     }
    }
   }
  },
  "/certifications": {
   "get": {
    "operationId": "listerCertifications",
    "summary": "Certifications RS / RNCP de l'organisme",
    "security": [
     {
      "cle": [
       "catalogue:lecture"
      ]
     }
    ],
    "responses": {
     "200": {
      "description": "Certifications",
      "content": {
       "application/json": {
        "schema": {
         "type": "object"
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Erreur"
     },
     "403": {
      "$ref": "#/components/responses/Erreur"
     },
     "429": {
      "$ref": "#/components/responses/Erreur"
     }
    }
   }
  },
  "/dossiers": {
   "get": {
    "operationId": "listerDossiers",
    "summary": "Dossiers de formation (pagination par `apres` et `limite`)",
    "security": [
     {
      "cle": [
       "dossiers:lecture"
      ]
     }
    ],
    "parameters": [
     {
      "name": "etape",
      "in": "query",
      "schema": {
       "type": "string"
      }
     },
     {
      "name": "statut",
      "in": "query",
      "schema": {
       "type": "string"
      }
     },
     {
      "name": "archives",
      "in": "query",
      "schema": {
       "type": "string",
       "enum": [
        "oui",
        "non",
        "tous"
       ],
       "default": "non"
      }
     },
     {
      "name": "limite",
      "in": "query",
      "schema": {
       "type": "integer",
       "minimum": 1,
       "maximum": 200,
       "default": 50
      }
     },
     {
      "name": "apres",
      "in": "query",
      "schema": {
       "type": "integer",
       "minimum": 0,
       "default": 0
      }
     }
    ],
    "responses": {
     "200": {
      "description": "Page de dossiers",
      "content": {
       "application/json": {
        "schema": {
         "type": "object"
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Erreur"
     },
     "403": {
      "$ref": "#/components/responses/Erreur"
     },
     "429": {
      "$ref": "#/components/responses/Erreur"
     }
    }
   }
  },
  "/dossiers/{id}": {
   "get": {
    "operationId": "lireDossier",
    "summary": "Un dossier : avancement, pièces manquantes, statut de chaque pièce",
    "security": [
     {
      "cle": [
       "dossiers:lecture"
      ]
     }
    ],
    "parameters": [
     {
      "name": "id",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string"
      },
      "description": "Identifiant ou référence du dossier."
     }
    ],
    "responses": {
     "200": {
      "description": "Dossier",
      "content": {
       "application/json": {
        "schema": {
         "type": "object"
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Erreur"
     },
     "403": {
      "$ref": "#/components/responses/Erreur"
     },
     "404": {
      "$ref": "#/components/responses/Erreur"
     },
     "429": {
      "$ref": "#/components/responses/Erreur"
     }
    }
   }
  },
  "/indicateurs": {
   "get": {
    "operationId": "lireIndicateurs",
    "summary": "Indicateurs de résultats (Qualiopi, indicateur 2) et publications",
    "security": [
     {
      "cle": [
       "qualite:lecture"
      ]
     }
    ],
    "parameters": [
     {
      "name": "exercice",
      "in": "query",
      "required": false,
      "schema": {
       "type": "integer",
       "example": 2026
      },
      "description": "Exercice civil (par défaut : le plus récent)."
     }
    ],
    "responses": {
     "200": {
      "description": "Indicateurs",
      "content": {
       "application/json": {
        "schema": {
         "type": "object"
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Erreur"
     },
     "403": {
      "$ref": "#/components/responses/Erreur"
     },
     "429": {
      "$ref": "#/components/responses/Erreur"
     }
    }
   }
  },
  "/bpf": {
   "get": {
    "operationId": "lireBpf",
    "summary": "Bilan pédagogique et financier calculé",
    "security": [
     {
      "cle": [
       "qualite:lecture"
      ]
     }
    ],
    "parameters": [
     {
      "name": "exercice",
      "in": "query",
      "required": false,
      "schema": {
       "type": "integer",
       "example": 2026
      },
      "description": "Exercice civil (par défaut : le plus récent)."
     }
    ],
    "responses": {
     "200": {
      "description": "BPF",
      "content": {
       "application/json": {
        "schema": {
         "type": "object"
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Erreur"
     },
     "403": {
      "$ref": "#/components/responses/Erreur"
     },
     "429": {
      "$ref": "#/components/responses/Erreur"
     }
    }
   }
  },
  "/pilotage": {
   "get": {
    "operationId": "lirePilotage",
    "summary": "Pilotage : chiffre d'affaires facturé, dossiers par étape, alertes",
    "security": [
     {
      "cle": [
       "qualite:lecture"
      ]
     }
    ],
    "parameters": [
     {
      "name": "annee",
      "in": "query",
      "schema": {
       "type": "integer"
      }
     }
    ],
    "responses": {
     "200": {
      "description": "Pilotage",
      "content": {
       "application/json": {
        "schema": {
         "type": "object"
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Erreur"
     },
     "403": {
      "$ref": "#/components/responses/Erreur"
     },
     "429": {
      "$ref": "#/components/responses/Erreur"
     }
    }
   }
  },
  "/editorial/calendrier": {
   "get": {
    "operationId": "lireCalendrierEditorial",
    "summary": "Calendrier éditorial des réseaux sociaux : contenus datés de la période (30 jours à partir d'aujourd'hui par défaut, 400 au plus)",
    "security": [
     {
      "cle": [
       "editorial:lecture"
      ]
     }
    ],
    "parameters": [
     {
      "name": "debut",
      "in": "query",
      "schema": {
       "type": "string",
       "format": "date"
      },
      "description": "AAAA-MM-JJ (par défaut : aujourd'hui)."
     },
     {
      "name": "fin",
      "in": "query",
      "schema": {
       "type": "string",
       "format": "date"
      },
      "description": "AAAA-MM-JJ (par défaut : début + 30 jours)."
     },
     {
      "name": "statut",
      "in": "query",
      "schema": {
       "type": "string",
       "enum": [
        "idee",
        "brouillon",
        "a_valider",
        "valide",
        "programme",
        "publie",
        "abandonne"
       ]
      },
      "description": "Un seul statut (par défaut : tous sauf « abandonne »)."
     }
    ],
    "responses": {
     "200": {
      "description": "Contenus de la période",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "periode": {
           "type": "object"
          },
          "contenus": {
           "type": "array",
           "items": {
            "type": "object"
           }
          }
         }
        }
       }
      }
     },
     "400": {
      "$ref": "#/components/responses/Erreur"
     },
     "401": {
      "$ref": "#/components/responses/Erreur"
     },
     "403": {
      "$ref": "#/components/responses/Erreur"
     },
     "429": {
      "$ref": "#/components/responses/Erreur"
     }
    }
   }
  },
  "/leads": {
   "post": {
    "operationId": "creerLead",
    "summary": "Déposer une demande de contact dans la boîte de réception de l'organisme",
    "security": [
     {
      "cle": [
       "leads:ecriture"
      ]
     }
    ],
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/Lead"
       }
      }
     }
    },
    "responses": {
     "201": {
      "description": "Demande enregistrée",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "numero": {
           "type": "string"
          },
          "statut": {
           "type": "string"
          }
         }
        }
       }
      }
     },
     "400": {
      "$ref": "#/components/responses/Erreur"
     },
     "401": {
      "$ref": "#/components/responses/Erreur"
     },
     "403": {
      "$ref": "#/components/responses/Erreur"
     },
     "429": {
      "$ref": "#/components/responses/Erreur"
     }
    }
   }
  },
  "/moi": {
   "get": {
    "operationId": "lireCle",
    "summary": "La clé utilisée : organisme et permissions (pour tester une connexion)",
    "responses": {
     "200": {
      "description": "Clé",
      "content": {
       "application/json": {
        "schema": {
         "type": "object"
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Erreur"
     },
     "403": {
      "$ref": "#/components/responses/Erreur"
     },
     "429": {
      "$ref": "#/components/responses/Erreur"
     }
    }
   }
  }
 }
}
