{
  "openapi": "3.1.0",
  "info": {
    "title": "Checkwise API",
    "version": "1.0.0",
    "summary": "Vérification d'informations avec verdicts sourcés et sources notées à l'avance.",
    "description": "L'API Checkwise vérifie une affirmation, un article, une image ou un domaine, et renvoie un verdict sourcé.\n\nLe modèle de langage ne décide pas du verdict. Il extrait les affirmations et lit les sources trouvées ;\nle verdict est ensuite calculé à partir des verdicts source par source, chaque source étant pondérée par\nune note de fiabilité établie avant la vérification, selon une méthodologie publique.\n\nMéthodologie de notation : https://checkwise.ai/rating-methodology\nBase publique des sites notés : https://checkwise.ai/sites\n\nHébergé en Europe.",
    "contact": {
      "name": "Checkwise",
      "url": "https://checkwise.ai/contact"
    },
    "termsOfService": "https://checkwise.ai/terms"
  },
  "servers": [
    {
      "url": "https://developer.checkwise.ai/v1",
      "description": "Production"
    }
  ],
  "security": [
    {
      "ApiKeyHeader": []
    },
    {
      "BearerKey": []
    }
  ],
  "tags": [
    {
      "name": "Fact-check",
      "description": "Vérification d'une affirmation, d'un article ou d'une image"
    },
    {
      "name": "Notation de sites",
      "description": "Fiabilité d'un domaine, de A à D"
    },
    {
      "name": "Images",
      "description": "Détection d'images générées par IA"
    }
  ],
  "paths": {
    "/check": {
      "post": {
        "tags": [
          "Fact-check"
        ],
        "summary": "Vérifier une affirmation, un article ou une image",
        "description": "Fournir exactement l'un des trois champs. Les affirmations vérifiables sont extraites, les sources recherchées, puis un verdict est calculé par affirmation et pour l'ensemble.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "text": {
                    "type": "string",
                    "description": "Texte libre contenant une ou plusieurs affirmations"
                  },
                  "url": {
                    "type": "string",
                    "format": "uri",
                    "description": "Adresse d'un article à vérifier"
                  },
                  "image": {
                    "type": "string",
                    "description": "Image encodée en base64"
                  }
                },
                "anyOf": [
                  {
                    "required": [
                      "text"
                    ]
                  },
                  {
                    "required": [
                      "url"
                    ]
                  },
                  {
                    "required": [
                      "image"
                    ]
                  }
                ]
              },
              "examples": {
                "texte": {
                  "value": {
                    "text": "Le taux de chômage en France est passé sous les 7 % en 2025."
                  }
                },
                "article": {
                  "value": {
                    "url": "https://example.org/un-article"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Vérification effectuée",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CheckResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationError"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/rate-site": {
      "post": {
        "tags": [
          "Notation de sites"
        ],
        "summary": "Obtenir la note de fiabilité d'un domaine",
        "description": "Renvoie la lettre de A à D et les dix critères. Un domaine déjà évalué est servi depuis la base, en quelques centaines de millisecondes : la réponse porte alors `cached: true` et elle est reproductible. Un domaine inconnu déclenche une analyse complète, plus lente.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "domain": {
                    "type": "string",
                    "description": "Nom de domaine, sans protocole ni chemin"
                  },
                  "url": {
                    "type": "string",
                    "format": "uri",
                    "description": "Adresse dont le domaine sera extrait"
                  },
                  "refresh": {
                    "type": "boolean",
                    "default": false,
                    "description": "Force une nouvelle analyse au lieu de servir la note existante"
                  }
                },
                "anyOf": [
                  {
                    "required": [
                      "domain"
                    ]
                  },
                  {
                    "required": [
                      "url"
                    ]
                  }
                ]
              },
              "examples": {
                "domaine": {
                  "value": {
                    "domain": "lemonde.fr"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Notation du domaine",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SiteRatingResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationError"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "description": "Domaine inconnu et non évaluable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/detect-ai-image": {
      "post": {
        "tags": [
          "Images"
        ],
        "summary": "Déterminer si une image a été générée par une IA",
        "description": "Renvoie un score de détection et une explication. Aucun détecteur n'étant fiable à 100 %, le résultat est un indice à croiser avec la provenance de l'image.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "image": {
                    "type": "string",
                    "description": "Image encodée en base64"
                  },
                  "url": {
                    "type": "string",
                    "format": "uri",
                    "description": "Adresse de l'image"
                  }
                },
                "anyOf": [
                  {
                    "required": [
                      "image"
                    ]
                  },
                  {
                    "required": [
                      "url"
                    ]
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Analyse effectuée",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ImageResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationError"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/lookup-sources": {
      "post": {
        "tags": [
          "Notation de sites"
        ],
        "summary": "Obtenir la note de plusieurs domaines en une requête",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "domains"
                ],
                "properties": {
                  "domains": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "Liste de domaines"
                  }
                }
              },
              "examples": {
                "liste": {
                  "value": {
                    "domains": [
                      "lemonde.fr",
                      "reuters.com"
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Notes des domaines demandés",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "scores": {
                      "type": "object",
                      "additionalProperties": true
                    },
                    "rate_limit": {
                      "$ref": "#/components/schemas/RateLimit"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "ApiKeyHeader": {
        "type": "apiKey",
        "in": "header",
        "name": "X-Checkwise-API-Key",
        "description": "Clé d'API. Le préfixe indique la provenance de la clé."
      },
      "BearerKey": {
        "type": "http",
        "scheme": "bearer",
        "description": "Même clé, transmise en `Authorization: Bearer <clé>`."
      }
    },
    "schemas": {
      "RateLimit": {
        "type": "object",
        "description": "État des crédits. Une vérification consomme un crédit.",
        "properties": {
          "credits_total": {
            "type": "integer"
          },
          "credits_remaining": {
            "type": "integer"
          }
        }
      },
      "Source": {
        "type": "object",
        "properties": {
          "url": {
            "type": "string",
            "format": "uri"
          },
          "organization": {
            "type": "string",
            "nullable": true
          },
          "summary": {
            "type": "string",
            "nullable": true,
            "description": "Ce que dit cette source à propos de l'affirmation"
          },
          "verdict": {
            "type": "string",
            "enum": [
              "true",
              "false",
              "mixed",
              "not_rated"
            ],
            "description": "Verdict de cette source prise isolément"
          },
          "site_rating": {
            "type": "string",
            "description": "Note de fiabilité du site, de A à D, ou mention indiquant qu'il n'est pas encore évalué"
          },
          "biases": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        }
      },
      "Claim": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "examples": [
              "c1"
            ]
          },
          "text": {
            "type": "string",
            "description": "L'affirmation telle qu'extraite"
          },
          "verdict": {
            "type": "string",
            "enum": [
              "true",
              "false",
              "mixed",
              "not_rated"
            ],
            "description": "Verdict calculé à partir des verdicts par source, jamais décidé par un modèle de langage seul."
          },
          "score": {
            "type": "integer",
            "minimum": 0,
            "maximum": 100,
            "description": "Solidité des preuves, en pourcentage"
          },
          "biases": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "sources_kept": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Source"
            },
            "description": "Sources retenues, cliquables"
          }
        }
      },
      "CheckResponse": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean"
          },
          "report_code": {
            "type": "string",
            "description": "Identifiant du rapport, consultable publiquement s'il a été rendu public"
          },
          "global_score": {
            "type": "integer",
            "minimum": 0,
            "maximum": 100
          },
          "global_verdict": {
            "type": "string",
            "enum": [
              "true",
              "false",
              "mixed",
              "not_rated"
            ]
          },
          "synthesis": {
            "type": "string",
            "nullable": true
          },
          "claims": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Claim"
            }
          },
          "processing_time_ms": {
            "type": "integer"
          },
          "metadata": {
            "type": "object",
            "properties": {
              "total_sources": {
                "type": "integer"
              },
              "input_type": {
                "type": "string",
                "enum": [
                  "text",
                  "url",
                  "image"
                ]
              },
              "credits_consumed": {
                "type": "integer"
              }
            }
          },
          "rate_limit": {
            "$ref": "#/components/schemas/RateLimit"
          }
        }
      },
      "SiteRatingResponse": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean"
          },
          "domain": {
            "type": "string"
          },
          "name": {
            "type": "string",
            "nullable": true
          },
          "categories": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "country_code": {
            "type": "string",
            "nullable": true
          },
          "region": {
            "type": "string",
            "nullable": true
          },
          "type": {
            "type": "string",
            "nullable": true
          },
          "language": {
            "type": "string",
            "nullable": true
          },
          "score": {
            "type": "integer",
            "minimum": 0,
            "maximum": 100
          },
          "summary": {
            "type": "string",
            "nullable": true
          },
          "verdict": {
            "type": "string",
            "nullable": true
          },
          "flags": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "criteria": {
            "type": "object",
            "description": "Les dix critères, notés sur dix, regroupés en quatre piliers : sécurité, transparence, rigueur, authenticité.",
            "additionalProperties": {
              "type": "object",
              "properties": {
                "score": {
                  "type": "integer",
                  "minimum": 0,
                  "maximum": 10
                },
                "verdict": {
                  "type": "string",
                  "nullable": true,
                  "description": "Justification, absente sur une réponse servie depuis la base"
                }
              }
            }
          },
          "cached": {
            "type": "boolean",
            "description": "Vrai si la note vient de la base plutôt que d'une nouvelle analyse"
          },
          "last_updated": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "rate_limit": {
            "$ref": "#/components/schemas/RateLimit"
          }
        }
      },
      "ImageResponse": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean"
          },
          "verdict": {
            "type": "string",
            "description": "Conclusion de l'analyse"
          },
          "ai_score": {
            "type": "number",
            "description": "Score de détection"
          },
          "is_ai": {
            "type": "boolean"
          },
          "confidence": {
            "type": "string",
            "nullable": true
          },
          "explanation": {
            "type": "string",
            "nullable": true
          },
          "generator": {
            "type": "string",
            "nullable": true,
            "description": "Générateur identifié, quand il l'est"
          },
          "heatmap": {
            "type": "string",
            "nullable": true,
            "description": "Carte des zones ayant pesé, encodée en base64"
          },
          "processing_time_ms": {
            "type": "integer"
          },
          "rate_limit": {
            "$ref": "#/components/schemas/RateLimit"
          }
        }
      },
      "Error": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean",
            "examples": [
              false
            ]
          },
          "error": {
            "type": "string",
            "examples": [
              "UNAUTHORIZED"
            ]
          },
          "message": {
            "type": "string"
          }
        }
      }
    },
    "responses": {
      "Unauthorized": {
        "description": "Clé d'API absente ou invalide",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "ValidationError": {
        "description": "Requête incomplète ou mal formée",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "InternalError": {
        "description": "Erreur interne",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      }
    }
  }
}