{
  "openapi": "3.0.3",
  "info": {
    "title": "NaviBat — API publique",
    "version": "1.0.0",
    "description": "app.navibat.fr est un ERP SaaS pour artisans du BTP. La quasi-totalité des opérations métier (chantiers, devis, factures) passe par des Server Actions Next.js internes, sans URL HTTP stable, et ne peut donc pas être décrite ici. Cette spécification couvre uniquement les routes HTTP publiques et stables sous /api/*."
  },
  "servers": [{ "url": "https://app.navibat.fr" }],
  "paths": {
    "/api/upload": {
      "post": {
        "operationId": "uploadFile",
        "summary": "Importer un fichier (document ou logo d'organisation)",
        "description": "Nécessite une session authentifiée (cookie). Stocke le fichier sur Vercel Blob et retourne son URL publique.",
        "security": [{ "sessionCookie": [] }],
        "requestBody": {
          "required": true,
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "properties": {
                  "file": { "type": "string", "format": "binary" },
                  "chantierId": { "type": "string", "description": "Optionnel — rattache le document à un chantier" },
                  "kind": { "type": "string", "enum": ["logo"], "description": "Optionnel — 'logo' pour un logo d'organisation (contraintes de taille/format différentes)" }
                },
                "required": ["file"]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Fichier importé",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": { "type": "boolean" },
                    "url": { "type": "string", "format": "uri" },
                    "nom": { "type": "string" },
                    "taille": { "type": "integer" },
                    "mimeType": { "type": "string" }
                  }
                }
              }
            }
          },
          "400": { "$ref": "#/components/responses/Error" },
          "401": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/api/auth/check-email": {
      "post": {
        "operationId": "checkEmailExists",
        "summary": "Vérifier si un email est déjà associé à un compte",
        "description": "Utilisé par le flux de mot de passe oublié. Route non authentifiée, à usage limité — expose intentionnellement l'existence d'un compte pour cet email.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": { "email": { "type": "string", "format": "email" } },
                "required": ["email"]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Résultat de la vérification",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": { "exists": { "type": "boolean" } }
                }
              }
            }
          },
          "400": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/api/auth/verify-reset-otp": {
      "post": {
        "operationId": "verifyResetOtp",
        "summary": "Vérifier un code de réinitialisation de mot de passe (sans le consommer)",
        "description": "Route non authentifiée. Permet à un client de valider un code OTP avant de l'utiliser réellement pour réinitialiser le mot de passe (ex : activer le bouton \"Réinitialiser\" seulement si le code est correct).",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "email": { "type": "string", "format": "email" },
                  "otp": { "type": "string", "minLength": 6, "maxLength": 6 }
                },
                "required": ["email", "otp"]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Code valide",
            "content": {
              "application/json": {
                "schema": { "type": "object", "properties": { "success": { "type": "boolean" } } }
              }
            }
          },
          "400": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/api/auth/reset-password": {
      "post": {
        "operationId": "resetPassword",
        "summary": "Réinitialiser le mot de passe avec un code valide",
        "description": "Route non authentifiée. Consomme le code OTP (usage unique).",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "email": { "type": "string", "format": "email" },
                  "otp": { "type": "string", "minLength": 6, "maxLength": 6 },
                  "newPassword": { "type": "string", "minLength": 8 }
                },
                "required": ["email", "otp", "newPassword"]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Mot de passe mis à jour",
            "content": {
              "application/json": {
                "schema": { "type": "object", "properties": { "success": { "type": "boolean" } } }
              }
            }
          },
          "400": { "$ref": "#/components/responses/Error" },
          "404": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/api/webhooks/b2brouter": {
      "post": {
        "operationId": "receiveB2brouterWebhook",
        "summary": "Webhook entrant B2BRouter (changement d'état de facture électronique)",
        "description": "Appelé par B2BRouter, pas par un client applicatif. Authentifié par signature HMAC-SHA256 dans l'en-tête X-B2Brouter-Signature (format t=<timestamp>,s=<hex>), pas par session.",
        "parameters": [
          {
            "name": "X-B2Brouter-Signature",
            "in": "header",
            "required": true,
            "schema": { "type": "string" },
            "description": "t=<unix_timestamp>,s=<hmac_sha256_hex>"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "code": { "type": "string", "example": "issued_invoice.state_change" },
                  "data": {
                    "type": "object",
                    "properties": {
                      "invoice_id": { "type": "integer" },
                      "state": { "type": "string" }
                    },
                    "required": ["invoice_id", "state"]
                  }
                },
                "required": ["code", "data"]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Accusé de réception",
            "content": {
              "application/json": {
                "schema": { "type": "object", "properties": { "received": { "type": "boolean" } } }
              }
            }
          },
          "401": { "description": "Signature invalide ou absente", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
          "500": { "description": "Webhook non configuré côté serveur (secret manquant)", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "sessionCookie": {
        "type": "apiKey",
        "in": "cookie",
        "name": "better-auth.session_token",
        "description": "Cookie de session posé après connexion via /api/auth/*"
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "properties": { "error": { "type": "string" } },
        "required": ["error"]
      }
    },
    "responses": {
      "Error": {
        "description": "Erreur",
        "content": {
          "application/json": { "schema": { "$ref": "#/components/schemas/Error" } }
        }
      }
    }
  }
}
