{
  "openapi": "3.0.3",
  "info": {
    "title": "0DATA Scel — SPINA API",
    "version": "3.0.0",
    "description": "Preuve-as-a-Service : scellez une donnée (empreinte SHA-256 + horodatage + ancrage Hedera HCS) en une requête HTTP. Clé API, quota mensuel, crédits, abonnement Stripe, fichier-clé (login sans saisie), scellement hors ligne Ed25519 (self-custody).\n\n**Base URL publique** : `https://scel.0data.fr/api/`\n\n**Auth** : en-tête `Authorization: Bearer scel_live_…` (clé API) ou `X-API-Key: scel_live_…`. Sans clé, le scellement fonctionne en mode invité (free tier limité, 10 scels/mois par IP).\n\n**Statut légal** : le scellement produit un *élément de preuve technique* (antériorité + intégrité), non qualifié par défaut. L'option horodatage qualifié (RFC 3161) passe par le QTSP de votre choix (BYO).",
    "contact": {
      "name": "0DATA support",
      "email": "support@0data.fr",
      "url": "https://scel.0data.fr"
    }
  },
  "servers": [
    { "url": "https://scel.0data.fr/api", "description": "Production (nginx — /api/ est strippé)" },
    { "url": "http://127.0.0.1:5099", "description": "Local direct (port 5099)" }
  ],
  "tags": [
    { "name": "Scellement", "description": "Sceller / vérifier une donnée" },
    { "name": "Compte & clés", "description": "Création de clé, fichier-clé, gestion du compte" },
    { "name": "Facturation", "description": "Plans, packs, checkout Stripe, remise de config" },
    { "name": "Verticales", "description": "Preuves réglementaires spécialisées (C2PA, consentement, agent IA, incident NIS2)" },
    { "name": "Méta", "description": "Modes, plans, santé, chaîne d'audit, clé publique" }
  ],
  "components": {
    "securitySchemes": {
      "ApiKeyHeader": {
        "type": "apiKey",
        "in": "header",
        "name": "X-API-Key",
        "description": "Clé API `scel_live_<64hex>`"
      },
      "BearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "`Authorization: Bearer <clé>` ou `<keyfile_id>:<file_hash>`"
      }
    },
    "schemas": {
      "ProofLocal": {
        "type": "object",
        "description": "Preuve en mode `local` (signature Ed25519, auto-vérifiable par un tiers avec la clé publique).",
        "properties": {
          "spina": { "type": "string", "example": "2.0" },
          "mode": { "type": "string", "enum": ["local"] },
          "alg": { "type": "string", "enum": ["Ed25519"] },
          "digest": { "type": "string", "description": "SHA-256 hex (64)", "example": "8f14e45fceea167a5a36dedd4bea2543" },
          "timestamp": { "type": "string", "format": "date-time", "description": "ISO 8601 UTC" },
          "signature": { "type": "string", "description": "Signature Ed25519 (128 hex) du message `digest|timestamp`" },
          "public_key": { "type": "string", "description": "Clé publique Ed25519 (64 hex)" },
          "authority": { "type": "string", "example": "SPINA Constat — 0DATA" },
          "sovereign": { "type": "boolean" },
          "self_verifiable": { "type": "boolean" }
        }
      },
      "ProofEidas": {
        "type": "object",
        "description": "Preuve en mode `eidas` (horodatage RFC 3161 via TSA).",
        "properties": {
          "spina": { "type": "string", "example": "2.0" },
          "mode": { "type": "string", "enum": ["eidas"] },
          "alg": { "type": "string", "enum": ["SHA256-RFC3161"] },
          "digest": { "type": "string" },
          "timestamp": { "type": "string", "format": "date-time" },
          "token_b64": { "type": "string", "description": "Token RFC 3161 (base64)" },
          "tsa": { "type": "string", "enum": ["freetsa", "certigna", "universign"] },
          "tsa_label": { "type": "string" },
          "eidas_qualified": { "type": "boolean" },
          "sovereign": { "type": "boolean" }
        }
      },
      "Proof": {
        "oneOf": [
          { "$ref": "#/components/schemas/ProofLocal" },
          { "$ref": "#/components/schemas/ProofEidas" }
        ]
      },
      "Anchor": {
        "type": "object",
        "description": "Ancrage Hedera HCS (best-effort).",
        "properties": {
          "network": { "type": "string", "example": "hedera-testnet" },
          "topic": { "type": "string", "example": "0.0.10605616" },
          "status": { "type": "string" },
          "timestamp": { "type": "string" }
        }
      },
      "Usage": {
        "type": "object",
        "properties": {
          "plan": { "type": "string", "example": "standard" },
          "used": { "type": "integer" },
          "quota": { "type": "integer" }
        }
      },
      "SealRequest": {
        "type": "object",
        "required": ["data"],
        "properties": {
          "data": {
            "description": "Contenu à sceller : chaîne (UTF-8) ou objet JSON (canonicalisé : clés triées). Le serveur calcule `digest = SHA-256(data)`. Pour sceller un fichier sans l'envoyer, calculez son SHA-256 côté client et passez le hash hex en `data`.",
            "oneOf": [ { "type": "string" }, { "type": "object" } ]
          },
          "mode": { "type": "string", "enum": ["local", "eidas"], "default": "local" },
          "tsa": { "type": "string", "enum": ["freetsa", "certigna", "universign"], "default": "freetsa", "description": "Pour mode=eidas uniquement." }
        }
      },
      "SealResponse": {
        "type": "object",
        "properties": {
          "ok": { "type": "boolean", "example": true },
          "proof": { "$ref": "#/components/schemas/Proof" },
          "anchor": { "$ref": "#/components/schemas/Anchor" },
          "info": { "type": "object" },
          "usage": { "$ref": "#/components/schemas/Usage" },
          "identity": { "type": "string", "enum": ["key", "guest"] }
        }
      },
      "QuotaError": {
        "type": "object",
        "properties": {
          "ok": { "type": "boolean", "example": false },
          "error": { "type": "string", "example": "quota_exceeded" },
          "detail": {
            "type": "object",
            "properties": {
              "plan": { "type": "string" },
              "used": { "type": "integer" },
              "quota": { "type": "integer" },
              "upgrade": { "type": "string" }
            }
          }
        }
      },
      "Record": {
        "type": "object",
        "description": "Enregistrement scellé (consentement / agent / incident) — horodaté, hashé, ancré, stocké (vérifiable via GET /proof/{digest})."
      }
    }
  },
  "paths": {
    "/seal": {
      "post": {
        "tags": ["Scellement"],
        "summary": "Sceller une donnée",
        "operationId": "seal",
        "security": [{ "BearerAuth": [] }, { "ApiKeyHeader": [] }],
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SealRequest" } } } },
        "responses": {
          "200": { "description": "Scellé", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SealResponse" } } } },
          "400": { "description": "Champ data manquant" },
          "401": { "description": "Clé fournie invalide" },
          "402": { "description": "Quota dépassé", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/QuotaError" } } } }
        }
      }
    },
    "/verify": {
      "post": {
        "tags": ["Scellement"],
        "summary": "Vérifier qu'une donnée correspond à sa preuve (gratuit, sans quota)",
        "operationId": "verify",
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": ["data", "proof"], "properties": { "data": { "oneOf": [ { "type": "string" }, { "type": "object" } ] }, "proof": { "$ref": "#/components/schemas/Proof" } } } } } },
        "responses": {
          "200": { "description": "Résultat", "content": { "application/json": { "schema": { "type": "object", "properties": { "ok": { "type": "boolean" }, "valid": { "type": "boolean" } } } } } },
          "400": { "description": "data/proof requis" }
        }
      }
    },
    "/keys": {
      "post": {
        "tags": ["Compte & clés"],
        "summary": "Inscription : crée un compte + une clé API + un fichier-clé",
        "operationId": "createKey",
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": ["email"], "properties": { "email": { "type": "string", "format": "email" }, "file_hash": { "type": "string", "description": "Optionnel : SHA-256 (64 hex) de votre propre fichier-clé (sinon généré)" } } } } } },
        "responses": {
          "201": { "description": "Clé créée (affichée une seule fois)", "content": { "application/json": { "schema": { "type": "object", "properties": { "ok": { "type": "boolean" }, "key": { "type": "string" }, "prefix": { "type": "string" }, "plan": { "type": "string" }, "quota_monthly": { "type": "integer" }, "account_id": { "type": "integer" }, "keyfile": { "type": "string" }, "keyfile_name": { "type": "string" }, "keyfile_warning": { "type": "string" }, "keyfile_registered": { "type": "boolean" }, "keyfile_id": { "type": "string" } } } } } },
          "409": { "description": "Email déjà pris → login fichier-clé" }
        }
      }
    },
    "/auth/keyfile": {
      "post": {
        "tags": ["Compte & clés"],
        "summary": "Login par fichier-clé (keyfile_id + hash)",
        "operationId": "keyfileLogin",
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": ["keyfile_id", "file_hash"], "properties": { "keyfile_id": { "type": "string" }, "file_hash": { "type": "string", "description": "SHA-256 (64 hex) du fichier .key" } } } } } },
        "responses": {
          "200": { "description": "Connecté", "content": { "application/json": { "schema": { "type": "object", "properties": { "ok": { "type": "boolean" }, "account_id": { "type": "integer" }, "email": { "type": "string" }, "plan": { "type": "string" }, "quota_monthly": { "type": "integer" }, "used_monthly": { "type": "integer" }, "credit_balance": { "type": "integer" }, "prefix": { "type": "string" }, "keyfile_id": { "type": "string" }, "subscription_active": { "type": "boolean" } } } } } },
          "400": { "description": "Hash invalide / keyfile_id requis" },
          "401": { "description": "Fichier-clé inconnu" }
        }
      }
    },
    "/usage": {
      "get": {
        "tags": ["Compte & clés"],
        "summary": "État de consommation de la clé",
        "operationId": "usage",
        "security": [{ "BearerAuth": [] }, { "ApiKeyHeader": [] }],
        "responses": {
          "200": { "description": "État", "content": { "application/json": { "schema": { "type": "object", "properties": { "plan": { "type": "string" }, "quota_monthly": { "type": "integer" }, "used_monthly": { "type": "integer" }, "credit_balance": { "type": "integer" }, "prefix": { "type": "string" }, "account_id": { "type": "integer" } } } } } },
          "401": { "description": "Clé requise" }
        }
      }
    },
    "/account": {
      "get": {
        "tags": ["Compte & clés"],
        "summary": "Vue complète du compte (plan, quota, crédits, abo, liste des clés)",
        "operationId": "account",
        "security": [{ "BearerAuth": [] }, { "ApiKeyHeader": [] }],
        "responses": {
          "200": { "description": "Compte" },
          "401": { "description": "Auth requise" }
        }
      }
    },
    "/account/seals": {
      "get": {
        "tags": ["Compte & clés"],
        "summary": "Historique des scels du compte (50 derniers)",
        "operationId": "accountSeals",
        "security": [{ "BearerAuth": [] }, { "ApiKeyHeader": [] }],
        "responses": {
          "200": { "description": "Historique", "content": { "application/json": { "schema": { "type": "object", "properties": { "ok": { "type": "boolean" }, "count": { "type": "integer" }, "seals": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "integer" }, "path": { "type": "string" }, "mode": { "type": "string" }, "ts": { "type": "string" } } } } } } } } },
          "401": { "description": "Auth requise" }
        }
      }
    },
    "/account/keys": {
      "post": {
        "tags": ["Compte & clés"],
        "summary": "Ajouter une clé API au compte (réservé login fichier-clé)",
        "operationId": "addKey",
        "security": [{ "BearerAuth": [] }],
        "responses": {
          "201": { "description": "Clé ajoutée", "content": { "application/json": { "schema": { "type": "object", "properties": { "ok": { "type": "boolean" }, "key": { "type": "string" }, "prefix": { "type": "string" }, "key_id": { "type": "integer" } } } } } },
          "403": { "description": "Réservé au login fichier .key" }
        }
      }
    },
    "/account/keys/revoke": {
      "post": {
        "tags": ["Compte & clés"],
        "summary": "Révoquer une clé API (pas la clé maître)",
        "operationId": "revokeKey",
        "security": [{ "BearerAuth": [] }],
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": ["key_id"], "properties": { "key_id": { "type": "integer" } } } } } },
        "responses": {
          "200": { "description": "Révoquée", "content": { "application/json": { "schema": { "type": "object", "properties": { "ok": { "type": "boolean" }, "revoked": { "type": "integer" } } } } } },
          "400": { "description": "Clé maître non révocable / key_id requis" },
          "403": { "description": "Réservé au login fichier .key" },
          "404": { "description": "Clé introuvable" }
        }
      }
    },
    "/account/keyfile/rotate": {
      "post": {
        "tags": ["Compte & clés"],
        "summary": "Rotation de la clé maître : nouveau fichier .key + nouvelle clé, ancienne désactivée",
        "operationId": "rotateKeyfile",
        "security": [{ "BearerAuth": [] }],
        "responses": {
          "201": { "description": "Nouvelle clé maître", "content": { "application/json": { "schema": { "type": "object", "properties": { "ok": { "type": "boolean" }, "key": { "type": "string" }, "prefix": { "type": "string" }, "keyfile": { "type": "string" }, "keyfile_name": { "type": "string" }, "keyfile_warning": { "type": "string" } } } } } },
          "403": { "description": "Réservé au login fichier .key" }
        }
      }
    },
    "/webhooks": {
      "post": {
        "tags": ["Compte & clés"],
        "summary": "Abonner un webhook sortant (déclenché à chaque scel ancré)",
        "operationId": "createWebhook",
        "security": [{ "BearerAuth": [] }],
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": ["url"], "properties": { "url": { "type": "string", "format": "uri", "description": "http(s) public uniquement (anti-SSRF)" }, "events": { "type": "string", "default": "seal" } } } } } },
        "responses": {
          "201": { "description": "Webhook créé", "content": { "application/json": { "schema": { "type": "object", "properties": { "ok": { "type": "boolean" }, "id": { "type": "integer" }, "url": { "type": "string" }, "events": { "type": "string" }, "verify": { "type": "object", "properties": { "alg": { "type": "string" }, "public_key": { "type": "string" }, "note": { "type": "string" } } } } } } } },
          "400": { "description": "URL invalide (anti-SSRF)" },
          "403": { "description": "Réservé au login fichier .key" }
        }
      },
      "get": {
        "tags": ["Compte & clés"],
        "summary": "Lister les webhooks du compte (+ dernier statut de livraison)",
        "operationId": "listWebhooks",
        "security": [{ "BearerAuth": [] }],
        "responses": {
          "200": { "description": "Liste", "content": { "application/json": { "schema": { "type": "object", "properties": { "ok": { "type": "boolean" }, "count": { "type": "integer" }, "webhooks": { "type": "array", "items": { "type": "object" } } } } } } },
          "403": { "description": "Réservé au login fichier .key" }
        }
      }
    },
    "/webhooks/delete": {
      "post": {
        "tags": ["Compte & clés"],
        "summary": "Supprimer un webhook",
        "operationId": "deleteWebhook",
        "security": [{ "BearerAuth": [] }],
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": ["id"], "properties": { "id": { "type": "integer" } } } } } },
        "responses": {
          "200": { "description": "Supprimé", "content": { "application/json": { "schema": { "type": "object", "properties": { "ok": { "type": "boolean" }, "deleted": { "type": "integer" } } } } } },
          "403": { "description": "Réservé au login fichier .key" },
          "404": { "description": "Webhook introuvable" }
        }
      }
    },
    "/chain": {
      "get": {
        "tags": ["Méta"],
        "summary": "État de la chaîne d'audit immuable + ancrage Hedera",
        "operationId": "chain",
        "responses": {
          "200": { "description": "Chaîne", "content": { "application/json": { "schema": { "type": "object", "properties": { "ok": { "type": "boolean" }, "chain_length": { "type": "integer" }, "last_entry_hash": { "type": "string" }, "anchor": { "type": "object", "properties": { "network": { "type": "string" }, "topic": { "type": "string" }, "verify": { "type": "string" } } } } } } } }
        }
      }
    },
    "/pubkey": {
      "get": {
        "tags": ["Méta"],
        "summary": "Clé publique Ed25519 du mode local (pour vérifier une preuve sans serveur)",
        "operationId": "pubkey",
        "responses": {
          "200": { "description": "Clé publique", "content": { "application/json": { "schema": { "type": "object", "properties": { "alg": { "type": "string" }, "public_key": { "type": "string" }, "verify": { "type": "string" } } } } } }
        }
      }
    },
    "/proof/{digest}": {
      "get": {
        "tags": ["Méta"],
        "summary": "Récupérer une preuve stockée (consentement/agent/incident) par digest",
        "operationId": "getProof",
        "parameters": [
          { "name": "digest", "in": "path", "required": true, "schema": { "type": "string" }, "description": "SHA-256 (64 hex)" }
        ],
        "responses": {
          "200": { "description": "Preuve", "content": { "application/json": { "schema": { "type": "object", "properties": { "ok": { "type": "boolean" }, "digest": { "type": "string" }, "type": { "type": "string" }, "record": { "type": "object" }, "canonical_json": { "type": "string" }, "proof": { "type": "object" }, "anchor": { "type": "object" }, "mode": { "type": "string" }, "ts": { "type": "string" }, "verify_url": { "type": "string" } } } } } },
          "404": { "description": "Preuve introuvable" }
        }
      }
    },
    "/checkout": {
      "post": {
        "tags": ["Facturation"],
        "summary": "Créer une session Stripe Checkout (abonnement standard/pro ou pack de crédits)",
        "operationId": "checkout",
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": ["product", "email"], "properties": { "product": { "type": "string", "enum": ["standard", "pro", "pack100", "pack500"] }, "email": { "type": "string", "format": "email" }, "account_id": { "type": "integer" }, "key_id": { "type": "integer" } } } } } },
        "responses": {
          "200": { "description": "URL de paiement", "content": { "application/json": { "schema": { "type": "object", "properties": { "ok": { "type": "boolean" }, "checkout_url": { "type": "string" }, "session_id": { "type": "string" }, "product": { "type": "string" }, "mode": { "type": "string", "enum": ["subscription", "payment"] } } } } } },
          "400": { "description": "product inconnu / email requis" },
          "401": { "description": "account_id requis" },
          "502": { "description": "Erreur Stripe" }
        }
      }
    },
    "/checkout/verticale": {
      "post": {
        "tags": ["Facturation"],
        "summary": "Checkout Stripe pour une verticale réglementaire (prospect froid, sans compte préalable)",
        "operationId": "checkoutVerticale",
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": ["verticale", "email"], "properties": { "verticale": { "type": "string", "description": "Slug de verticale (ex: cbam, eudr, dora, esg, methane, ai-act, mica, sla…)" }, "email": { "type": "string", "format": "email" } } } } } },
        "responses": {
          "200": { "description": "URL de paiement", "content": { "application/json": { "schema": { "type": "object", "properties": { "ok": { "type": "boolean" }, "checkout_url": { "type": "string" }, "session_id": { "type": "string" }, "verticale": { "type": "string" }, "mode": { "type": "string" } } } } } },
          "400": { "description": "verticale inconnue / email requis" },
          "500": { "description": "Prix Stripe non configuré" },
          "502": { "description": "Erreur Stripe" }
        }
      }
    },
    "/delivery": {
      "get": {
        "tags": ["Facturation"],
        "summary": "Remise de la config après paiement (show-once, TTL 24h)",
        "operationId": "delivery",
        "parameters": [
          { "name": "session_id", "in": "query", "required": true, "schema": { "type": "string" } }
        ],
        "responses": {
          "200": { "description": "Clé + fichier .key (une seule fois)", "content": { "application/json": { "schema": { "type": "object", "properties": { "ok": { "type": "boolean" }, "verticale": { "type": "string" }, "email": { "type": "string" }, "api_key": { "type": "string" }, "keyfile": { "type": "string" }, "keyfile_name": { "type": "string" }, "note": { "type": "string" } } } } } },
          "400": { "description": "session_id requis" },
          "404": { "description": "Config déjà récupérée ou introuvable" },
          "410": { "description": "Lien expiré (24h)" }
        }
      }
    },
    "/contrefacon": {
      "post": {
        "tags": ["Verticales"],
        "summary": "Contrefaçon inversée : fetch sécurisé d'une URL + hash + comparaison optionnelle",
        "operationId": "contrefacon",
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": ["url"], "properties": { "url": { "type": "string", "format": "uri" }, "digest": { "type": "string", "description": "SHA-256 de référence (64 hex)" }, "proof": { "type": "object", "description": "Ou une preuve contenant un digest" } } } } } },
        "responses": {
          "200": { "description": "Résultat", "content": { "application/json": { "schema": { "type": "object", "properties": { "ok": { "type": "boolean" }, "url": { "type": "string" }, "online_digest": { "type": "string" }, "size": { "type": "integer" }, "content_type": { "type": "string" }, "status": { "type": "integer" }, "fetched_at": { "type": "string" }, "reference_digest": { "type": "string" }, "match": { "type": "boolean" }, "verdict": { "type": "string", "enum": ["copie_exacte", "contenu_different", "aucune_reference"] } } } } } },
          "400": { "description": "url requis / digest invalide" },
          "422": { "description": "Fetch impossible" }
        }
      }
    },
    "/c2pa": {
      "post": {
        "tags": ["Verticales"],
        "summary": "Preuve d'origine de contenu (C2PA / Content Credentials — humain vs IA générative)",
        "operationId": "c2pa",
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": ["manifest"], "properties": { "manifest": { "oneOf": [ { "type": "object" }, { "type": "string" } ], "description": "Manifest C2PA / Content Credentials" }, "mode": { "type": "string", "enum": ["local", "eidas"], "default": "local" }, "tsa": { "type": "string" }, "content_hash": { "type": "string", "description": "SHA-256 (64 hex) du contenu media" }, "origin": { "type": "string", "enum": ["human", "ai", "unknown"] } } } } } },
        "responses": {
          "200": { "description": "Manifest scellé", "content": { "application/json": { "schema": { "type": "object", "properties": { "ok": { "type": "boolean" }, "proof": { "$ref": "#/components/schemas/Proof" }, "c2pa": { "type": "object", "properties": { "origin": { "type": "string" }, "content_hash": { "type": "string" }, "manifest_digest": { "type": "string" }, "declaration": { "type": "string" } } }, "anchor": { "$ref": "#/components/schemas/Anchor" } } } } } },
          "400": { "description": "manifest requis / content_hash invalide" }
        }
      }
    },
    "/consent": {
      "post": {
        "tags": ["Verticales"],
        "summary": "Preuve de consentement scellée + ancrée (RGPD art.7)",
        "operationId": "consent",
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": ["purpose", "consent"], "properties": { "purpose": { "type": "string" }, "consent": { "type": "string", "description": "Alias statement" }, "email": { "type": "string" }, "identity": { "type": "object" }, "consent_mode": { "type": "string", "default": "text" }, "lang": { "type": "string", "default": "fr" }, "granted": { "type": "boolean", "default": true }, "seal_mode": { "type": "string", "enum": ["local", "eidas"], "default": "local" }, "tsa": { "type": "string" } } } } } },
        "responses": {
          "200": { "description": "Consentement scellé", "content": { "application/json": { "schema": { "type": "object", "properties": { "ok": { "type": "boolean" }, "record": { "$ref": "#/components/schemas/Record" }, "proof": { "$ref": "#/components/schemas/Proof" }, "anchor": { "$ref": "#/components/schemas/Anchor" } } } } } },
          "400": { "description": "purpose/consent requis" }
        }
      }
    },
    "/agent": {
      "post": {
        "tags": ["Verticales"],
        "summary": "Preuve d'exécution d'un agent IA (AI Act art.12)",
        "operationId": "agent",
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": ["agent_id", "action"], "properties": { "agent_id": { "type": "string" }, "action": { "type": "string" }, "decision": { "type": "string" }, "input_digest": { "type": "string" }, "context": { "type": "object" }, "seal_mode": { "type": "string", "enum": ["local", "eidas"], "default": "local" }, "tsa": { "type": "string" } } } } } },
        "responses": {
          "200": { "description": "Action scellée", "content": { "application/json": { "schema": { "type": "object", "properties": { "ok": { "type": "boolean" }, "record": { "$ref": "#/components/schemas/Record" }, "proof": { "$ref": "#/components/schemas/Proof" }, "anchor": { "$ref": "#/components/schemas/Anchor" } } } } } },
          "400": { "description": "agent_id/action requis" }
        }
      }
    },
    "/incident": {
      "post": {
        "tags": ["Verticales"],
        "summary": "Timeline d'incident NIS2 — chaîne d'événements scellée (détection → remédiation)",
        "operationId": "incident",
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": ["incident_id", "phase"], "properties": { "incident_id": { "type": "string" }, "phase": { "type": "string", "description": "Alias event. Ex: detection/qualification/notification/remediation" }, "description": { "type": "string" }, "severity": { "type": "string" }, "seal_mode": { "type": "string", "enum": ["local", "eidas"], "default": "local" }, "tsa": { "type": "string" } } } } } },
        "responses": {
          "200": { "description": "Événement scellé", "content": { "application/json": { "schema": { "type": "object", "properties": { "ok": { "type": "boolean" }, "record": { "$ref": "#/components/schemas/Record" }, "proof": { "$ref": "#/components/schemas/Proof" }, "anchor": { "$ref": "#/components/schemas/Anchor" } } } } } },
          "400": { "description": "incident_id/phase requis" }
        }
      }
    },
    "/modes": {
      "get": {
        "tags": ["Méta"],
        "summary": "Modes de scellement disponibles",
        "operationId": "modes",
        "responses": { "200": { "description": "Liste des modes" } }
      }
    },
    "/plans": {
      "get": {
        "tags": ["Méta"],
        "summary": "Plans, packs de crédits et prix unitaires",
        "operationId": "plans",
        "responses": {
          "200": { "description": "Tarifs", "content": { "application/json": { "schema": { "type": "object", "properties": { "plans": { "type": "object" }, "credit_packs": { "type": "object" }, "unit_standard_eur": { "type": "number", "example": 0.2 }, "unit_eidas_eur": { "type": "number", "example": 0.3 } } } } } }
        }
      }
    },
    "/health": {
      "get": {
        "tags": ["Méta"],
        "summary": "État du service",
        "operationId": "health",
        "responses": {
          "200": { "description": "OK", "content": { "application/json": { "schema": { "type": "object", "properties": { "status": { "type": "string" }, "service": { "type": "string" }, "scel_standard_eur": { "type": "number" }, "scel_eidas_eur": { "type": "number" } } } } } }
        }
      }
    }
  }
}
