{
  "openapi": "3.1.0",
  "info": {
    "title": "ZAYKO AI Lab API",
    "version": "1.0.0",
    "description": "Scanner d'enquête on-chain Solana en JSON : score de risque, filtre de listing, scan par lot, pare-feu de transaction, flux d'événements et rapports d'audit signés. Authentification par clé API, quota mensuel et limite de débit par clé.",
    "contact": {
      "name": "ZAYKO AI Lab",
      "email": "contact@labzayko.com",
      "url": "https://labzayko.com/enterprise/docs"
    }
  },
  "servers": [
    {
      "url": "https://labzayko.com",
      "description": "Production"
    },
    {
      "url": "https://project--95462de0-d34d-43ed-8465-db9987a4db07-dev.lovable.app",
      "description": "Préproduction"
    }
  ],
  "security": [
    {
      "bearerAuth": []
    },
    {
      "apiKeyHeader": []
    }
  ],
  "tags": [
    {
      "name": "Risque",
      "description": "Score de sécurité et données mesurées d'un token."
    },
    {
      "name": "Listing",
      "description": "Application de règles de listing."
    },
    {
      "name": "Lot",
      "description": "Scan par lot asynchrone."
    },
    {
      "name": "Firewall",
      "description": "Simulation d'une transaction avant signature."
    },
    {
      "name": "Événements",
      "description": "Flux d'événements de risque."
    },
    {
      "name": "Audit",
      "description": "Rapports d'audit signés Ed25519."
    },
    {
      "name": "Facturation",
      "description": "Activation d'une offre après paiement en $ZAYKO."
    },
    {
      "name": "Flux temps réel",
      "description": "Flux SSE (pas de clé API, borné par adresse IP)."
    }
  ],
  "paths": {
    "/api/public/risk": {
      "get": {
        "tags": [
          "Risque"
        ],
        "operationId": "getRisk",
        "summary": "Score de risque d'un token",
        "description": "Verdict, score /100, liquidité, concentration du top 10 et test de vendabilité. Seul endpoint ouvert aux clés d'essai (`zayko_trial_…`).",
        "parameters": [
          {
            "name": "mint",
            "in": "query",
            "required": true,
            "description": "Adresse du mint Solana (base58).",
            "schema": {
              "type": "string",
              "pattern": "^[1-9A-HJ-NP-Za-km-z]{32,44}$"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Score calculé.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "mint": {
                      "type": "string"
                    },
                    "score": {
                      "type": "integer",
                      "minimum": 0,
                      "maximum": 100
                    },
                    "verdict": {
                      "type": "string",
                      "examples": [
                        "RISQUE FAIBLE",
                        "PRUDENCE",
                        "HAUT RISQUE"
                      ]
                    },
                    "liquidityUsd": {
                      "type": [
                        "number",
                        "null"
                      ]
                    },
                    "topHoldersPct": {
                      "type": [
                        "number",
                        "null"
                      ]
                    },
                    "sellable": {
                      "type": [
                        "boolean",
                        "null"
                      ]
                    },
                    "timestamp": {
                      "type": "string",
                      "format": "date-time"
                    }
                  },
                  "required": [
                    "mint",
                    "score",
                    "verdict",
                    "timestamp"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Paramètre manquant ou invalide.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "401": {
            "description": "Clé API absente, invalide ou révoquée.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "402": {
            "description": "Offre expirée.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "429": {
            "description": "Quota mensuel atteint ou limite par minute dépassée.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "500": {
            "description": "Analyse impossible (RPC indisponible).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/api/public/listing-gate": {
      "get": {
        "tags": [
          "Listing"
        ],
        "operationId": "getListingGate",
        "summary": "Filtre de listing",
        "description": "Applique tes règles (liquidité minimale, concentration maximale, mint authority, honeypot, score, âge) et retourne une décision avec les preuves. Les règles se configurent sur /enterprise/listing-gate.",
        "parameters": [
          {
            "name": "mint",
            "in": "query",
            "required": true,
            "description": "Adresse du mint Solana (base58).",
            "schema": {
              "type": "string",
              "pattern": "^[1-9A-HJ-NP-Za-km-z]{32,44}$"
            }
          },
          {
            "name": "configId",
            "in": "query",
            "required": true,
            "description": "Identifiant de la configuration de règles.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Décision de listing.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "mint": {
                      "type": "string"
                    },
                    "decision": {
                      "type": "string",
                      "enum": [
                        "APPROVE",
                        "MANUAL_REVIEW",
                        "REJECT"
                      ]
                    },
                    "score": {
                      "type": "integer"
                    },
                    "reasons": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Paramètre manquant ou invalide.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "401": {
            "description": "Clé API absente, invalide ou révoquée.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "402": {
            "description": "Offre expirée.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "429": {
            "description": "Quota mensuel atteint ou limite par minute dépassée.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "500": {
            "description": "Analyse impossible (RPC indisponible).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/api/public/bulk-scan": {
      "post": {
        "tags": [
          "Lot"
        ],
        "operationId": "createBulkScan",
        "summary": "Lancer un scan par lot",
        "description": "Jusqu'à 50 mints par job. Retourne un identifiant de job à interroger ensuite.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "mints": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "minItems": 1,
                    "maxItems": 50
                  },
                  "label": {
                    "type": "string",
                    "description": "Nom libre du lot."
                  }
                },
                "required": [
                  "mints"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Job créé.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "jobId": {
                      "type": "string",
                      "format": "uuid"
                    },
                    "total": {
                      "type": "integer"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Paramètre manquant ou invalide.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "401": {
            "description": "Clé API absente, invalide ou révoquée.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "402": {
            "description": "Offre expirée.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "429": {
            "description": "Quota mensuel atteint ou limite par minute dépassée.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "500": {
            "description": "Analyse impossible (RPC indisponible).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/api/public/bulk-scan/jobs/{jobId}": {
      "get": {
        "tags": [
          "Lot"
        ],
        "operationId": "getBulkScanJob",
        "summary": "Avancement d'un job de lot",
        "parameters": [
          {
            "name": "jobId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "État du job et résultats disponibles.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "string",
                      "format": "uuid"
                    },
                    "status": {
                      "type": "string",
                      "examples": [
                        "queued",
                        "running",
                        "done"
                      ]
                    },
                    "total": {
                      "type": "integer"
                    },
                    "done": {
                      "type": "integer"
                    },
                    "results": {
                      "type": "array",
                      "items": {
                        "type": "object"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Paramètre manquant ou invalide.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "401": {
            "description": "Clé API absente, invalide ou révoquée.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "402": {
            "description": "Offre expirée.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "429": {
            "description": "Quota mensuel atteint ou limite par minute dépassée.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "500": {
            "description": "Analyse impossible (RPC indisponible).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/api/public/firewall": {
      "post": {
        "tags": [
          "Firewall"
        ],
        "operationId": "checkTransaction",
        "summary": "Vérifier une transaction avant signature",
        "description": "Simule la transaction on-chain sans la diffuser. Retourne un verdict, les findings, les programmes touchés et un bloc `execution` quand un swap est identifié. Ce qui n'est pas décodable reste `null`, jamais estimé.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "transaction": {
                    "type": "string",
                    "description": "Transaction non signée sérialisée en base64."
                  },
                  "expected": {
                    "type": "object",
                    "description": "Action annoncée par ton application, comparée au résultat simulé.",
                    "properties": {
                      "action": {
                        "type": "string"
                      },
                      "mint": {
                        "type": "string"
                      },
                      "maxSolOut": {
                        "type": "number"
                      }
                    }
                  }
                },
                "required": [
                  "transaction"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Verdict de simulation.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "verdict": {
                      "type": "string",
                      "enum": [
                        "ALLOW",
                        "WARN",
                        "BLOCK",
                        "UNKNOWN"
                      ]
                    },
                    "risk": {
                      "type": "integer",
                      "minimum": 0,
                      "maximum": 100
                    },
                    "simulated": {
                      "type": "boolean"
                    },
                    "findings": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "code": {
                            "type": "string",
                            "enum": [
                              "authority_change",
                              "freeze_authority",
                              "delegation",
                              "unknown_program",
                              "unexpected_token_transfer",
                              "large_sol_outflow",
                              "outcome_differs",
                              "simulation_failed",
                              "sandwich_exposure",
                              "high_slippage",
                              "abnormal_priority_fee"
                            ]
                          },
                          "severity": {
                            "type": "string"
                          },
                          "title": {
                            "type": "string"
                          },
                          "detail": {
                            "type": "string"
                          }
                        }
                      }
                    },
                    "programs": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    },
                    "solDelta": {
                      "type": [
                        "number",
                        "null"
                      ]
                    },
                    "tokenDeltas": {
                      "type": "array",
                      "items": {
                        "type": "object"
                      }
                    },
                    "execution": {
                      "type": [
                        "object",
                        "null"
                      ],
                      "properties": {
                        "isSwap": {
                          "type": "boolean"
                        },
                        "dexName": {
                          "type": [
                            "string",
                            "null"
                          ]
                        },
                        "sandwichExposure": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "enum": [
                            "high",
                            "medium",
                            "low",
                            null
                          ]
                        },
                        "slippagePct": {
                          "type": [
                            "number",
                            "null"
                          ]
                        },
                        "expectedOutUi": {
                          "type": [
                            "number",
                            "null"
                          ]
                        },
                        "worstOutUi": {
                          "type": [
                            "number",
                            "null"
                          ]
                        },
                        "mevProtection": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "enum": [
                            "on",
                            "partial",
                            "off",
                            null
                          ]
                        },
                        "jitoTipSol": {
                          "type": [
                            "number",
                            "null"
                          ]
                        },
                        "dontFront": {
                          "type": "boolean"
                        },
                        "priorityFee": {
                          "type": [
                            "object",
                            "null"
                          ]
                        },
                        "recommendations": {
                          "type": "array",
                          "items": {
                            "type": "object"
                          }
                        }
                      }
                    }
                  },
                  "required": [
                    "verdict",
                    "risk",
                    "simulated",
                    "findings"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Paramètre manquant ou invalide.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "401": {
            "description": "Clé API absente, invalide ou révoquée.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "402": {
            "description": "Offre expirée.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "429": {
            "description": "Quota mensuel atteint ou limite par minute dépassée.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "500": {
            "description": "Analyse impossible (RPC indisponible).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/api/public/events": {
      "get": {
        "tags": [
          "Événements"
        ],
        "operationId": "listRiskEvents",
        "summary": "Flux d'événements de risque",
        "description": "Historique des événements détectés en continu. Utilise `since` (ou le `cursor` renvoyé) pour ne récupérer que le nouveau.",
        "parameters": [
          {
            "name": "mint",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "kind",
            "in": "query",
            "description": "Type d'événement.",
            "schema": {
              "type": "string",
              "examples": [
                "risk.changed",
                "liquidity.drop",
                "whale.movement",
                "holder.concentration",
                "deployer.detected",
                "authority.changed",
                "abnormal.activity",
                "launch.detected",
                "listing_gate.blocked"
              ]
            }
          },
          {
            "name": "severity",
            "in": "query",
            "description": "Gravité minimale retenue.",
            "schema": {
              "type": "string",
              "examples": [
                "info",
                "warning",
                "critical"
              ]
            }
          },
          {
            "name": "since",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 200,
              "default": 50
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Événements du plus récent au plus ancien.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "events": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "string"
                          },
                          "mint": {
                            "type": "string"
                          },
                          "kind": {
                            "type": "string"
                          },
                          "severity": {
                            "type": "string"
                          },
                          "title": {
                            "type": "string"
                          },
                          "message": {
                            "type": "string"
                          },
                          "score": {
                            "type": [
                              "integer",
                              "null"
                            ]
                          },
                          "previousScore": {
                            "type": [
                              "integer",
                              "null"
                            ]
                          },
                          "liquidityUsd": {
                            "type": [
                              "number",
                              "null"
                            ]
                          },
                          "previousLiquidityUsd": {
                            "type": [
                              "number",
                              "null"
                            ]
                          },
                          "data": {
                            "type": "object"
                          },
                          "createdAt": {
                            "type": "string",
                            "format": "date-time"
                          }
                        }
                      }
                    },
                    "count": {
                      "type": "integer"
                    },
                    "cursor": {
                      "type": [
                        "string",
                        "null"
                      ]
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Paramètre manquant ou invalide.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "401": {
            "description": "Clé API absente, invalide ou révoquée.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "402": {
            "description": "Offre expirée.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "429": {
            "description": "Quota mensuel atteint ou limite par minute dépassée.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "500": {
            "description": "Analyse impossible (RPC indisponible).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/api/public/audit/{id}": {
      "get": {
        "tags": [
          "Audit"
        ],
        "operationId": "verifyAuditReport",
        "summary": "Vérifier un rapport d'audit signé",
        "description": "Aucune clé API requise : un rapport doit pouvoir être contrôlé par n'importe qui. Retourne le document canonique, son empreinte SHA-256, la signature Ed25519, la clé publique et le résultat de la revérification serveur. Réponse mise en cache 5 minutes, 120 vérifications par adresse IP toutes les 10 minutes.",
        "security": [],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Rapport signé et vérification.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "reportId": {
                      "type": "string",
                      "format": "uuid"
                    },
                    "issuedAt": {
                      "type": "string",
                      "format": "date-time"
                    },
                    "document": {
                      "type": "object"
                    },
                    "digest": {
                      "type": "string"
                    },
                    "signature": {
                      "type": "string"
                    },
                    "algorithm": {
                      "type": "string",
                      "const": "Ed25519"
                    },
                    "keyId": {
                      "type": "string"
                    },
                    "publicKey": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "verification": {
                      "type": "object",
                      "properties": {
                        "digestMatches": {
                          "type": "boolean"
                        },
                        "signatureValid": {
                          "type": "boolean"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Numéro de rapport invalide.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "404": {
            "description": "Rapport introuvable.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "429": {
            "description": "Trop de vérifications depuis cette adresse.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/api/public/enterprise-payment": {
      "post": {
        "tags": [
          "Facturation"
        ],
        "operationId": "confirmEnterprisePayment",
        "summary": "Activer une offre après paiement en $ZAYKO",
        "description": "La preuve d'authenticité est la transaction elle-même : elle est vérifiée on-chain et ne peut servir qu'une fois.",
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "keyId": {
                    "type": "string",
                    "format": "uuid"
                  },
                  "planId": {
                    "type": "string",
                    "format": "uuid"
                  },
                  "signature": {
                    "type": "string",
                    "description": "Signature de la transaction Solana."
                  }
                },
                "required": [
                  "keyId",
                  "planId",
                  "signature"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Offre activée.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean"
                    },
                    "expiresAt": {
                      "type": "string",
                      "format": "date-time"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Requête invalide ou paiement non conforme.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/api/public/live-feed": {
      "get": {
        "tags": [
          "Flux temps réel"
        ],
        "operationId": "streamLiveFeed",
        "summary": "Flux SSE des nouveaux tokens scorés",
        "description": "Server-Sent Events : chaque nouveau token Solana noté dès sa détection. Pas de clé API, 20 connexions par adresse IP toutes les 10 minutes.",
        "security": [],
        "responses": {
          "200": {
            "description": "Flux d'événements.",
            "content": {
              "text/event-stream": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "429": {
            "description": "Trop de connexions depuis cette adresse.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/api/public/scan-stream": {
      "get": {
        "tags": [
          "Flux temps réel"
        ],
        "operationId": "streamScan",
        "summary": "Enquête en direct sur une adresse (SSE)",
        "description": "Le dossier se remplit pièce par pièce au lieu d'attendre la fin de l'analyse. Pas de clé API, borné par adresse IP.",
        "security": [],
        "parameters": [
          {
            "name": "address",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Flux d'événements d'analyse.",
            "content": {
              "text/event-stream": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "429": {
            "description": "Trop d'enquêtes depuis cette adresse.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "`Authorization: Bearer zayko_xxxxxxxxxxxxxxxx`"
      },
      "apiKeyHeader": {
        "type": "apiKey",
        "in": "header",
        "name": "X-API-Key",
        "description": "Alternative à l'en-tête Authorization."
      }
    },
    "headers": {
      "X-Zayko-Quota-Limit": {
        "description": "Appels autorisés sur le mois.",
        "schema": {
          "type": "integer"
        }
      },
      "X-Zayko-Quota-Remaining": {
        "description": "Appels restants.",
        "schema": {
          "type": "integer"
        }
      },
      "X-Zayko-Quota-Reset": {
        "description": "Date de remise à zéro du quota.",
        "schema": {
          "type": "string"
        }
      },
      "X-Zayko-RateLimit-Limit": {
        "description": "Appels autorisés par minute.",
        "schema": {
          "type": "integer"
        }
      },
      "X-Zayko-Quota-Warning": {
        "description": "Présent à partir de 80 % du quota.",
        "schema": {
          "type": "string"
        }
      }
    }
  }
}