{
  "openapi": "3.1.0",
  "info": {
    "title": "Web Resurrect API",
    "version": "1.0.0",
    "description": "API REST pour automatiser la résurrection de domaines expirés : récupération des URLs archivées, scraping du contenu, réécriture IA, génération d'images et publication sur WordPress.\n\n## Authentification\n\nToutes les requêtes doivent inclure une clé API dans le header `Authorization` :\n\n```\nAuthorization: Bearer wr_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n```\n\nCréez vos clés API depuis votre [tableau de bord](https://web-resurrect.com/dashboard).\n\n## Opérations asynchrones\n\nLes opérations longues (scraping, réécriture, publication) retournent un `job_id`. Consultez l'état du job via `GET /api/v1/jobs/{id}`.\n\n## Crédits\n\n| Action | Coût |\n|--------|------|\n| Création de projet + récupération URLs | Gratuit |\n| Enrichissement Haloscan (trafic, mots-clés) | Gratuit |\n| Enrichissement Majestic (backlinks) | 10 crédits |\n| Scraping d'une page | 1 crédit |\n| Réécriture basique | 1 crédit |\n| Réécriture Wisewand | 5 crédits (1 avec votre clé) |\n| Génération d'image | 1 crédit |\n| Catégorisation IA | Gratuit |\n| Publication WordPress | Gratuit |\n\n## Connexion WordPress\n\nDeux modes supportés, détectés automatiquement :\n- **Plugin** (recommandé) : installez le Web Resurrect Connector plugin\n- **Basic Auth** : nom d'utilisateur + mot de passe d'application WordPress",
    "contact": {
      "email": "contact@web-resurrect.com",
      "url": "https://web-resurrect.com"
    }
  },
  "servers": [
    {
      "url": "https://web-resurrect.com",
      "description": "Production"
    }
  ],
  "security": [
    {
      "BearerAuth": []
    }
  ],
  "components": {
    "securitySchemes": {
      "BearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "Clé API au format `wr_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx`"
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "properties": {
          "error": {
            "type": "object",
            "properties": {
              "code": { "type": "string", "example": "VALIDATION_ERROR" },
              "message": { "type": "string", "example": "Validation error: domain - Domain is required" },
              "details": { "type": "object" }
            }
          }
        }
      },
      "JobStatus": {
        "type": "object",
        "properties": {
          "id": { "type": "string", "format": "uuid" },
          "type": { "type": "string" },
          "status": { "type": "string", "enum": ["pending", "processing", "completed", "failed", "cancelled"] },
          "progress": {
            "type": "object",
            "nullable": true,
            "properties": {
              "total": { "type": "integer" },
              "processed": { "type": "integer" },
              "failed": { "type": "integer" },
              "percentage": { "type": "integer" }
            }
          },
          "credits": {
            "type": "object",
            "properties": {
              "reserved": { "type": "integer" },
              "used": { "type": "integer" },
              "refunded": { "type": "integer" }
            }
          },
          "result": { "type": "object", "nullable": true },
          "error": { "type": "string", "nullable": true },
          "created_at": { "type": "string", "format": "date-time" },
          "started_at": { "type": "string", "format": "date-time", "nullable": true },
          "completed_at": { "type": "string", "format": "date-time", "nullable": true }
        }
      },
      "Page": {
        "type": "object",
        "properties": {
          "id": { "type": "string", "format": "uuid" },
          "url": { "type": "string" },
          "archive_url": { "type": "string" },
          "title": { "type": "string", "nullable": true },
          "status": { "type": "string", "enum": ["pending", "scraped", "rewritten", "rewriting", "published", "scrape_failed", "empty"] },
          "is_scraped": { "type": "boolean" },
          "is_rewritten": { "type": "boolean" },
          "posted_to_wordpress": { "type": "boolean" },
          "seo": {
            "type": "object",
            "properties": {
              "traffic": { "type": "integer", "nullable": true },
              "keywords": { "type": "integer", "nullable": true },
              "backlinks": { "type": "integer", "nullable": true }
            }
          },
          "featured_image_url": { "type": "string", "nullable": true },
          "created_at": { "type": "string", "format": "date-time" }
        }
      },
      "Pagination": {
        "type": "object",
        "properties": {
          "page": { "type": "integer" },
          "limit": { "type": "integer" },
          "total": { "type": "integer" },
          "totalPages": { "type": "integer" },
          "hasMore": { "type": "boolean" }
        }
      }
    }
  },
  "tags": [
    { "name": "Credits", "description": "Gestion du solde de crédits" },
    { "name": "Projects", "description": "Créer et gérer vos projets de résurrection" },
    { "name": "Pages", "description": "Consulter les pages récupérées d'un projet" },
    { "name": "Scraping", "description": "Extraire le contenu des pages archivées" },
    { "name": "SEO Enrichment", "description": "Enrichir un projet avec des données SEO (Haloscan, Majestic)" },
    { "name": "Rewriting", "description": "Réécrire le contenu avec l'IA" },
    { "name": "Image Generation", "description": "Générer des images à la une pour les articles" },
    { "name": "Categorization", "description": "Catégoriser automatiquement les articles via l'IA" },
    { "name": "WordPress", "description": "Configurer et publier sur WordPress (plugin ou Basic Auth)" },
    { "name": "Jobs", "description": "Suivre la progression des opérations asynchrones" },
    { "name": "Usage", "description": "Historique de consommation de crédits" }
  ],
  "paths": {
    "/api/v1/credits": {
      "get": {
        "tags": ["Credits"],
        "summary": "Consulter le solde de crédits",
        "responses": {
          "200": {
            "description": "Solde actuel",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": { "type": "boolean", "example": true },
                    "data": {
                      "type": "object",
                      "properties": {
                        "credits": { "type": "integer", "example": 4362 },
                        "email": { "type": "string", "example": "user@example.com" },
                        "member_since": { "type": "string", "format": "date-time" }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/projects": {
      "post": {
        "tags": ["Projects"],
        "summary": "Créer un projet",
        "description": "Crée un nouveau projet et lance automatiquement la récupération des URLs via la Wayback Machine. Retourne un `job_id` pour suivre la progression.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["domain"],
                "properties": {
                  "domain": { "type": "string", "example": "example.fr", "description": "Domaine expiré à analyser" },
                  "name": { "type": "string", "example": "Mon projet", "description": "Nom du projet (optionnel, utilise le domaine par défaut)" }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Projet créé, récupération des URLs en cours",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": { "type": "boolean", "example": true },
                    "data": {
                      "type": "object",
                      "properties": {
                        "project_id": { "type": "string", "format": "uuid" },
                        "domain": { "type": "string" },
                        "name": { "type": "string" },
                        "job_id": { "type": "string", "format": "uuid", "description": "Job de récupération des URLs" }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      },
      "get": {
        "tags": ["Projects"],
        "summary": "Lister les projets",
        "parameters": [
          { "name": "page", "in": "query", "schema": { "type": "integer", "default": 1 } },
          { "name": "limit", "in": "query", "schema": { "type": "integer", "default": 20, "maximum": 100 } }
        ],
        "responses": {
          "200": { "description": "Liste paginée des projets" }
        }
      }
    },
    "/api/v1/projects/{id}": {
      "get": {
        "tags": ["Projects"],
        "summary": "Détail d'un projet",
        "parameters": [
          { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } }
        ],
        "responses": { "200": { "description": "Détails du projet avec statistiques" } }
      },
      "delete": {
        "tags": ["Projects"],
        "summary": "Supprimer un projet",
        "description": "Supprime le projet et toutes ses pages (cascade).",
        "parameters": [
          { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } }
        ],
        "responses": { "200": { "description": "Projet supprimé" } }
      }
    },
    "/api/v1/projects/{id}/pages": {
      "get": {
        "tags": ["Pages"],
        "summary": "Lister les pages d'un projet",
        "description": "Chaque page renvoie un champ `source` : `wayback` (découverte via la Wayback Machine, scrapable) ou `haloscan` (découverte via Haloscan, pas de snapshot — uniquement réécriture Wisewand).",
        "parameters": [
          { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } },
          { "name": "status", "in": "query", "schema": { "type": "string", "enum": ["pending", "scraped", "empty", "failed", "rewritten", "published", "haloscan", "rewritable_wisewand"] }, "description": "Filtrer par statut. `haloscan` = pages Haloscan non encore réécrites. `rewritable_wisewand` = toutes pages éligibles à Wisewand (scrapées + Haloscan)." },
          { "name": "source", "in": "query", "schema": { "type": "string", "enum": ["wayback", "haloscan", "semrush"] }, "description": "Filtrer par origine de la page." },
          { "name": "has_data", "in": "query", "schema": { "type": "string", "enum": ["haloscan", "majestic", "any"] }, "description": "Ne garder que les pages avec données SEO." },
          { "name": "search", "in": "query", "schema": { "type": "string" }, "description": "Rechercher par URL ou titre" },
          { "name": "sort", "in": "query", "schema": { "type": "string", "enum": ["created_at", "total_traffic", "backlinks_count", "url", "title"] } },
          { "name": "order", "in": "query", "schema": { "type": "string", "enum": ["asc", "desc"], "default": "desc" } },
          { "name": "page", "in": "query", "schema": { "type": "integer", "default": 1 } },
          { "name": "limit", "in": "query", "schema": { "type": "integer", "default": 50, "maximum": 100 } }
        ],
        "responses": {
          "200": {
            "description": "Liste paginée des pages",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": { "type": "boolean" },
                    "data": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "id": { "type": "string", "format": "uuid" },
                          "url": { "type": "string" },
                          "archive_url": { "type": "string", "nullable": true },
                          "title": { "type": "string", "nullable": true },
                          "source": { "type": "string", "enum": ["wayback", "haloscan", "semrush"], "description": "Origine de la page. `haloscan` = pas de snapshot Wayback, Wisewand-only." },
                          "top_keywords": { "type": "string", "nullable": true, "description": "Mots-clés SEO classés (Haloscan), liste séparée par virgules." },
                          "status": { "type": "string" },
                          "is_scraped": { "type": "boolean" },
                          "is_rewritten": { "type": "boolean" },
                          "wisewand_status": { "type": "string", "nullable": true },
                          "posted_to_wordpress": { "type": "boolean" },
                          "seo": {
                            "type": "object",
                            "properties": {
                              "traffic": { "type": "integer", "nullable": true },
                              "keywords": { "type": "integer", "nullable": true },
                              "backlinks": { "type": "integer", "nullable": true }
                            }
                          }
                        }
                      }
                    },
                    "pagination": {
                      "type": "object",
                      "properties": {
                        "page": { "type": "integer" },
                        "limit": { "type": "integer" },
                        "total": { "type": "integer" },
                        "totalPages": { "type": "integer" },
                        "hasMore": { "type": "boolean" }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/pages/{id}": {
      "get": {
        "tags": ["Pages"],
        "summary": "Détail d'une page",
        "parameters": [
          { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } }
        ],
        "responses": { "200": { "description": "Détails complets de la page (scrape, rewrite, WordPress, SEO)" } }
      }
    },
    "/api/v1/pages/{id}/content": {
      "get": {
        "tags": ["Pages"],
        "summary": "Contenu scrapé d'une page",
        "parameters": [
          { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } }
        ],
        "responses": { "200": { "description": "Contenu HTML et texte de la page scrapée" } }
      }
    },
    "/api/v1/pages/{id}/rewritten": {
      "get": {
        "tags": ["Pages"],
        "summary": "Contenu réécrit d'une page",
        "parameters": [
          { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } }
        ],
        "responses": { "200": { "description": "Contenu réécrit" } }
      }
    },
    "/api/v1/scrape": {
      "post": {
        "tags": ["Scraping"],
        "summary": "Scraper une page",
        "description": "Extrait le contenu d'une page archivée sur la Wayback Machine. Coût : 1 crédit.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["page_id"],
                "properties": {
                  "page_id": { "type": "string", "format": "uuid" },
                  "content_type": { "type": "string", "enum": ["article", "product", "productList", "jina"], "default": "article" }
                }
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Scraping lancé",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": { "type": "boolean" },
                    "data": {
                      "type": "object",
                      "properties": {
                        "job_id": { "type": "string", "format": "uuid" },
                        "status": { "type": "string", "example": "pending" },
                        "page_id": { "type": "string", "format": "uuid" },
                        "credits_used": { "type": "integer", "example": 1 }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/scrape/bulk": {
      "post": {
        "tags": ["Scraping"],
        "summary": "Scraper plusieurs pages",
        "description": "Scrape en lot. Coût : 1 crédit par page.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["page_ids"],
                "properties": {
                  "page_ids": { "type": "array", "items": { "type": "string", "format": "uuid" }, "maxItems": 100 },
                  "content_type": { "type": "string", "default": "article" }
                }
              }
            }
          }
        },
        "responses": { "202": { "description": "Scraping en lot lancé" } }
      }
    },
    "/api/v1/stats/enrich": {
      "post": {
        "tags": ["SEO Enrichment"],
        "summary": "Enrichir un projet avec des données SEO",
        "description": "Lance l'enrichissement Haloscan (trafic, mots-clés — gratuit) et/ou Majestic (backlinks — 10 crédits).",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["project_id"],
                "properties": {
                  "project_id": { "type": "string", "format": "uuid" },
                  "sources": {
                    "type": "array",
                    "items": { "type": "string", "enum": ["haloscan", "majestic"] },
                    "default": ["haloscan"],
                    "description": "Sources de données. Haloscan = gratuit, Majestic = 10 crédits."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Enrichissement lancé",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": { "type": "boolean" },
                    "data": {
                      "type": "object",
                      "properties": {
                        "job_id": { "type": "string", "format": "uuid" },
                        "sources": { "type": "array", "items": { "type": "string" } },
                        "credits_used": { "type": "integer" }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/rewrite": {
      "post": {
        "tags": ["Rewriting"],
        "summary": "Réécrire une page",
        "description": "Réécriture rapide via IA. Coût : 1 crédit.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["page_id"],
                "properties": {
                  "page_id": { "type": "string", "format": "uuid" },
                  "instructions": { "type": "string", "description": "Instructions personnalisées pour la réécriture", "example": "Réécrire en français courant pour un blog éducatif." }
                }
              }
            }
          }
        },
        "responses": { "202": { "description": "Réécriture lancée" } }
      }
    },
    "/api/v1/rewrite/wisewand": {
      "post": {
        "tags": ["Rewriting"],
        "summary": "Réécrire une page (Wisewand)",
        "description": "Réécriture premium via Wisewand. Traitement : 2-4 heures. Coût : 5 crédits (1 avec votre propre clé Wisewand). Accepte deux types de pages : (1) les pages scrapées depuis la Wayback Machine (`source=wayback`, comportement historique), et (2) les pages Haloscan (`source=haloscan`, sans snapshot Wayback) — pour ces dernières, le contenu synthétique est construit côté serveur à partir du slug + mots-clés classés, puis analysé par OpenAI pour extraire le sujet principal.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["page_id"],
                "properties": {
                  "page_id": { "type": "string", "format": "uuid" },
                  "subject": { "type": "string", "description": "Sujet personnalisé (optionnel). Si fourni pour une page Haloscan, court-circuite l'extraction OpenAI." },
                  "article_params": { "type": "object", "description": "Paramètres Wisewand additionnels (type, lang, country, target_keyword, keywords_secondary, additional_information...). Pour les pages Haloscan, ceux-ci remplissent les champs manquants après la préparation IA." },
                  "wisewand_api_key": { "type": "string", "description": "Votre propre clé API Wisewand (réduit le coût à 1 crédit)." }
                }
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Réécriture Wisewand lancée",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": { "type": "boolean" },
                    "data": {
                      "type": "object",
                      "properties": {
                        "job_id": { "type": "string", "format": "uuid" },
                        "status": { "type": "string" },
                        "page_id": { "type": "string", "format": "uuid" },
                        "source": { "type": "string", "enum": ["wayback", "haloscan"], "description": "Origine de la page traitée." },
                        "credits_used": { "type": "integer" },
                        "used_own_api_key": { "type": "boolean" },
                        "subject": { "type": "string" },
                        "subject_source": { "type": "string", "enum": ["ai", "first_keyword", "request", "page_title"], "description": "D'où vient le subject utilisé." },
                        "note": { "type": "string" }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/rewrite/bulk": {
      "post": {
        "tags": ["Rewriting"],
        "summary": "Réécrire plusieurs pages",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["page_ids"],
                "properties": {
                  "page_ids": { "type": "array", "items": { "type": "string", "format": "uuid" }, "maxItems": 50 }
                }
              }
            }
          }
        },
        "responses": { "202": { "description": "Réécriture en lot lancée" } }
      }
    },
    "/api/v1/generate-image": {
      "post": {
        "tags": ["Image Generation"],
        "summary": "Générer une image à la une",
        "description": "Génère une image via IA pour une page. Coût : 1 crédit.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["page_id"],
                "properties": {
                  "page_id": { "type": "string", "format": "uuid" }
                }
              }
            }
          }
        },
        "responses": { "202": { "description": "Génération d'image lancée" } }
      }
    },
    "/api/v1/generate-image/bulk": {
      "post": {
        "tags": ["Image Generation"],
        "summary": "Générer des images en lot",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["page_ids"],
                "properties": {
                  "page_ids": { "type": "array", "items": { "type": "string", "format": "uuid" }, "maxItems": 50 }
                }
              }
            }
          }
        },
        "responses": { "202": { "description": "Génération en lot lancée" } }
      }
    },
    "/api/v1/categorize": {
      "post": {
        "tags": ["Categorization"],
        "summary": "Catégoriser une page",
        "description": "Suggère une catégorie WordPress pour une page via l'IA. Gratuit.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["page_id", "wordpress_domain"],
                "properties": {
                  "page_id": { "type": "string", "format": "uuid" },
                  "wordpress_domain": { "type": "string", "example": "example.com" }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Catégorie suggérée",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": { "type": "boolean" },
                    "data": {
                      "type": "object",
                      "properties": {
                        "page_id": { "type": "string", "format": "uuid" },
                        "suggested_category": {
                          "type": "object",
                          "nullable": true,
                          "properties": {
                            "id": { "type": "integer" },
                            "name": { "type": "string" },
                            "slug": { "type": "string" },
                            "confidence": { "type": "number" }
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/wordpress/plugin/check": {
      "post": {
        "tags": ["WordPress"],
        "summary": "Vérifier la connexion plugin",
        "description": "Vérifie si le plugin Web Resurrect Connector est installé et connecté. Retourne aussi les catégories et auteurs.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["domain"],
                "properties": {
                  "domain": { "type": "string", "example": "example.com" }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Statut de la connexion plugin",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": { "type": "boolean" },
                    "data": {
                      "type": "object",
                      "properties": {
                        "domain": { "type": "string" },
                        "plugin_detected": { "type": "boolean" },
                        "connected": { "type": "boolean" },
                        "plugin_version": { "type": "string", "nullable": true },
                        "categories": { "type": "array", "items": { "type": "object" } },
                        "authors": { "type": "array", "items": { "type": "object" } }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/wordpress/credentials": {
      "post": {
        "tags": ["WordPress"],
        "summary": "Configurer WordPress",
        "description": "Configure la connexion WordPress. Deux modes : **Plugin** (`mode: \"plugin\"`) ou **Basic Auth** (`username` + `app_password`).",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "examples": {
                "plugin": {
                  "summary": "Mode Plugin (recommandé)",
                  "value": { "site_url": "https://example.com", "mode": "plugin" }
                },
                "basic_auth": {
                  "summary": "Mode Basic Auth",
                  "value": { "site_url": "https://example.com", "username": "admin", "app_password": "xxxx xxxx xxxx xxxx" }
                }
              },
              "schema": {
                "type": "object",
                "required": ["site_url"],
                "properties": {
                  "site_url": { "type": "string", "description": "URL du site WordPress" },
                  "mode": { "type": "string", "enum": ["plugin"], "description": "Mettre `plugin` pour le mode plugin. Omettre pour Basic Auth." },
                  "username": { "type": "string", "description": "Nom d'utilisateur WordPress (Basic Auth uniquement)" },
                  "app_password": { "type": "string", "description": "Mot de passe d'application (Basic Auth uniquement)" },
                  "post_as_draft": { "type": "boolean", "default": true }
                }
              }
            }
          }
        },
        "responses": { "201": { "description": "WordPress configuré" } }
      },
      "get": {
        "tags": ["WordPress"],
        "summary": "Lister les sites WordPress configurés",
        "responses": { "200": { "description": "Liste des configurations WordPress avec le mode (plugin/basic_auth)" } }
      }
    },
    "/api/v1/wordpress/credentials/validate": {
      "post": {
        "tags": ["WordPress"],
        "summary": "Valider la connexion WordPress",
        "description": "Teste la connexion WordPress. Détecte automatiquement le mode (plugin ou Basic Auth).",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["domain"],
                "properties": {
                  "domain": { "type": "string" }
                }
              }
            }
          }
        },
        "responses": { "200": { "description": "Résultat de la validation" } }
      }
    },
    "/api/v1/wordpress/categories/{domain}": {
      "get": {
        "tags": ["WordPress"],
        "summary": "Catégories WordPress",
        "parameters": [
          { "name": "domain", "in": "path", "required": true, "schema": { "type": "string" } }
        ],
        "responses": { "200": { "description": "Liste des catégories WordPress" } }
      }
    },
    "/api/v1/wordpress/authors/{domain}": {
      "get": {
        "tags": ["WordPress"],
        "summary": "Auteurs WordPress",
        "parameters": [
          { "name": "domain", "in": "path", "required": true, "schema": { "type": "string" } }
        ],
        "responses": { "200": { "description": "Liste des auteurs WordPress" } }
      }
    },
    "/api/v1/wordpress/publish": {
      "post": {
        "tags": ["WordPress"],
        "summary": "Publier sur WordPress",
        "description": "Publie une page sur WordPress via le plugin ou Basic Auth. Gratuit.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["page_id", "wordpress_domain"],
                "properties": {
                  "page_id": { "type": "string", "format": "uuid" },
                  "wordpress_domain": { "type": "string" },
                  "category_id": { "type": "integer", "description": "ID de la catégorie WordPress" },
                  "author_id": { "type": "integer", "description": "ID de l'auteur WordPress" },
                  "post_type": { "type": "string", "enum": ["post", "page"], "default": "post" },
                  "status": { "type": "string", "enum": ["draft", "publish"], "default": "draft" },
                  "use_rewritten_content": { "type": "boolean", "default": true },
                  "remove_links": { "type": "boolean", "default": false }
                }
              }
            }
          }
        },
        "responses": { "202": { "description": "Publication lancée" } }
      }
    },
    "/api/v1/wordpress/publish/bulk": {
      "post": {
        "tags": ["WordPress"],
        "summary": "Publier plusieurs pages sur WordPress",
        "responses": { "202": { "description": "Publication en lot lancée" } }
      }
    },
    "/api/v1/jobs": {
      "get": {
        "tags": ["Jobs"],
        "summary": "Lister les jobs",
        "parameters": [
          { "name": "status", "in": "query", "schema": { "type": "string", "enum": ["pending", "processing", "completed", "failed"] } },
          { "name": "type", "in": "query", "schema": { "type": "string" }, "description": "Filtrer par type (scrape, rewrite, publish, enrich...)" },
          { "name": "page", "in": "query", "schema": { "type": "integer", "default": 1 } },
          { "name": "limit", "in": "query", "schema": { "type": "integer", "default": 20 } }
        ],
        "responses": { "200": { "description": "Liste paginée des jobs" } }
      }
    },
    "/api/v1/jobs/{id}": {
      "get": {
        "tags": ["Jobs"],
        "summary": "Statut d'un job",
        "description": "Retourne le statut, la progression, le résultat et les crédits consommés.",
        "parameters": [
          { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } }
        ],
        "responses": { "200": { "description": "Détails du job" } }
      }
    },
    "/api/v1/jobs/{id}/cancel": {
      "post": {
        "tags": ["Jobs"],
        "summary": "Annuler un job",
        "parameters": [
          { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } }
        ],
        "responses": { "200": { "description": "Job annulé" } }
      }
    },
    "/api/v1/usage": {
      "get": {
        "tags": ["Usage"],
        "summary": "Historique de consommation de crédits",
        "parameters": [
          { "name": "from", "in": "query", "schema": { "type": "string", "format": "date-time" }, "description": "Date de début (ISO 8601)" },
          { "name": "to", "in": "query", "schema": { "type": "string", "format": "date-time" }, "description": "Date de fin (ISO 8601)" },
          { "name": "action_type", "in": "query", "schema": { "type": "string" }, "description": "Filtrer par type d'action (ex: api_scrape, api_rewrite_wisewand)" },
          { "name": "page", "in": "query", "schema": { "type": "integer", "default": 1 } },
          { "name": "limit", "in": "query", "schema": { "type": "integer", "default": 50, "maximum": 100 } }
        ],
        "responses": { "200": { "description": "Historique paginé des crédits consommés" } }
      }
    },
    "/api/v1/pages/{id}/snapshots": {
      "get": {
        "tags": ["Pages"],
        "summary": "Snapshots Wayback Machine d'une page",
        "parameters": [
          { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } }
        ],
        "responses": {
          "200": {
            "description": "Liste des snapshots Wayback pour la page",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": { "type": "boolean" },
                    "data": {
                      "type": "object",
                      "properties": {
                        "page_id": { "type": "string", "format": "uuid" },
                        "url": { "type": "string" },
                        "current_archive_url": { "type": "string" },
                        "snapshots_count": { "type": "integer" },
                        "snapshots": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "id": { "type": "string" },
                              "timestamp": { "type": "string" },
                              "archive_url": { "type": "string" },
                              "status_code": { "type": "integer", "nullable": true },
                              "content_length": { "type": "integer", "nullable": true },
                              "created_at": { "type": "string", "format": "date-time" }
                            }
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/pages/{id}/featured-image": {
      "get": {
        "tags": ["Pages"],
        "summary": "Image à la une d'une page",
        "parameters": [
          { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } }
        ],
        "responses": {
          "200": {
            "description": "URL de l'image à la une (si générée)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": { "type": "boolean" },
                    "data": {
                      "type": "object",
                      "properties": {
                        "id": { "type": "string", "format": "uuid" },
                        "has_featured_image": { "type": "boolean" },
                        "url": { "type": "string", "nullable": true },
                        "title": { "type": "string", "nullable": true }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/projects/{id}/stats": {
      "get": {
        "tags": ["Projects"],
        "summary": "Statistiques détaillées d'un projet",
        "description": "Retourne les compteurs de pages par statut (pending, scraped, rewritten, published, wisewand_*), les stats SEO agrégées et les pourcentages de progression. Utilise une requête SQL agrégée — scale à 20K+ pages.",
        "parameters": [
          { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } }
        ],
        "responses": {
          "200": {
            "description": "Stats détaillées du projet",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": { "type": "boolean" },
                    "data": {
                      "type": "object",
                      "properties": {
                        "pages": {
                          "type": "object",
                          "properties": {
                            "total": { "type": "integer" },
                            "pending": { "type": "integer" },
                            "scraped": { "type": "integer" },
                            "scrape_failed": { "type": "integer" },
                            "scrape_empty": { "type": "integer" },
                            "rewritten": { "type": "integer" },
                            "wisewand_pending": { "type": "integer" },
                            "wisewand_completed": { "type": "integer" },
                            "wisewand_failed": { "type": "integer" },
                            "published": { "type": "integer" }
                          }
                        },
                        "seo": {
                          "type": "object",
                          "properties": {
                            "total_traffic": { "type": "integer" },
                            "total_keywords": { "type": "integer" },
                            "total_backlinks": { "type": "integer" },
                            "keywords_top_3": { "type": "integer" },
                            "keywords_top_10": { "type": "integer" },
                            "keywords_top_50": { "type": "integer" },
                            "keywords_top_100": { "type": "integer" }
                          }
                        },
                        "progress": {
                          "type": "object",
                          "properties": {
                            "scrape_progress": { "type": "integer", "description": "Pourcentage de pages scrapées" },
                            "rewrite_progress": { "type": "integer" },
                            "publish_progress": { "type": "integer" }
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/projects/{id}/seo": {
      "get": {
        "tags": ["SEO Enrichment"],
        "summary": "Stats SEO d'un projet",
        "description": "Retourne les stats SEO agrégées, les top pages par trafic et par backlinks.",
        "parameters": [
          { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } }
        ],
        "responses": {
          "200": {
            "description": "Données SEO agrégées",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": { "type": "boolean" },
                    "data": {
                      "type": "object",
                      "properties": {
                        "aggregate": {
                          "type": "object",
                          "properties": {
                            "total_traffic": { "type": "integer" },
                            "total_keywords": { "type": "integer" },
                            "total_backlinks": { "type": "integer" },
                            "keywords_top_3": { "type": "integer" },
                            "keywords_top_10": { "type": "integer" },
                            "keywords_top_50": { "type": "integer" },
                            "keywords_top_100": { "type": "integer" },
                            "pages_with_stats": { "type": "integer" },
                            "pages_with_backlinks": { "type": "integer" }
                          }
                        },
                        "top_by_traffic": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "url": { "type": "string" },
                              "title": { "type": "string", "nullable": true },
                              "traffic": { "type": "integer" },
                              "keywords": { "type": "integer" },
                              "backlinks": { "type": "integer" }
                            }
                          }
                        },
                        "top_by_backlinks": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "url": { "type": "string" },
                              "title": { "type": "string", "nullable": true },
                              "backlinks": { "type": "integer" },
                              "traffic": { "type": "integer" }
                            }
                          }
                        },
                        "last_stats_update": { "type": "string", "format": "date-time", "nullable": true },
                        "last_backlinks_update": { "type": "string", "format": "date-time", "nullable": true }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/projects/{id}/redirects": {
      "get": {
        "tags": ["WordPress"],
        "summary": "Exporter les redirections d'un projet",
        "description": "Exporte les mappings de redirections (ancienne URL → URL WordPress) au format JSON pour le plugin **Redirection** (John Godley) ou **Rank Math**. Ne retourne que les pages publiées.",
        "parameters": [
          { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } },
          { "name": "format", "in": "query", "schema": { "type": "string", "enum": ["redirection", "rankmath"], "default": "redirection" } }
        ],
        "responses": { "200": { "description": "Mappings de redirections au format demandé" } }
      }
    },
    "/api/v1/projects/{id}/redirects/push": {
      "post": {
        "tags": ["WordPress"],
        "summary": "Pousser les redirections vers le plugin WordPress",
        "description": "Pousse les mappings d'URL vers le plugin Web Resurrect Connector.\n\n**Deux modes** :\n- Sans `urls[]` : pousse **toutes** les pages non publiées comme redirections (+ les pages publiées comme URL mappings)\n- Avec `urls[]` : ne redirige que ces URLs spécifiques\n\nNécessite le mode plugin (incompatible avec Basic Auth).",
        "parameters": [
          { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["wordpress_domain"],
                "properties": {
                  "wordpress_domain": { "type": "string", "example": "example.com" },
                  "urls": {
                    "type": "array",
                    "items": { "type": "string" },
                    "description": "URLs ou paths spécifiques à rediriger. Si omis, toutes les pages du projet sont traitées."
                  },
                  "redirect_to": {
                    "type": "string",
                    "description": "URL de destination pour les redirections (défaut : homepage du domaine)"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Redirections poussées",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": { "type": "boolean" },
                    "data": {
                      "type": "object",
                      "properties": {
                        "pushed": { "type": "integer" },
                        "published_urls": { "type": "integer" },
                        "homepage_redirects": { "type": "integer" },
                        "redirect_to": { "type": "string" },
                        "message": { "type": "string" }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/stats/analyze": {
      "post": {
        "tags": ["SEO Enrichment"],
        "summary": "Lancer une analyse SEO complète",
        "description": "Déclenche une analyse SEO asynchrone pour un projet. Retourne un `job_id` à poller.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["project_id"],
                "properties": {
                  "project_id": { "type": "string", "format": "uuid" }
                }
              }
            }
          }
        },
        "responses": { "202": { "description": "Analyse SEO lancée" } }
      }
    },
    "/api/v1/rewrite/wisewand/bulk": {
      "post": {
        "tags": ["Rewriting"],
        "summary": "Réécrire plusieurs pages avec Wisewand",
        "description": "Réécriture Wisewand en lot (max 50 pages). Traitement : plusieurs heures. Coût : 10 crédits par page (1 avec votre propre clé Wisewand). Mélange possible de pages Wayback (scrapées) et de pages Haloscan (sans snapshot). Pour chaque page Haloscan, le contenu synthétique et le sujet sont préparés par OpenAI côté worker avant le déclenchement de Wisewand — l'appel HTTP reste rapide.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["page_ids"],
                "properties": {
                  "page_ids": { "type": "array", "items": { "type": "string", "format": "uuid" }, "maxItems": 50 },
                  "article_params": { "type": "object", "description": "Paramètres Wisewand appliqués à toutes les pages (type, lang, country...). Pour les pages Haloscan, la préparation par page remplit les champs manquants (additional_information, target_keyword, keywords_secondary)." },
                  "wisewand_api_key": { "type": "string", "description": "Votre propre clé API Wisewand (réduit le coût à 1 crédit/page)." }
                }
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Réécriture Wisewand en lot lancée",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": { "type": "boolean" },
                    "data": {
                      "type": "object",
                      "properties": {
                        "job_id": { "type": "string", "format": "uuid" },
                        "status": { "type": "string" },
                        "total_items": { "type": "integer" },
                        "haloscan_count": { "type": "integer", "description": "Nombre de pages Haloscan-origin dans le lot." },
                        "wayback_count": { "type": "integer", "description": "Nombre de pages Wayback (scrapées) dans le lot." },
                        "not_scraped": { "type": "integer", "description": "Pages Wayback sans contenu scrapé — non éligibles, écartées." },
                        "credits_reserved": { "type": "integer" },
                        "credits_per_page": { "type": "integer" },
                        "used_own_api_key": { "type": "boolean" },
                        "note": { "type": "string" }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/categorize/bulk": {
      "post": {
        "tags": ["Categorization"],
        "summary": "Catégoriser plusieurs pages",
        "description": "Suggère et applique automatiquement une catégorie WordPress à chaque page via l'IA. Gratuit. Max 50 pages par lot.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["page_ids", "wordpress_domain"],
                "properties": {
                  "page_ids": { "type": "array", "items": { "type": "string", "format": "uuid" }, "maxItems": 50 },
                  "wordpress_domain": { "type": "string" }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Catégories suggérées",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": { "type": "boolean" },
                    "data": {
                      "type": "object",
                      "properties": {
                        "wordpress_domain": { "type": "string" },
                        "total": { "type": "integer" },
                        "categorized": { "type": "integer" },
                        "suggestions": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "page_id": { "type": "string", "format": "uuid" },
                              "suggested_category": {
                                "type": "object",
                                "nullable": true,
                                "properties": {
                                  "id": { "type": "integer" },
                                  "name": { "type": "string" },
                                  "slug": { "type": "string" },
                                  "confidence": { "type": "number" }
                                }
                              },
                              "message": { "type": "string" }
                            }
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/wordpress/credentials/{domain}": {
      "get": {
        "tags": ["WordPress"],
        "summary": "Détails de la configuration WordPress d'un domaine",
        "description": "Retourne la configuration WordPress pour un domaine (sans les secrets). Confirme juste que les credentials sont bien en vault.",
        "parameters": [
          { "name": "domain", "in": "path", "required": true, "schema": { "type": "string" } }
        ],
        "responses": { "200": { "description": "Configuration du domaine" } }
      },
      "delete": {
        "tags": ["WordPress"],
        "summary": "Supprimer la configuration WordPress d'un domaine",
        "parameters": [
          { "name": "domain", "in": "path", "required": true, "schema": { "type": "string" } }
        ],
        "responses": { "200": { "description": "Configuration supprimée" } }
      }
    },
    "/api/v1/wordpress/mapping": {
      "post": {
        "tags": ["WordPress"],
        "summary": "Configurer le mapping catégorie → auteur",
        "description": "Définit un mapping entre les catégories WordPress et les auteurs. Permet d'automatiquement affecter un auteur selon la catégorie choisie lors de la publication.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["domain"],
                "properties": {
                  "domain": { "type": "string" },
                  "mappings": {
                    "type": "array",
                    "items": {
                      "type": "object",
                      "properties": {
                        "category_id": { "type": "integer" },
                        "author_id": { "type": "integer" }
                      }
                    }
                  },
                  "default_author_id": { "type": "integer", "nullable": true },
                  "default_category_id": { "type": "integer", "nullable": true }
                }
              }
            }
          }
        },
        "responses": { "201": { "description": "Mapping enregistré" } }
      }
    },
    "/api/v1/wordpress/mapping/{domain}": {
      "get": {
        "tags": ["WordPress"],
        "summary": "Consulter le mapping d'un domaine",
        "parameters": [
          { "name": "domain", "in": "path", "required": true, "schema": { "type": "string" } }
        ],
        "responses": { "200": { "description": "Mapping actuel" } }
      },
      "put": {
        "tags": ["WordPress"],
        "summary": "Mettre à jour le mapping d'un domaine",
        "parameters": [
          { "name": "domain", "in": "path", "required": true, "schema": { "type": "string" } }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "mappings": {
                    "type": "array",
                    "items": {
                      "type": "object",
                      "properties": {
                        "category_id": { "type": "integer" },
                        "author_id": { "type": "integer" }
                      }
                    }
                  },
                  "default_author_id": { "type": "integer", "nullable": true },
                  "default_category_id": { "type": "integer", "nullable": true }
                }
              }
            }
          }
        },
        "responses": { "200": { "description": "Mapping mis à jour" } }
      },
      "delete": {
        "tags": ["WordPress"],
        "summary": "Effacer le mapping d'un domaine",
        "parameters": [
          { "name": "domain", "in": "path", "required": true, "schema": { "type": "string" } }
        ],
        "responses": { "200": { "description": "Mapping effacé" } }
      }
    }
  }
}
