{
  "openapi": "3.1.0",
  "info": {
    "title": "a4list API",
    "version": "2.2.0",
    "description": "Capability-authenticated whole-document API for printable a4list sheets. JSON and a4list plain text are accepted for creation and atomic replacement."
  },
  "servers": [{ "url": "/" }],
  "paths": {
    "/api/sheet": {
      "post": {
        "operationId": "create_sheet",
        "summary": "Create a sheet with independent read and write capabilities",
        "parameters": [{
          "name": "X-A4List-Title",
          "in": "header",
          "required": false,
          "description": "Initial title for a default blank sheet when no request body is supplied.",
          "schema": { "type": "string", "maxLength": 120 }
        }],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": { "schema": { "oneOf": [{ "$ref": "#/components/schemas/CreateSheetOptions" }, { "$ref": "#/components/schemas/SheetDocument" }] } },
            "text/plain": { "schema": { "$ref": "#/components/schemas/PlainTextDocument" } }
          }
        },
        "responses": {
          "201": { "description": "Sheet created", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreatedSheet" } } } },
          "400": { "$ref": "#/components/responses/ErrorResponse" },
          "413": { "$ref": "#/components/responses/ErrorResponse" },
          "415": { "$ref": "#/components/responses/ErrorResponse" },
          "429": { "$ref": "#/components/responses/ErrorResponse" },
          "503": { "$ref": "#/components/responses/ErrorResponse" }
        }
      }
    },
    "/api/sheet/{capability}": {
      "parameters": [{ "$ref": "#/components/parameters/Capability" }],
      "get": {
        "operationId": "get_sheet",
        "summary": "Read the complete committed sheet document",
        "responses": {
          "200": { "description": "Capability-safe sheet response, or a4list plain text when requested with Accept: text/plain", "content": {
            "application/json": { "schema": { "oneOf": [{ "$ref": "#/components/schemas/ReadSheet" }, { "$ref": "#/components/schemas/WriteSheet" }] } },
            "text/plain": { "schema": { "$ref": "#/components/schemas/PlainTextDocument" } }
          } },
          "404": { "$ref": "#/components/responses/ErrorResponse" }
        }
      },
      "post": {
        "operationId": "replace_sheet_document",
        "summary": "Atomically replace the complete document using a write capability",
        "parameters": [{ "$ref": "#/components/parameters/IfMatch" }],
        "requestBody": { "required": true, "content": {
          "application/json": { "schema": { "$ref": "#/components/schemas/SheetDocument" } },
          "text/plain": { "schema": { "$ref": "#/components/schemas/PlainTextDocument" } }
        } },
        "responses": {
          "200": { "description": "Committed revision", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Revision" } } } },
          "400": { "$ref": "#/components/responses/ErrorResponse" },
          "403": { "$ref": "#/components/responses/ErrorResponse" },
          "412": { "$ref": "#/components/responses/ConflictResponse" },
          "413": { "$ref": "#/components/responses/ErrorResponse" },
          "415": { "$ref": "#/components/responses/ErrorResponse" },
          "428": { "$ref": "#/components/responses/ErrorResponse" }
        }
      }
    },
    "/api/sheet/{capability}/txt": {
      "parameters": [{ "$ref": "#/components/parameters/Capability" }],
      "get": {
        "operationId": "get_sheet_plain_text",
        "summary": "Read the sheet in a4list plain text format",
        "responses": {
          "200": { "description": "a4list plain text", "content": { "text/plain": { "schema": { "$ref": "#/components/schemas/PlainTextDocument" } } } },
          "404": { "$ref": "#/components/responses/ErrorResponse" }
        }
      }
    },
    "/api/sheet/{capability}/recovery-email": {
      "parameters": [{ "$ref": "#/components/parameters/Capability" }],
      "put": {
        "operationId": "set_recovery_email",
        "summary": "Set the write-only recovery address",
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/RecoveryEmail" } } } },
        "responses": {
          "200": { "description": "Recovery email stored", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/RecoveryEmail" } } } },
          "400": { "$ref": "#/components/responses/ErrorResponse" },
          "403": { "$ref": "#/components/responses/ErrorResponse" },
          "404": { "$ref": "#/components/responses/ErrorResponse" },
          "413": { "$ref": "#/components/responses/ErrorResponse" },
          "415": { "$ref": "#/components/responses/ErrorResponse" }
        }
      }
    },
    "/api/sheet/{capability}/duplicate": {
      "parameters": [{ "$ref": "#/components/parameters/Capability" }],
      "post": {
        "operationId": "duplicate_sheet",
        "summary": "Duplicate the latest committed document into a new sheet",
        "requestBody": { "required": false, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/DuplicateSheet" } } } },
        "responses": {
          "201": { "description": "Independent sheet created", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreatedSheet" } } } },
          "400": { "$ref": "#/components/responses/ErrorResponse" },
          "404": { "$ref": "#/components/responses/ErrorResponse" },
          "413": { "$ref": "#/components/responses/ErrorResponse" },
          "429": { "$ref": "#/components/responses/ErrorResponse" },
          "415": { "$ref": "#/components/responses/ErrorResponse" }
        }
      }
    },
    "/api/sheet/{capability}/meta": {
      "parameters": [{ "$ref": "#/components/parameters/Capability" }],
      "get": {
        "operationId": "get_sheet_metadata",
        "summary": "Validate a capability and retrieve safe revision metadata",
        "responses": {
          "200": { "description": "Capability-safe metadata", "content": { "application/json": { "schema": { "oneOf": [{ "$ref": "#/components/schemas/ReadMetadata" }, { "$ref": "#/components/schemas/WriteMetadata" }] } } } },
          "404": { "$ref": "#/components/responses/ErrorResponse" }
        }
      }
    },
    "/api/sheet/{capability}/pdf": {
      "parameters": [{ "$ref": "#/components/parameters/Capability" }],
      "get": {
        "operationId": "generate_sheet_pdf",
        "summary": "Generate or retrieve a revision-pinned A4 PDF",
        "parameters": [
          { "name": "revision", "in": "query", "required": true, "schema": { "type": "integer", "minimum": 0 } },
          { "name": "disposition", "in": "query", "required": false, "schema": { "type": "string", "enum": ["inline", "attachment"], "default": "inline" } }
        ],
        "responses": {
          "200": { "description": "A4 PDF", "content": { "application/pdf": { "schema": { "type": "string", "format": "binary" } } } },
          "400": { "$ref": "#/components/responses/ErrorResponse" },
          "404": { "$ref": "#/components/responses/ErrorResponse" },
          "409": { "$ref": "#/components/responses/ErrorResponse" },
          "429": { "$ref": "#/components/responses/ErrorResponse" },
          "503": { "$ref": "#/components/responses/ErrorResponse" }
        }
      }
    }
  },
  "components": {
    "parameters": {
      "Capability": {
        "name": "capability",
        "in": "path",
        "required": true,
        "description": "A capability prefixed with re_ or wr_. New secrets contain 80 random bits; existing 128-bit secrets remain valid.",
        "schema": { "$ref": "#/components/schemas/Capability" }
      },
      "IfMatch": {
        "name": "If-Match",
        "in": "header",
        "required": true,
        "description": "The base revision, formatted as \"revision-N\".",
        "schema": { "type": "string", "pattern": "^\\\"revision-[0-9]+\\\"$" }
      }
    },
    "responses": {
      "ErrorResponse": { "description": "Request failed", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
      "ConflictResponse": { "description": "The base revision is stale", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Conflict" } } } }
    },
    "schemas": {
      "Capability": { "type": "string", "pattern": "^(re|wr)_[0-9a-f]{20}([0-9a-f]{12})?$", "examples": ["re_0123456789abcdef0123"] },
      "CreatedSheet": {
        "type": "object", "additionalProperties": false,
        "required": ["read_url", "write_url", "revision"],
        "properties": {
          "read_url": { "type": "string" },
          "write_url": { "type": "string" },
          "revision": { "type": "integer", "minimum": 0 }
        }
      },
      "DuplicateSheet": {
        "type": "object", "additionalProperties": false,
        "required": ["title"],
        "properties": {
          "title": { "type": "string", "maxLength": 120 }
        }
      },
      "CreateSheetOptions": {
        "type": "object", "additionalProperties": false,
        "required": ["title"],
        "properties": {
          "title": { "type": "string", "maxLength": 120, "description": "UTF-8 title for a localized default sheet." }
        }
      },
      "ReadSheet": {
        "type": "object", "additionalProperties": false,
        "required": ["access", "revision", "document"],
        "properties": {
          "access": { "const": "read" },
          "revision": { "type": "integer", "minimum": 0 },
          "document": { "$ref": "#/components/schemas/SheetDocument" }
        }
      },
      "WriteSheet": {
        "type": "object", "additionalProperties": false,
        "required": ["access", "read_url", "recovery_email", "revision", "document"],
        "properties": {
          "access": { "const": "write" },
          "read_url": { "type": "string" },
          "recovery_email": { "type": "string", "maxLength": 254 },
          "revision": { "type": "integer", "minimum": 0 },
          "document": { "$ref": "#/components/schemas/SheetDocument" }
        }
      },
      "ReadMetadata": {
        "type": "object", "additionalProperties": false,
        "required": ["access", "revision", "is_locked"],
        "properties": { "access": { "const": "read" }, "revision": { "type": "integer", "minimum": 0 }, "is_locked": { "type": "boolean" } }
      },
      "WriteMetadata": {
        "type": "object", "additionalProperties": false,
        "required": ["access", "read_url", "revision", "is_locked"],
        "properties": { "access": { "const": "write" }, "read_url": { "type": "string" }, "revision": { "type": "integer", "minimum": 0 }, "is_locked": { "type": "boolean" } }
      },
      "Revision": {
        "type": "object", "additionalProperties": false,
        "required": ["revision"], "properties": { "revision": { "type": "integer", "minimum": 0 } }
      },
      "Conflict": {
        "type": "object", "additionalProperties": false,
        "required": ["error", "revision"],
        "properties": { "error": { "const": "revision_conflict" }, "revision": { "type": "integer", "minimum": 0 } }
      },
      "Error": {
        "type": "object", "additionalProperties": false,
        "required": ["error"], "properties": { "error": { "type": "string" } }
      },
      "RecoveryEmail": {
        "type": "object", "additionalProperties": false,
        "required": ["recovery_email"],
        "properties": { "recovery_email": { "type": "string", "maxLength": 254 } }
      },
      "PlainTextDocument": {
        "type": "string",
        "description": "UTF-8 a4list plain text; see /plain_text_format.md."
      },
      "SheetDocument": {
        "type": "object", "additionalProperties": false,
        "required": ["schema_version", "title", "paper", "print", "panels"],
        "properties": {
          "schema_version": { "const": 2 },
          "title": { "type": "string", "maxLength": 120 },
          "paper": { "$ref": "#/components/schemas/Paper" },
          "print": { "$ref": "#/components/schemas/PrintSettings" },
          "panels": { "type": "object", "minProperties": 4, "maxProperties": 4, "propertyNames": { "pattern": "^pn_[0-9a-f]{16}$" }, "additionalProperties": { "$ref": "#/components/schemas/Panel" } }
        }
      },
      "Paper": {
        "type": "object", "additionalProperties": false,
        "required": ["key", "label", "width_mm", "height_mm", "panel_width_mm", "panel_height_mm", "grid_mm"],
        "properties": {
          "key": { "const": "a4" }, "label": { "const": "A4 / four A6 panels" },
          "width_mm": { "const": 210 }, "height_mm": { "const": 297 },
          "panel_width_mm": { "const": 105 }, "panel_height_mm": { "const": 148.5 }, "grid_mm": { "const": 5 }
        }
      },
      "PrintSettings": {
        "type": "object", "additionalProperties": false,
        "required": ["show_qr", "show_sheet_url", "qr_links_to_read_only", "checklist_box_count"],
        "properties": {
          "show_qr": { "type": "boolean" }, "show_sheet_url": { "type": "boolean" }, "qr_links_to_read_only": { "type": "boolean" },
          "checklist_box_count": { "type": "integer", "enum": [7, 14], "description": "Use one week of seven boxes or two weeks of fourteen boxes on every checklist row." }
        }
      },
      "Panel": {
        "type": "object", "additionalProperties": false,
        "required": ["position", "is_print_enabled", "mirror_source_panel_id", "rows"],
        "properties": {
          "position": { "type": "integer", "minimum": 0, "maximum": 3 },
          "is_print_enabled": { "type": "boolean" },
          "mirror_source_panel_id": { "oneOf": [{ "type": "null" }, { "type": "string", "pattern": "^pn_[0-9a-f]{16}$" }] },
          "rows": { "type": "object", "minProperties": 28, "maxProperties": 28, "propertyNames": { "pattern": "^rw_[0-9a-f]{16}$" }, "additionalProperties": { "$ref": "#/components/schemas/Row" } }
        }
      },
      "Row": {
        "type": "object", "additionalProperties": false,
        "required": ["sort_key", "row_kind", "has_line", "label"],
        "properties": {
          "sort_key": { "type": "string", "minLength": 1, "maxLength": 64 },
          "row_kind": { "enum": ["gap", "checklist"] },
          "has_line": { "type": "boolean" },
          "label": { "type": "string", "maxLength": 200 }
        }
      }
    }
  }
}
