{
  "openapi": "3.0.3",
  "info": {
    "title": "ProgPost Agent API",
    "version": "2.0.0",
    "description": "Prépare des brouillons de vidéos TikTok. La clé X-API-Key, créée dans ProgPost par son titulaire, est obligatoire et limitée à son compte. Elle ne permet ni de valider ni de publier : ces actions se font dans l'interface, par le créateur."
  },
  "servers": [{ "url": "https://progpost.com" }],
  "security": [{ "AgentKey": [] }],
  "components": {
    "securitySchemes": { "AgentKey": { "type": "apiKey", "in": "header", "name": "X-API-Key" } },
    "schemas": {
      "PostInput": {
        "type": "object",
        "required": ["video_id", "title"],
        "properties": {
          "video_id": { "type": "string", "description": "ID renvoyé par POST /api/videos" },
          "title": { "type": "string", "description": "Nom interne du post" },
          "caption": { "type": "string", "description": "Légende TikTok, sans les hashtags" },
          "hashtags": { "type": "array", "items": { "type": "string" }, "description": "Hashtags avec ou sans #" },
          "scheduled_at": { "type": "string", "format": "date-time", "nullable": true, "description": "Date ISO 8601 avec fuseau horaire, obligatoirement dans le futur" }
        }
      },
      "Post": {
        "allOf": [{ "$ref": "#/components/schemas/PostInput" }, { "type": "object", "properties": { "id": { "type": "string" }, "status": { "type": "string", "enum": ["draft", "ready", "queued", "scheduled", "publishing", "processing", "published", "failed"] }, "tiktok_caption": { "type": "string" }, "can_delete": { "type": "boolean" }, "video_available": { "type": "boolean" }, "error": { "type": "string", "nullable": true } } }]
      },
      "Error": { "type": "object", "properties": { "error": { "type": "string" }, "code": { "type": "string" } } }
    },
    "responses": {
      "Unauthorized": { "description": "Clé absente ou invalide", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
      "RateLimited": { "description": "Trop de requêtes : 120 par minute maximum", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }
    }
  },
  "paths": {
    "/api/state": {
      "get": { "operationId": "getStudioState", "summary": "Lister les vidéos et publications de ce compte", "responses": { "200": { "description": "État du compte", "content": { "application/json": { "schema": { "type": "object", "properties": { "posts": { "type": "array", "items": { "$ref": "#/components/schemas/Post" } }, "videos": { "type": "array", "items": { "type": "object" } }, "usage": { "type": "object" } } } } } }, "401": { "$ref": "#/components/responses/Unauthorized" }, "429": { "$ref": "#/components/responses/RateLimited" } } }
    },
    "/api/videos": {
      "post": { "operationId": "uploadVideo", "summary": "Importer une vidéo MP4, MOV ou WebM", "parameters": [{ "in": "header", "name": "X-Filename", "required": true, "schema": { "type": "string" } }, { "in": "header", "name": "X-Duration-Seconds", "description": "Utilisé seulement si la durée est illisible dans le fichier", "schema": { "type": "number" } }], "requestBody": { "required": true, "content": { "application/octet-stream": { "schema": { "type": "string", "format": "binary" } } } }, "responses": { "201": { "description": "Vidéo importée ; utiliser son id pour créer un post" }, "400": { "description": "Vidéo refusée : format, codec, résolution, images par seconde ou durée hors des limites TikTok" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "413": { "description": "Vidéo trop volumineuse ou stockage du compte plein" }, "507": { "description": "Le service manque d'espace : réessayer plus tard" } } }
    },
    "/api/posts": {
      "post": { "operationId": "createPost", "summary": "Créer un brouillon éventuellement daté", "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PostInput" } } } }, "responses": { "201": { "description": "Brouillon créé", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Post" } } } }, "401": { "$ref": "#/components/responses/Unauthorized" } } }
    },
    "/api/posts/{id}": {
      "parameters": [{ "in": "path", "name": "id", "required": true, "schema": { "type": "string" } }],
      "patch": { "operationId": "updatePost", "summary": "Modifier un post non envoyé ; efface une éventuelle validation", "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PostInput" } } } }, "responses": { "200": { "description": "Post modifié" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "404": { "description": "Post introuvable sur ce compte" } } },
      "delete": { "operationId": "deletePost", "summary": "Supprimer un post non envoyé et sa vidéo si aucun autre post ne l'utilise", "responses": { "200": { "description": "Post supprimé" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "404": { "description": "Post introuvable sur ce compte" } } }
    }
  }
}
