{
  "openapi": "3.1.0",
  "info": {
    "title": "Drivecord API v2",
    "version": "2.0.0",
    "description": "API v2 de Drivecord. Tout le contenu privé est chiffré de bout en bout : le serveur ne voit jamais ni noms, ni contenus, ni clés. Les clients chiffrent avec le format décrit dans SECURITY.md (AES-256-GCM par morceaux de 8 Mio)."
  },
  "servers": [
    {
      "url": "https://drivecord.app/api/v2"
    }
  ],
  "security": [
    {
      "bearer": []
    }
  ],
  "paths": {
    "/me": {
      "get": {
        "summary": "Identité du jeton",
        "description": "Permission requise : n'importe quel jeton valide.",
        "security": [
          {
            "bearer": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Me"
                }
              }
            }
          },
          "401": {
            "description": "Jeton manquant, invalide ou expiré.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Scope insuffisant ou origine non autorisée.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Limite de débit atteinte (voir `Retry-After`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/uploads": {
      "post": {
        "summary": "Ouvrir une session d'upload",
        "description": "Permission requise : `app_folder:write` / `drive:write`.",
        "security": [
          {
            "bearer": []
          }
        ],
        "responses": {
          "201": {
            "description": "Session créée",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UploadSession"
                }
              }
            }
          },
          "401": {
            "description": "Jeton manquant, invalide ou expiré.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Scope insuffisant ou origine non autorisée.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Identifiant déjà utilisé ou drive non chiffré.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Limite de débit atteinte (voir `Retry-After`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "minLength": 8,
              "maxLength": 128
            },
            "description": "Rejoue la réponse pendant 24 h si la même requête est renvoyée."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UploadCreate"
              }
            }
          }
        }
      }
    },
    "/uploads/{uploadId}": {
      "delete": {
        "summary": "Annuler un upload",
        "description": "Permission requise : écriture.",
        "security": [
          {
            "bearer": []
          }
        ],
        "responses": {
          "204": {
            "description": "Annulé"
          },
          "401": {
            "description": "Jeton manquant, invalide ou expiré.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Scope insuffisant ou origine non autorisée.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Limite de débit atteinte (voir `Retry-After`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "uploadId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Identifiant de session"
          }
        ]
      }
    },
    "/uploads/{uploadId}/chunks/{index}": {
      "put": {
        "summary": "Envoyer un morceau (octet-stream)",
        "description": "Permission requise : écriture.",
        "security": [
          {
            "bearer": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ChunkReceipt"
                }
              }
            }
          },
          "400": {
            "description": "Taille ou empreinte incorrecte (`chunk_mismatch`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Jeton manquant, invalide ou expiré.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Scope insuffisant ou origine non autorisée.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Limite de débit atteinte (voir `Retry-After`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "uploadId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Session"
          },
          {
            "name": "index",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Index du morceau (0…)"
          },
          {
            "name": "X-Chunk-SHA256",
            "in": "header",
            "schema": {
              "type": "string"
            },
            "description": "SHA-256 hexadécimal, vérifié si présent."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/octet-stream": {
              "schema": {
                "type": "string",
                "format": "binary"
              }
            }
          }
        }
      }
    },
    "/uploads/{uploadId}/complete": {
      "post": {
        "summary": "Finaliser un upload",
        "description": "Permission requise : écriture.",
        "security": [
          {
            "bearer": []
          }
        ],
        "responses": {
          "201": {
            "description": "Fichier créé",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/File"
                }
              }
            }
          },
          "401": {
            "description": "Jeton manquant, invalide ou expiré.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Scope insuffisant ou origine non autorisée.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Morceaux manquants (`upload_incomplete`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Limite de débit atteinte (voir `Retry-After`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "uploadId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Session"
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "minLength": 8,
              "maxLength": 128
            },
            "description": "Rejoue la réponse pendant 24 h si la même requête est renvoyée."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UploadComplete"
              }
            }
          }
        }
      }
    },
    "/files": {
      "get": {
        "summary": "Lister les fichiers",
        "description": "Permission requise : lecture.",
        "security": [
          {
            "bearer": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FileList"
                }
              }
            }
          },
          "401": {
            "description": "Jeton manquant, invalide ou expiré.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Scope insuffisant ou origine non autorisée.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Limite de débit atteinte (voir `Retry-After`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 200,
              "default": 50
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "parentId",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Dossier ; `\"\"` = racine. Par défaut : dossier de l'application (apps) / tout le drive (jetons personnels)."
          },
          {
            "name": "trashed",
            "in": "query",
            "schema": {
              "type": "boolean",
              "default": false
            }
          }
        ]
      }
    },
    "/files/{id}": {
      "get": {
        "summary": "Lire un fichier",
        "description": "Permission requise : lecture.",
        "security": [
          {
            "bearer": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/File"
                }
              }
            }
          },
          "401": {
            "description": "Jeton manquant, invalide ou expiré.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Scope insuffisant ou origine non autorisée.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Introuvable.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Limite de débit atteinte (voir `Retry-After`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Identifiant"
          }
        ]
      },
      "patch": {
        "summary": "Modifier (métadonnées chiffrées, déplacement, corbeille)",
        "description": "Permission requise : écriture.",
        "security": [
          {
            "bearer": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/File"
                }
              }
            }
          },
          "401": {
            "description": "Jeton manquant, invalide ou expiré.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Scope insuffisant ou origine non autorisée.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Limite de débit atteinte (voir `Retry-After`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Identifiant"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/FilePatch"
              }
            }
          }
        }
      },
      "delete": {
        "summary": "Mettre à la corbeille (ou supprimer avec `?permanent=true`)",
        "description": "Permission requise : suppression.",
        "security": [
          {
            "bearer": []
          }
        ],
        "responses": {
          "204": {
            "description": "Supprimé"
          },
          "401": {
            "description": "Jeton manquant, invalide ou expiré.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Scope insuffisant ou origine non autorisée.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Limite de débit atteinte (voir `Retry-After`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Identifiant"
          },
          {
            "name": "permanent",
            "in": "query",
            "schema": {
              "type": "boolean"
            }
          }
        ]
      }
    },
    "/files/{id}/chunks/{index}": {
      "get": {
        "summary": "Télécharger un morceau (chiffré)",
        "description": "Permission requise : lecture.",
        "security": [
          {
            "bearer": []
          }
        ],
        "responses": {
          "200": {
            "description": "Octets du morceau",
            "content": {
              "application/octet-stream": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "401": {
            "description": "Jeton manquant, invalide ou expiré.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Scope insuffisant ou origine non autorisée.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Limite de débit atteinte (voir `Retry-After`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Identifiant"
          },
          {
            "name": "index",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Index du morceau"
          }
        ]
      }
    },
    "/files/{id}/shares": {
      "post": {
        "summary": "Créer un partage chiffré",
        "description": "Permission requise : `drive:share` (jetons personnels).",
        "security": [
          {
            "bearer": []
          }
        ],
        "responses": {
          "201": {
            "description": "Partage créé",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Share"
                }
              }
            }
          },
          "401": {
            "description": "Jeton manquant, invalide ou expiré.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Scope insuffisant ou origine non autorisée.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Limite de débit atteinte (voir `Retry-After`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Identifiant"
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "minLength": 8,
              "maxLength": 128
            },
            "description": "Rejoue la réponse pendant 24 h si la même requête est renvoyée."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ShareCreate"
              }
            }
          }
        }
      }
    },
    "/files/{id}/public": {
      "post": {
        "summary": "Créer un lien public (fichiers `visibility: public`)",
        "description": "Permission requise : `drive:share`.",
        "security": [
          {
            "bearer": []
          }
        ],
        "responses": {
          "201": {
            "description": "Lien créé",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicLink"
                }
              }
            }
          },
          "401": {
            "description": "Jeton manquant, invalide ou expiré.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Scope insuffisant ou origine non autorisée.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Le fichier est chiffré.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Limite de débit atteinte (voir `Retry-After`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Identifiant"
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "minLength": 8,
              "maxLength": 128
            },
            "description": "Rejoue la réponse pendant 24 h si la même requête est renvoyée."
          }
        ]
      },
      "delete": {
        "summary": "Révoquer le lien public",
        "description": "Permission requise : `drive:share`.",
        "security": [
          {
            "bearer": []
          }
        ],
        "responses": {
          "204": {
            "description": "Révoqué"
          },
          "401": {
            "description": "Jeton manquant, invalide ou expiré.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Scope insuffisant ou origine non autorisée.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Limite de débit atteinte (voir `Retry-After`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Identifiant"
          }
        ]
      }
    },
    "/shares/{token}": {
      "get": {
        "summary": "Lire un partage",
        "description": "Permission requise : `drive:share`.",
        "security": [
          {
            "bearer": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Share"
                }
              }
            }
          },
          "401": {
            "description": "Jeton manquant, invalide ou expiré.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Scope insuffisant ou origine non autorisée.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Limite de débit atteinte (voir `Retry-After`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "token",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Jeton de partage"
          }
        ]
      },
      "delete": {
        "summary": "Révoquer un partage",
        "description": "Permission requise : `drive:share`.",
        "security": [
          {
            "bearer": []
          }
        ],
        "responses": {
          "204": {
            "description": "Révoqué"
          },
          "401": {
            "description": "Jeton manquant, invalide ou expiré.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Scope insuffisant ou origine non autorisée.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Limite de débit atteinte (voir `Retry-After`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "token",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Jeton de partage"
          }
        ]
      }
    },
    "/folders": {
      "get": {
        "summary": "Lister les dossiers",
        "description": "Permission requise : lecture.",
        "security": [
          {
            "bearer": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FolderList"
                }
              }
            }
          },
          "401": {
            "description": "Jeton manquant, invalide ou expiré.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Scope insuffisant ou origine non autorisée.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Limite de débit atteinte (voir `Retry-After`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 200,
              "default": 50
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "parentId",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Dossier ; `\"\"` = racine. Par défaut : dossier de l'application (apps) / tout le drive (jetons personnels)."
          },
          {
            "name": "trashed",
            "in": "query",
            "schema": {
              "type": "boolean",
              "default": false
            }
          }
        ]
      },
      "post": {
        "summary": "Créer un dossier (nom chiffré)",
        "description": "Permission requise : écriture.",
        "security": [
          {
            "bearer": []
          }
        ],
        "responses": {
          "201": {
            "description": "Dossier créé",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Folder"
                }
              }
            }
          },
          "401": {
            "description": "Jeton manquant, invalide ou expiré.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Scope insuffisant ou origine non autorisée.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Limite de débit atteinte (voir `Retry-After`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "minLength": 8,
              "maxLength": 128
            },
            "description": "Rejoue la réponse pendant 24 h si la même requête est renvoyée."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/FolderCreate"
              }
            }
          }
        }
      }
    },
    "/folders/{id}": {
      "get": {
        "summary": "Lire un dossier",
        "description": "Permission requise : lecture.",
        "security": [
          {
            "bearer": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Folder"
                }
              }
            }
          },
          "401": {
            "description": "Jeton manquant, invalide ou expiré.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Scope insuffisant ou origine non autorisée.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Limite de débit atteinte (voir `Retry-After`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Identifiant"
          }
        ]
      },
      "patch": {
        "summary": "Modifier un dossier",
        "description": "Permission requise : écriture.",
        "security": [
          {
            "bearer": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Folder"
                }
              }
            }
          },
          "401": {
            "description": "Jeton manquant, invalide ou expiré.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Scope insuffisant ou origine non autorisée.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Limite de débit atteinte (voir `Retry-After`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Identifiant"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/FolderPatch"
              }
            }
          }
        }
      },
      "delete": {
        "summary": "Corbeille (ou suppression d'un dossier vide avec `?permanent=true`)",
        "description": "Permission requise : suppression.",
        "security": [
          {
            "bearer": []
          }
        ],
        "responses": {
          "204": {
            "description": "Supprimé"
          },
          "401": {
            "description": "Jeton manquant, invalide ou expiré.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Scope insuffisant ou origine non autorisée.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Limite de débit atteinte (voir `Retry-After`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Identifiant"
          },
          {
            "name": "permanent",
            "in": "query",
            "schema": {
              "type": "boolean"
            }
          }
        ]
      }
    },
    "/changes": {
      "get": {
        "summary": "Journal des changements (jetons personnels)",
        "description": "Permission requise : `drive:read`.",
        "security": [
          {
            "bearer": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ChangeList"
                }
              }
            }
          },
          "401": {
            "description": "Jeton manquant, invalide ou expiré.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Scope insuffisant ou origine non autorisée.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Limite de débit atteinte (voir `Retry-After`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "cursor",
            "in": "query",
            "schema": {
              "type": "string",
              "default": "0"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "maximum": 500
            }
          }
        ]
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearer": {
        "type": "http",
        "scheme": "bearer",
        "description": "Jeton d'accès OAuth (`dvc_at_…`) ou jeton personnel (`dvc_pat_…`)."
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "required": [
          "error"
        ],
        "properties": {
          "error": {
            "type": "object",
            "required": [
              "code",
              "message"
            ],
            "properties": {
              "code": {
                "type": "string"
              },
              "message": {
                "type": "string"
              },
              "requestId": {
                "type": "string"
              }
            }
          }
        }
      },
      "Me": {
        "type": "object",
        "properties": {
          "principal": {
            "type": "object"
          },
          "user": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string"
              }
            }
          },
          "drive": {
            "type": "object"
          },
          "limits": {
            "type": "object"
          }
        }
      },
      "UploadCreate": {
        "type": "object",
        "required": [
          "fileId",
          "size"
        ],
        "additionalProperties": false,
        "properties": {
          "fileId": {
            "type": "string",
            "pattern": "^[A-Za-z0-9_-]{21}$"
          },
          "parentId": {
            "type": "string"
          },
          "size": {
            "type": "integer",
            "minimum": 1
          },
          "visibility": {
            "enum": [
              "private",
              "public"
            ],
            "default": "private"
          }
        }
      },
      "UploadSession": {
        "type": "object",
        "properties": {
          "uploadId": {
            "type": "string"
          },
          "fileId": {
            "type": "string"
          },
          "parentId": {
            "type": "string"
          },
          "chunkSize": {
            "type": "integer"
          },
          "chunkCount": {
            "type": "integer"
          },
          "expiresAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "ChunkReceipt": {
        "type": "object",
        "properties": {
          "index": {
            "type": "integer"
          },
          "size": {
            "type": "integer"
          },
          "sha256": {
            "type": "string"
          }
        }
      },
      "UploadComplete": {
        "oneOf": [
          {
            "type": "object",
            "required": [
              "encMeta",
              "fkWrapped",
              "noncePrefix"
            ],
            "additionalProperties": false,
            "properties": {
              "encMeta": {
                "type": "string"
              },
              "fkWrapped": {
                "type": "string"
              },
              "noncePrefix": {
                "type": "string"
              }
            }
          },
          {
            "type": "object",
            "required": [
              "filename"
            ],
            "additionalProperties": false,
            "properties": {
              "filename": {
                "type": "string"
              },
              "mimeType": {
                "type": "string"
              }
            }
          }
        ]
      },
      "File": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "parentId": {
            "type": "string"
          },
          "visibility": {
            "enum": [
              "private",
              "public"
            ]
          },
          "size": {
            "type": "integer"
          },
          "chunkSize": {
            "type": "integer"
          },
          "chunkCount": {
            "type": "integer"
          },
          "cryptoVersion": {
            "type": "integer"
          },
          "encMeta": {
            "type": [
              "string",
              "null"
            ]
          },
          "fkWrapped": {
            "type": [
              "string",
              "null"
            ]
          },
          "noncePrefix": {
            "type": [
              "string",
              "null"
            ]
          },
          "filename": {
            "type": "string"
          },
          "mimeType": {
            "type": "string"
          },
          "trashed": {
            "type": "boolean"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "FileList": {
        "type": "object",
        "properties": {
          "files": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/File"
            }
          },
          "nextCursor": {
            "type": [
              "string",
              "null"
            ]
          }
        }
      },
      "FilePatch": {
        "type": "object",
        "additionalProperties": false,
        "minProperties": 1,
        "properties": {
          "encMeta": {
            "type": "string"
          },
          "parentId": {
            "type": "string"
          },
          "trashed": {
            "type": "boolean"
          }
        }
      },
      "Folder": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "parentId": {
            "type": "string"
          },
          "encName": {
            "type": [
              "string",
              "null"
            ]
          },
          "color": {
            "type": [
              "string",
              "null"
            ]
          },
          "trashed": {
            "type": "boolean"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "FolderList": {
        "type": "object",
        "properties": {
          "folders": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Folder"
            }
          },
          "nextCursor": {
            "type": [
              "string",
              "null"
            ]
          }
        }
      },
      "FolderCreate": {
        "type": "object",
        "required": [
          "encName"
        ],
        "additionalProperties": false,
        "properties": {
          "parentId": {
            "type": "string"
          },
          "encName": {
            "type": "string"
          },
          "color": {
            "type": [
              "string",
              "null"
            ]
          }
        }
      },
      "FolderPatch": {
        "type": "object",
        "additionalProperties": false,
        "minProperties": 1,
        "properties": {
          "encName": {
            "type": "string"
          },
          "parentId": {
            "type": "string"
          },
          "color": {
            "type": [
              "string",
              "null"
            ]
          },
          "trashed": {
            "type": "boolean"
          }
        }
      },
      "ShareCreate": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "token": {
            "type": "string"
          },
          "expiresInDays": {
            "type": [
              "integer",
              "null"
            ]
          },
          "fkWrappedForShare": {
            "type": "string"
          },
          "shareKdf": {
            "type": "object"
          }
        }
      },
      "Share": {
        "type": "object",
        "properties": {
          "token": {
            "type": "string"
          },
          "url": {
            "type": "string"
          },
          "hasPassword": {
            "type": "boolean"
          },
          "expiresAt": {
            "type": [
              "string",
              "null"
            ]
          }
        }
      },
      "PublicLink": {
        "type": "object",
        "properties": {
          "token": {
            "type": "string"
          },
          "url": {
            "type": "string"
          }
        }
      },
      "ChangeList": {
        "type": "object",
        "properties": {
          "changes": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "type": {
                  "enum": [
                    "upsert",
                    "delete"
                  ]
                },
                "kind": {
                  "enum": [
                    "file",
                    "folder"
                  ]
                },
                "id": {
                  "type": "string"
                },
                "at": {
                  "type": "string"
                }
              }
            }
          },
          "cursor": {
            "type": "string"
          },
          "hasMore": {
            "type": "boolean"
          }
        }
      }
    }
  }
}
