{
  "openapi": "3.1.0",
  "info": {
    "title": "wh-drop API",
    "version": "0.1.0",
    "description": "Instant static web hosting for AI agents. Anonymous publish of static files to a live URL. Sites live 24 hours. Hosted in Norway."
  },
  "servers": [{ "url": "https://api.xdr.no" }],
  "paths": {
    "/api/v1/publish": {
      "post": {
        "summary": "Create a publish: send a file manifest, receive upload URLs",
        "operationId": "createPublish",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/Manifest" }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Publish created",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/PublishResponse" }
              }
            }
          },
          "400": { "description": "Invalid manifest" },
          "429": { "description": "Rate limit exceeded" }
        }
      }
    },
    "/api/v1/u/{token}": {
      "put": {
        "summary": "Upload a file's raw bytes to a one-time upload URL",
        "operationId": "uploadFile",
        "parameters": [
          { "name": "token", "in": "path", "required": true, "schema": { "type": "string" } }
        ],
        "requestBody": {
          "required": true,
          "content": { "application/octet-stream": { "schema": { "type": "string", "format": "binary" } } }
        },
        "responses": {
          "200": { "description": "Uploaded (size + sha256 verified)" },
          "400": { "description": "Size or sha256 mismatch" },
          "404": { "description": "Unknown or already-used upload URL" },
          "409": { "description": "Already uploaded" }
        }
      }
    },
    "/api/v1/publish/{slug}/finalize": {
      "post": {
        "summary": "Finalize a publish and make the site live",
        "operationId": "finalizePublish",
        "parameters": [
          { "name": "slug", "in": "path", "required": true, "schema": { "type": "string" } }
        ],
        "responses": {
          "200": {
            "description": "Site is live",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/FinalizeResponse" } } }
          },
          "404": { "description": "No pending publish for this slug" },
          "409": { "description": "Not all files uploaded" }
        }
      }
    },
    "/api/v1/publish/{slug}": {
      "get": {
        "summary": "Get the status of a publish",
        "operationId": "getPublish",
        "parameters": [
          { "name": "slug", "in": "path", "required": true, "schema": { "type": "string" } }
        ],
        "responses": {
          "200": { "description": "Status" },
          "404": { "description": "Not found or expired" }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "Manifest": {
        "type": "object",
        "required": ["files"],
        "properties": {
          "files": {
            "type": "array",
            "items": {
              "type": "object",
              "required": ["path", "size", "sha256"],
              "properties": {
                "path": { "type": "string", "example": "index.html" },
                "size": { "type": "integer", "example": 1240 },
                "contentType": { "type": "string", "example": "text/html" },
                "sha256": { "type": "string", "description": "lowercase hex SHA-256 of the file bytes" }
              }
            }
          }
        }
      },
      "PublishResponse": {
        "type": "object",
        "properties": {
          "slug": { "type": "string" },
          "url": { "type": "string", "example": "https://a7f3k9q2x1.xdr.no" },
          "expiresAt": { "type": "string", "format": "date-time" },
          "claimUrl": { "type": "string" },
          "finalize": { "type": "string" },
          "uploads": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "path": { "type": "string" },
                "putUrl": { "type": "string" },
                "method": { "type": "string", "example": "PUT" }
              }
            }
          }
        }
      },
      "FinalizeResponse": {
        "type": "object",
        "properties": {
          "slug": { "type": "string" },
          "url": { "type": "string" },
          "expiresAt": { "type": "string", "format": "date-time" }
        }
      }
    }
  }
}
