{
  "openapi": "3.1.1",
  "info": {
    "title": "Printshop API",
    "version": "1.0.0",
    "summary": "Deterministic tools for people and AI agents.",
    "description": "Every endpoint performs the same calculation as the human page and returns inputs, result, units, assumptions, sources, warnings and computedAt. MCP endpoint: /mcp."
  },
  "servers": [
    {
      "url": "https://printshop.usefulweb.site"
    }
  ],
  "paths": {
    "/api/v1/tools": {
      "get": {
        "operationId": "listTools",
        "summary": "Catalog of all tools",
        "responses": {
          "200": {
            "description": "Tool list.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/tools/{id}": {
      "get": {
        "operationId": "getTool",
        "summary": "Definition of one tool",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "type": "string",
              "enum": [
                "printshop-qr-code",
                "printshop-barcode",
                "printshop-calendar",
                "printshop-label-sheet",
                "printshop-graph-paper",
                "printshop-poster-tiler",
                "printshop-booklet",
                "printshop-sudoku",
                "printshop-maze",
                "printshop-word-search",
                "printshop-crossword-fill",
                "printshop-nonogram",
                "printshop-math-worksheet",
                "ruledate",
                "lumina-print-planner",
                "lumina-image-splitter",
                "panelcraft-book-plan"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Tool definition.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "404": {
            "description": "Invalid input (see errors[]).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/tools/printshop-qr-code/calculate": {
      "post": {
        "operationId": "calculatePrintshopQrCode",
        "summary": "QR codes for links, text, Wi-Fi, contacts and more — as vector PDF, SVG and PNG.",
        "description": "Encode a link, text, Wi-Fi login, contact card, e-mail, phone, SMS or map location as a QR code following ISO/IEC 18004 (versions 1–40, error correction L/M/Q/H, optimal mode switching, all eight masks scored). Get a print page with a test square, the code alone as SVG and PNG, a sheet of copies or Wi-Fi guest cards.\n\nMethodology:\n- Data is split into numeric, alphanumeric and byte (UTF-8) segments with the fewest bits (dynamic programming over the bit costs of ISO/IEC 18004 §7.4); the smallest version 1–40 that holds it at the chosen error-correction level is used.\n- Reed–Solomon error correction over GF(256) (polynomial 0x11D), block interleaving after Table 9, all eight masks scored with the four penalty rules and the lowest chosen; format and version information use the BCH codes of §7.9–7.10.\n- The logo-safe area clears the centre modules (never finder, timing or alignment patterns) and counts, per Reed–Solomon block, how many codewords it touches; the area is reported safe only when that stays within half of the block’s error-correction codewords.\n- Wi-Fi codes use the WIFI:T:…;S:…;P:…;; format read by phone cameras (special characters escaped). Pages print at true size with a 20 mm (or 1 in) test square.\n\n“QR Code” is a registered trademark of DENSO WAVE INCORPORATED. Test a printed code with the phones of your audience before printing many copies.",
        "tags": [
          "apps"
        ],
        "x-mcp-tool": "printshop_qr_code",
        "x-owner-app": "printshop",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PrintshopQrCodeInput"
              },
              "examples": {
                "example1": {
                  "summary": "Link to a website",
                  "value": {
                    "content": "url",
                    "text": "https://usefulweb.site/",
                    "ecc": "M",
                    "size": 60
                  }
                },
                "example2": {
                  "summary": "Wi-Fi guest cards",
                  "value": {
                    "content": "wifi",
                    "ssid": "Guest network",
                    "password": "sunny-garden-2027",
                    "security": "WPA",
                    "layout": "wifi-card"
                  }
                },
                "example3": {
                  "summary": "Sheet of small codes with a logo-safe centre",
                  "value": {
                    "content": "text",
                    "text": "Table 12 · ask for the menu",
                    "ecc": "H",
                    "size": 40,
                    "logo": 20,
                    "layout": "sheet",
                    "caption": "Scan for the menu"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Calculation result envelope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PrintshopQrCodeResult"
                }
              }
            }
          },
          "400": {
            "description": "Malformed JSON body.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "Invalid input (see errors[]).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded (see Retry-After).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/tools/printshop-barcode/calculate": {
      "post": {
        "operationId": "calculatePrintshopBarcode",
        "summary": "EAN-13, UPC-A and Code 128 barcodes with check digits, true-size PDF, SVG and PNG.",
        "description": "Make an EAN-13, UPC-A or Code 128 barcode. EAN/UPC check digits are calculated (or verified), Code 128 switches between code sets A, B and C for the shortest symbol, and the result prints at GS1 sizes with quiet zones and a test square.\n\nMethodology:\n- EAN-13: the first digit selects the L/G parity pattern of the left half (GS1 table), the right half uses R codes; the check digit is the mod-10 sum with weights 3 and 1 from the right. UPC-A is encoded as EAN-13 with a leading 0.\n- Code 128: a dynamic programme over (position, active code set) picks start code, CODE A/B/C switches and SHIFT for the fewest symbol characters; check value = (start + Σ value × position) mod 103.\n- Sizes: EAN/UPC module 0.330 mm × magnification (80–200 %), bar height 22.85 mm × magnification, guard bars 5 modules longer; quiet zones 11/7 modules (EAN-13), 9/9 (UPC-A), 10/10 (Code 128).\n\nRetail EAN/UPC numbers must be licensed from GS1; making a barcode does not register a product number. Check print quality with a scanner before mass printing.",
        "tags": [
          "apps"
        ],
        "x-mcp-tool": "printshop_barcode",
        "x-owner-app": "printshop",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PrintshopBarcodeInput"
              },
              "examples": {
                "example1": {
                  "summary": "EAN-13 with the check digit added",
                  "value": {
                    "symbology": "ean13",
                    "data": "400638133393"
                  }
                },
                "example2": {
                  "summary": "UPC-A",
                  "value": {
                    "symbology": "upca",
                    "data": "03600029145"
                  }
                },
                "example3": {
                  "summary": "Code 128 for a parcel reference",
                  "value": {
                    "symbology": "code128",
                    "data": "PO-2027-000123",
                    "height": 15,
                    "layout": "sheet"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Calculation result envelope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PrintshopBarcodeResult"
                }
              }
            }
          },
          "400": {
            "description": "Malformed JSON body.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "Invalid input (see errors[]).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded (see Retry-After).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/tools/printshop-calendar/calculate": {
      "post": {
        "operationId": "calculatePrintshopCalendar",
        "summary": "Month or year calendars in 17 languages with week numbers and public holidays.",
        "description": "Make a printable calendar for any year: one month per page or the whole year on one page, in 17 languages including right-to-left Arabic, with ISO 8601 or US week numbers, the first weekday of the region and public holidays for 16 countries (2024–2030).\n\nMethodology:\n- Month grids use the proleptic Gregorian calendar in UTC. The first weekday follows CLDR week data for the region (for example Sunday in the US, Monday in Germany, Saturday in Egypt) unless you choose one.\n- ISO 8601 weeks start on Monday and week 1 contains the year’s first Thursday; a row shows the ISO week of its Monday. US weeks start on Sunday and week 1 contains 1 January; a row shows the US week of its Saturday.\n- Month and weekday names come from the CLDR data built into the JavaScript runtime (Intl.DateTimeFormat). Arabic calendars run right to left. Text is shaped and embedded with Noto fonts.\n- Public holidays come from the RuleDate data set (Nager.Date) for 16 countries, 2024–2030; regional holidays need an ISO 3166-2 region code.\n\nHoliday data covers 2024–2030 and nationwide plus listed regional holidays; school holidays and local observances are not included. Check dates that matter.",
        "tags": [
          "apps"
        ],
        "x-mcp-tool": "printshop_calendar",
        "x-owner-app": "printshop",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PrintshopCalendarInput"
              },
              "examples": {
                "example1": {
                  "summary": "German 2027 wall calendar with ISO weeks and Bavarian holidays",
                  "value": {
                    "year": 2027,
                    "lang": "de",
                    "country": "DE",
                    "subdivision": "DE-BY",
                    "weekNumbers": "iso"
                  }
                },
                "example2": {
                  "summary": "US year at a glance on Letter landscape",
                  "value": {
                    "year": 2027,
                    "layout": "year",
                    "country": "US",
                    "paper": "letter",
                    "orientation": "landscape",
                    "weekNumbers": "us"
                  }
                },
                "example3": {
                  "summary": "Arabic six-month calendar",
                  "value": {
                    "year": 2027,
                    "months": 6,
                    "lang": "ar",
                    "weekStart": "sat"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Calculation result envelope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PrintshopCalendarResult"
                }
              }
            }
          },
          "400": {
            "description": "Malformed JSON body.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "Invalid input (see errors[]).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded (see Retry-After).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/tools/printshop-label-sheet/calculate": {
      "post": {
        "operationId": "calculatePrintshopLabelSheet",
        "summary": "Address labels, name badges and product labels from a CSV, for any sheet layout.",
        "description": "Fill a sheet of labels from CSV rows with a {Column} template: address labels, name badges, jar and product labels. Use a generic sheet layout or enter your own geometry, skip labels already used, add a QR code or barcode per label and print a true-size PDF.\n\nMethodology:\n- CSV is read after RFC 4180 (quoted fields, doubled quotes, line breaks inside quotes); comma, semicolon or tab is detected from the header line. Each row fills the {Column} placeholders of the template.\n- Label n sits at left + column × horizontal pitch, top + row × vertical pitch, filled row by row; “start at” skips used positions on the first sheet. Presets are generic dimension sets (no brand or product numbers).\n- Text is wrapped to the label width and reduced in 10 % steps until it fits; labels whose text still does not fit are counted as overflow. A QR code takes up to 45 % of the width; barcodes sit at the bottom.\n\nPrinters shift paper by up to a millimetre or two. Print one test page on plain paper, hold it against a label sheet and adjust the margins before printing on labels.",
        "tags": [
          "apps"
        ],
        "x-mcp-tool": "printshop_label_sheet",
        "x-owner-app": "printshop",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PrintshopLabelSheetInput"
              },
              "examples": {
                "example1": {
                  "summary": "Address labels on a 3 × 8 sheet",
                  "value": {}
                },
                "example2": {
                  "summary": "Jar labels with a QR code, starting at label 4",
                  "value": {
                    "sheet": "a4-3x7-63x38",
                    "template": "{Product}\nBest before {Date}",
                    "csv": "Product,Date,Code\nPlum jam,2028-06,https://example.com/jam/plum\nApricot jam,2028-07,https://example.com/jam/apricot",
                    "code": "qr",
                    "codeTemplate": "{Code}",
                    "fontSize": 4.5,
                    "align": "start",
                    "startAt": 4,
                    "outlines": true
                  }
                },
                "example3": {
                  "summary": "Custom 2 × 3 badges",
                  "value": {
                    "sheet": "custom",
                    "cols": 2,
                    "rows": 3,
                    "labelW": 90,
                    "labelH": 80,
                    "top": 18.5,
                    "left": 12,
                    "pitchX": 96,
                    "pitchY": 88,
                    "template": "{Name}\n{Team}",
                    "csv": "Name,Team\nAlex,Design\nSam,Support\nKim,Finance",
                    "align": "middle",
                    "fontSize": 8,
                    "outlines": true
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Calculation result envelope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PrintshopLabelSheetResult"
                }
              }
            }
          },
          "400": {
            "description": "Malformed JSON body.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "Invalid input (see errors[]).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded (see Retry-After).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/tools/printshop-graph-paper/calculate": {
      "post": {
        "operationId": "calculatePrintshopGraphPaper",
        "summary": "Printable grid, dot, isometric, hexagon, music staff and lined paper at exact sizes.",
        "description": "Make printable paper with a square grid (with major lines), dot grid, isometric triangles, hexagons, music staves or writing lines. Spacing is exact in millimetres, the grid is centred on the page and a 10 cm scale bar lets you check the printer scale.\n\nMethodology:\n- Square and dot grids use whole cells centred in the area inside the margin, so leftover space is split evenly. Major lines count from the first line.\n- Isometric paper draws three families of lines (horizontal and ±60°) that form equilateral triangles of the given side; hexagons are regular with the given side, in offset rows (pointy top) or columns (flat top).\n- Music staves have five lines with the given spacing and a gap of 1.75 staff heights between staves. Lined paper starts one line spacing below the top margin.\n\nPrint at 100 % (actual size) and check the 10 cm scale bar: “fit to page” changes every spacing.",
        "tags": [
          "apps"
        ],
        "x-mcp-tool": "printshop_graph_paper",
        "x-owner-app": "printshop",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PrintshopGraphPaperInput"
              },
              "examples": {
                "example1": {
                  "summary": "5 mm grid with centimetre lines",
                  "value": {
                    "kind": "grid",
                    "spacing": 5,
                    "majorEvery": 2
                  }
                },
                "example2": {
                  "summary": "Dot grid journal page",
                  "value": {
                    "kind": "dots",
                    "spacing": 5,
                    "majorEvery": 0,
                    "color": "#8f9aa6"
                  }
                },
                "example3": {
                  "summary": "Isometric drawing paper",
                  "value": {
                    "kind": "isometric",
                    "spacing": 8,
                    "majorEvery": 0
                  }
                },
                "example4": {
                  "summary": "Music staff paper",
                  "value": {
                    "kind": "music",
                    "spacing": 2,
                    "header": true
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Calculation result envelope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PrintshopGraphPaperResult"
                }
              }
            }
          },
          "400": {
            "description": "Malformed JSON body.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "Invalid input (see errors[]).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded (see Retry-After).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/tools/printshop-poster-tiler/calculate": {
      "post": {
        "operationId": "calculatePrintshopPosterTiler",
        "summary": "Print a big poster on ordinary paper: tiles with overlap, crop marks and an assembly map.",
        "description": "Enlarge a JPEG or PNG to a poster of any width and split it over A4, Letter or other sheets with overlap, trim lines, crop marks, alignment crosses and tile names, plus a cover page with the assembly map, the effective resolution and a test square. Without an image you get the tiling plan.\n\nMethodology:\n- Printable area = paper − 2 × margin; each next sheet starts one step = printable − overlap further, so neighbouring sheets share the overlap strip. Sheets across = ceil((poster − overlap) / step); with “fewest sheets” both orientations are tried.\n- The image is embedded once (JPEG unchanged, PNG losslessly compressed) and every sheet shows its part through a clipping rectangle, so the PDF stays small and keeps the full resolution.\n- Effective resolution = image pixels ÷ poster inches (Lumina’s print planner gives the matching print size table). Below about 100 pixels per inch prints look soft up close.\n\nPrinters differ slightly in scale and margins: print the cover page first and measure the 50 mm test square. Interlaced PNG and CMYK JPEG files are not supported.",
        "tags": [
          "apps"
        ],
        "x-mcp-tool": "printshop_poster_tiler",
        "x-owner-app": "printshop",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PrintshopPosterTilerInput"
              },
              "examples": {
                "example1": {
                  "summary": "60 cm poster plan for a 4000 × 3000 photo",
                  "value": {
                    "imageWidth": 4000,
                    "imageHeight": 3000,
                    "width": 600
                  }
                },
                "example2": {
                  "summary": "One-metre portrait poster on Letter paper",
                  "value": {
                    "imageWidth": 3000,
                    "imageHeight": 4500,
                    "width": 1000,
                    "paper": "letter",
                    "overlap": 15
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Calculation result envelope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PrintshopPosterTilerResult"
                }
              }
            }
          },
          "400": {
            "description": "Malformed JSON body.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "Invalid input (see errors[]).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded (see Retry-After).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/tools/printshop-booklet/calculate": {
      "post": {
        "operationId": "calculatePrintshopBooklet",
        "summary": "Fold-and-staple booklets: notebook or calendar pages imposed in the right order.",
        "description": "Make a saddle-stitched booklet: pages of grid, dot or lined paper (a notebook) or a month-per-page calendar are padded to a multiple of four and printed two per sheet side in booklet order, with optional creep compensation, page numbers and fold marks. Prints double-sided, flip on the short edge.\n\nMethodology:\n- Pages are padded with blanks to a multiple of four. Sheet k (from the outside) carries pages (n − 2k, 2k + 1) on the front and (2k + 2, n − 2k − 1) on the back — Panelcraft’s booklet order; right-edge binding swaps each pair.\n- Each page is scaled uniformly into half of the landscape sheet and centred; with creep compensation the pages of sheet k move k × creep towards the fold, because inner sheets stick out further after folding.\n- The PDF alternates front and back of each sheet: print double-sided, flipping on the short edge, then fold the stack and staple along the fold.\n\nDuplex settings differ between printers: print the first sheet and check the page order before printing all.",
        "tags": [
          "apps"
        ],
        "x-mcp-tool": "printshop_booklet",
        "x-owner-app": "printshop",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PrintshopBookletInput"
              },
              "examples": {
                "example1": {
                  "summary": "16-page dot-grid pocket notebook",
                  "value": {
                    "source": "ruled",
                    "pages": 16,
                    "kind": "dots"
                  }
                },
                "example2": {
                  "summary": "2027 pocket calendar (12 months, 3 sheets)",
                  "value": {
                    "source": "calendar",
                    "year": 2027
                  }
                },
                "example3": {
                  "summary": "Right-bound 8-page lined booklet with creep",
                  "value": {
                    "source": "ruled",
                    "pages": 8,
                    "kind": "lined",
                    "spacing": 7,
                    "reading": "rtl",
                    "creep": 0.1
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Calculation result envelope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PrintshopBookletResult"
                }
              }
            }
          },
          "400": {
            "description": "Malformed JSON body.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "Invalid input (see errors[]).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded (see Retry-After).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/tools/printshop-sudoku/calculate": {
      "post": {
        "operationId": "calculatePrintshopSudoku",
        "summary": "Printable sudokus with one solution, graded by the solving techniques needed.",
        "description": "Make printable sudokus from 4 × 4 for young children to 16 × 16 for experts. Every puzzle is proven to have exactly one solution, its difficulty is graded by the techniques a person needs (singles, locked candidates, pairs, triples, X-wing), and answer-key pages follow. Up to six per page, as a true-size PDF.\n\nMethodology:\n- A full grid is filled by a randomised depth-first search that always tries the cell with the fewest candidates. Clues are then removed in a seeded order (in pairs when symmetric); a removal is kept only when a counting solver still finds exactly one solution — a count that runs out of its node budget keeps the clue, so uniqueness is always proven.\n- Difficulty: a logic solver applies techniques from simple to hard — naked and hidden singles (easy), locked candidates (medium), naked and hidden pairs, naked triples and X-wing (hard). The grade is the hardest technique it needed; “expert” puzzles are unique but need more (chains or trial and error). For easy and medium a removal is also undone when the puzzle would need harder techniques.\n- Easy puzzles keep at least 45 % of the cells as clues, medium at least 32 %. Several digging orders are tried and the one that matches the requested level best is kept; the printed level is always the measured one.\n\nDifficulty is measured by technique, not by solving time; people find different techniques hard. 16 × 16 grids have a time budget and may keep a few extra clues.",
        "tags": [
          "apps"
        ],
        "x-mcp-tool": "printshop_sudoku",
        "x-owner-app": "printshop",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PrintshopSudokuInput"
              },
              "examples": {
                "example1": {
                  "summary": "Four medium 9 × 9 sudokus on one page",
                  "value": {
                    "size": "9",
                    "difficulty": "medium",
                    "count": 4,
                    "perPage": "4",
                    "seed": "sudoku-1"
                  }
                },
                "example2": {
                  "summary": "Six easy 6 × 6 sudokus for children",
                  "value": {
                    "size": "6",
                    "difficulty": "easy",
                    "count": 6,
                    "perPage": "6",
                    "seed": "kids-1"
                  }
                },
                "example3": {
                  "summary": "One hard 12 × 12 sudoku",
                  "value": {
                    "size": "12",
                    "difficulty": "hard",
                    "count": 1,
                    "perPage": "1",
                    "seed": "big-1"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Calculation result envelope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PrintshopSudokuResult"
                }
              }
            }
          },
          "400": {
            "description": "Malformed JSON body.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "Invalid input (see errors[]).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded (see Retry-After).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/tools/printshop-maze/calculate": {
      "post": {
        "operationId": "calculatePrintshopMaze",
        "summary": "Printable mazes in squares, hexagons or circles, cut to a heart, star or your own shape.",
        "description": "Make printable mazes with square or hexagon cells or round “theta” mazes, optionally cut to a heart, star, circle, diamond, triangle or a shape you draw with # signs. Choose the recursive backtracker (long corridors), Kruskal or Wilson (uniform random) algorithm, up to six mazes per page and answer keys with the solution path.\n\nMethodology:\n- Every shape is a graph of cells whose sides are either shared with a neighbour or part of the outer wall. Square and hexagon grids can be cut to an outline (tested at each cell centre); only the largest connected group of cells is kept. Round mazes have one centre cell and rings whose cell count doubles when cells get wider than two ring heights.\n- The maze is a spanning tree of that graph, so exactly one path joins the entrance (top) and the exit (bottom, or the centre of a round maze). Recursive backtracker = randomised depth-first search (about 10 % dead ends); Kruskal = random walls removed with union–find (about 30 %); Wilson = loop-erased random walks, which pick every possible maze with the same probability.\n- The solution is found by breadth-first search through the open passages and drawn through the cell centres and the middle of each passage.\n\nVery large mazes on small paper get thin walls; check the PNG preview before printing many copies.",
        "tags": [
          "apps"
        ],
        "x-mcp-tool": "printshop_maze",
        "x-owner-app": "printshop",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PrintshopMazeInput"
              },
              "examples": {
                "example1": {
                  "summary": "Classic 16 × 20 maze",
                  "value": {
                    "shape": "rect",
                    "cols": 16,
                    "rows": 20,
                    "algorithm": "backtracker",
                    "seed": "maze-1"
                  }
                },
                "example2": {
                  "summary": "Four heart-shaped mazes per page",
                  "value": {
                    "shape": "rect",
                    "cols": 24,
                    "rows": 22,
                    "mask": "heart",
                    "count": 4,
                    "perPage": "4",
                    "seed": "hearts"
                  }
                },
                "example3": {
                  "summary": "Round maze with 14 rings (Wilson)",
                  "value": {
                    "shape": "circle",
                    "rows": 14,
                    "algorithm": "wilson",
                    "seed": "round-1"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Calculation result envelope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PrintshopMazeResult"
                }
              }
            }
          },
          "400": {
            "description": "Malformed JSON body.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "Invalid input (see errors[]).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded (see Retry-After).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/tools/printshop-word-search/calculate": {
      "post": {
        "operationId": "calculatePrintshopWordSearch",
        "summary": "Printable word searches from your own words, in any language and script.",
        "description": "Turn your own word list into a printable word search: grid size automatic or fixed, diagonal and backwards words optional, shared letters allowed or not. Works letter by letter in every script — accents, Cyrillic, Greek, Devanagari, Chinese and right-to-left Arabic — and adds an answer key with every word circled.\n\nMethodology:\n- Words are normalised (Unicode NFC, spaces and punctuation removed, optional capitals with the language’s rules, e.g. Turkish İ) and split into user-perceived characters (Unicode grapheme clusters, UAX #29): one character per cell.\n- Longest words are placed first at random allowed positions (right and down, optionally the two diagonals and all reversed directions); shared letters are preferred when allowed. With automatic size the grid grows from about √(letters × 2) until every word fits.\n- Empty cells get random letters taken from your words, so the filler matches the script. Any word that appears a second time by accident gets its filler letters redrawn, so each word can be found exactly once. Right-to-left word lists are mirrored so “forwards” reads right to left.\n\nChinese, Japanese and Korean grids print only characters in Printshop’s font subsets; missing characters are reported as a warning.",
        "tags": [
          "apps"
        ],
        "x-mcp-tool": "printshop_word_search",
        "x-owner-app": "printshop",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PrintshopWordSearchInput"
              },
              "examples": {
                "example1": {
                  "summary": "Space words with diagonals",
                  "value": {
                    "seed": "space-1"
                  }
                },
                "example2": {
                  "summary": "German animals, backwards too",
                  "value": {
                    "words": "Fuchs, Igel, Eichhörnchen, Dachs, Reh, Biber, Hase, Maus, Specht, Eule",
                    "backwards": true,
                    "lang": "de",
                    "seed": "wald"
                  }
                },
                "example3": {
                  "summary": "Arabic words (right to left)",
                  "value": {
                    "words": "شمس\nقمر\nنجمة\nسماء\nبحر\nجبل\nشجرة\nوردة",
                    "lang": "ar",
                    "diagonal": false,
                    "seed": "ar-1"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Calculation result envelope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PrintshopWordSearchResult"
                }
              }
            }
          },
          "400": {
            "description": "Malformed JSON body.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "Invalid input (see errors[]).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded (see Retry-After).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/tools/printshop-crossword-fill/calculate": {
      "post": {
        "operationId": "calculatePrintshopCrosswordFill",
        "summary": "Criss-cross crosswords from your own words and clues, numbered, with an answer key.",
        "description": "Write one “word: clue” per line and get a printable criss-cross crossword: the words are interlocked into a compact grid, numbered in reading order, with Across and Down clue lists and the word lengths. Works in any script, including right-to-left Arabic.\n\nMethodology:\n- Only your words are used (no dictionary). Words are split into grapheme clusters like the word search. The first word is laid down, and every further word must cross a letter that is already in the grid; a placement is rejected when it would run into another word or put letters side by side.\n- Among the valid placements the one with the most crossings and the smallest grid wins; 40 seeded attempts with different word orders are compared and the layout with the most placed words, then the most crossings, then the smallest area is kept (at most 30 × 30 cells).\n- Numbers follow the reading order of the grid (right to left for Arabic and Hebrew lists); a cell that starts an Across and a Down word gets one number.\n\nWords without a shared letter cannot be joined and are left out (listed as a warning). This is a criss-cross puzzle, not a dense newspaper crossword.",
        "tags": [
          "apps"
        ],
        "x-mcp-tool": "printshop_crossword_fill",
        "x-owner-app": "printshop",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PrintshopCrosswordFillInput"
              },
              "examples": {
                "example1": {
                  "summary": "Seaside vocabulary with clues",
                  "value": {
                    "seed": "sea-1"
                  }
                },
                "example2": {
                  "summary": "Spanish fruit (clues in English)",
                  "value": {
                    "words": "manzana: apple\nplátano: banana\nnaranja: orange\nfresa: strawberry\nuva: grape\npera: pear\nlimón: lemon\nsandía: watermelon",
                    "lang": "es",
                    "seed": "frutas"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Calculation result envelope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PrintshopCrosswordFillResult"
                }
              }
            }
          },
          "400": {
            "description": "Malformed JSON body.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "Invalid input (see errors[]).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded (see Retry-After).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/tools/printshop-nonogram/calculate": {
      "post": {
        "operationId": "calculatePrintshopNonogram",
        "summary": "Nonograms from a drawing or an image, checked for one solution and fixed with givens.",
        "description": "Turn a pixel drawing, a built-in picture or a PNG image into a printable nonogram (picross, griddler) with row and column clues. A line solver checks that the puzzle can be solved without guessing; if not, it adds as few given cells as it can until it can. Answer key included.\n\nMethodology:\n- Clues are the lengths of the runs of filled cells in each row and column. Images are reduced to the chosen grid by averaging the Rec. 709 luminance of each cell (transparent parts count as white) and comparing with the threshold.\n- Line solver: for one row or column, a dynamic programme over (cell, block) from both ends marks every cell that is filled in all placements of the blocks consistent with the known cells, or empty in all of them. Rows and columns are repeated until nothing changes. If that solves the grid, the solution is unique.\n- Fix: while cells stay undecided, the undecided cell that settles the most other cells when revealed is printed as a given (filled square or a cross) and the line solver runs again.\n\nPhotos rarely make good nonograms; simple shapes with clear outlines work best. Without givens, a puzzle that is not line-solvable may have several solutions.",
        "tags": [
          "apps"
        ],
        "x-mcp-tool": "printshop_nonogram",
        "x-owner-app": "printshop",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PrintshopNonogramInput"
              },
              "examples": {
                "example1": {
                  "summary": "Built-in cat",
                  "value": {
                    "source": "picture",
                    "picture": "cat"
                  }
                },
                "example2": {
                  "summary": "Your own drawing",
                  "value": {
                    "source": "grid",
                    "grid": "..####..\n.#....#.\n#.#..#.#\n#......#\n#.#..#.#\n#..##..#\n.#....#.\n..####..",
                    "seed": "smile"
                  }
                },
                "example3": {
                  "summary": "Rocket without automatic givens",
                  "value": {
                    "source": "picture",
                    "picture": "rocket",
                    "fix": false
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Calculation result envelope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PrintshopNonogramResult"
                }
              }
            }
          },
          "400": {
            "description": "Malformed JSON body.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "Invalid input (see errors[]).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded (see Retry-After).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/tools/printshop-math-worksheet/calculate": {
      "post": {
        "operationId": "calculatePrintshopMathWorksheet",
        "summary": "Times tables, column sums, division and fractions — seeded variants with answer keys.",
        "description": "Make maths worksheets for the classroom or home: times tables, column addition and subtraction with or without carrying, long multiplication, division with or without remainders, fractions, or a mix of facts. Up to six variants (A to F) give neighbours different problems of the same difficulty, each with its answer key.\n\nMethodology:\n- Each variant letter has its own seeded random stream (seed + letter), so variant B is always the same for the same seed and differs from A. Repeated problems are avoided within a variant.\n- Column addition without carrying keeps every digit sum below 10; subtraction without borrowing keeps every digit of the first number at least as large as the one below it (and the result never negative). With regrouping allowed, problems that actually need it are preferred.\n- Division problems are built backwards (divisor × quotient + remainder), so answers are whole numbers. Fraction answers are reduced with the greatest common divisor; subtraction never goes below zero.\n\nCheck that the exercise type fits the class level; the generator does not follow a particular curriculum.",
        "tags": [
          "apps"
        ],
        "x-mcp-tool": "printshop_math_worksheet",
        "x-owner-app": "printshop",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PrintshopMathWorksheetInput"
              },
              "examples": {
                "example1": {
                  "summary": "Times tables 2–10, variants A–C",
                  "value": {
                    "kind": "times",
                    "tables": "2-10",
                    "count": 30,
                    "variants": 3,
                    "seed": "class-4b"
                  }
                },
                "example2": {
                  "summary": "Three-digit subtraction with borrowing",
                  "value": {
                    "kind": "sub",
                    "digits": 3,
                    "regroup": true,
                    "count": 24,
                    "variants": 2,
                    "seed": "sub-3"
                  }
                },
                "example3": {
                  "summary": "Adding fractions with like denominators",
                  "value": {
                    "kind": "fractions",
                    "fractionOps": "add",
                    "sameDenominator": true,
                    "maxDenominator": 12,
                    "count": 20,
                    "variants": 1,
                    "seed": "frac-1"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Calculation result envelope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PrintshopMathWorksheetResult"
                }
              }
            }
          },
          "400": {
            "description": "Malformed JSON body.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "Invalid input (see errors[]).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded (see Retry-After).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/tools/ruledate/calculate": {
      "post": {
        "operationId": "calculateRuledate",
        "summary": "Business-day and deadline maths with public holidays and a step-by-step rule trace.",
        "description": "Chain date operations (add business days, add months with clamping, end of month, roll to next business day) on a start date. RuleDate uses public holidays for 16 countries and their subdivisions (2024–2030) and shows every skipped date with its reason, so the result can be checked rather than trusted.\n\nMethodology:\n- A business day is a day that is not a selected weekend day, not a public holiday of the chosen country (nationwide, or of the chosen subdivision) and not an extra closure date. Only Nager.Date entries of type \"Public\" count; bank, school, optional and observance days are ignored.\n- Add business days counts business days after the start date (the start date itself is not counted); negative amounts count backwards. Every non-business day passed over is listed with all its reasons.\n- Add calendar days / weeks ignore holidays. Add months keeps the day of month; if it does not exist, \"clamp\" uses the month’s last day and \"overflow\" rolls into the next month.\n- End of month moves to the last calendar day of the month that is `amount` months after the current date. Next / previous business day roll only if the current date is not a business day (following / preceding convention).\n- Optional final rule modelled on § 193 BGB: if the result falls on a Saturday, Sunday or a public holiday at the chosen place, it moves to the next day that is none of these (extra closures and custom weekends are ignored for this rule).\n- Holiday data covers 2024–2030; dates outside that range are checked for weekends and closures only and trigger a warning.\n\nNot legal advice. Statutory and contractual deadlines have their own rules (start-day exclusion, service dates, court holidays, local holidays); verify critical deadlines with a qualified professional.",
        "tags": [
          "developer"
        ],
        "x-mcp-tool": "ruledate",
        "x-owner-app": "opsdeck",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RuledateInput"
              },
              "examples": {
                "example1": {
                  "summary": "10 business days from 25 Sep 2026 in Bavaria",
                  "value": {
                    "startDate": "2026-09-25",
                    "operations": [
                      {
                        "op": "add-business-days",
                        "amount": 10
                      }
                    ],
                    "country": "DE",
                    "subdivision": "DE-BY"
                  }
                },
                "example2": {
                  "summary": "5 business days over Christmas in England, then end of month",
                  "value": {
                    "startDate": "2026-12-21",
                    "operations": [
                      {
                        "op": "add-business-days",
                        "amount": 5
                      },
                      {
                        "op": "end-of-month",
                        "amount": 0
                      },
                      {
                        "op": "previous-business-day"
                      }
                    ],
                    "country": "GB",
                    "subdivision": "GB-ENG"
                  }
                },
                "example3": {
                  "summary": "31 Aug + 1 month (clamped) + 3 days, § 193 BGB adjustment",
                  "value": {
                    "startDate": "2026-08-31",
                    "operations": [
                      {
                        "op": "add-months",
                        "amount": 1
                      },
                      {
                        "op": "add-calendar-days",
                        "amount": 3
                      }
                    ],
                    "country": "DE",
                    "finalRule": "bgb193"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Calculation result envelope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RuledateResult"
                }
              }
            }
          },
          "400": {
            "description": "Malformed JSON body.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "Invalid input (see errors[]).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded (see Retry-After).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/tools/lumina-print-planner/calculate": {
      "post": {
        "operationId": "calculateLuminaPrintPlanner",
        "summary": "Find how large your photo can print at your chosen resolution.",
        "description": "Convert image pixel dimensions into print dimensions in inches and centimeters at a specified pixels-per-inch resolution. Compare sizes without uploading the image.\n\nMethodology:\n- Print width in inches equals pixel width divided by PPI. One inch equals 2.54 centimeters.\n- PPI describes image pixel density, not printer dot density. Calculated dimensions do not guarantee print quality.",
        "tags": [
          "apps"
        ],
        "x-mcp-tool": "lumina_print_planner",
        "x-owner-app": "lumina",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/LuminaPrintPlannerInput"
              },
              "examples": {
                "example1": {
                  "summary": "24 MP photo at 300 PPI",
                  "value": {
                    "width": 6000,
                    "height": 4000,
                    "ppi": 300
                  }
                },
                "example2": {
                  "summary": "Web image at 150 PPI",
                  "value": {
                    "width": 1920,
                    "height": 1080,
                    "ppi": 150
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Calculation result envelope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LuminaPrintPlannerResult"
                }
              }
            }
          },
          "400": {
            "description": "Malformed JSON body.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "Invalid input (see errors[]).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded (see Retry-After).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/tools/lumina-image-splitter/calculate": {
      "post": {
        "operationId": "calculateLuminaImageSplitter",
        "summary": "Slice a photo into numbered tiles without losing edge pixels.",
        "description": "Split one image into a row-and-column grid and download every tile as a PNG in one ZIP. Uneven dimensions are distributed across the tiles so the complete photo can be reconstructed.\n\nMethodology:\n- The source is auto-oriented. Integer boundaries use floor(index × size / count), ensuring no gaps, overlaps or missing edge pixels.\n- At most 64 nonempty tiles; original decoded photo limited to 16 MP. ZIP names encode row and column.\n- Outputs are PNGs with original EXIF/GPS removed. The ZIP includes a JSON manifest with the exact tile coordinates.",
        "tags": [
          "apps"
        ],
        "x-mcp-tool": "lumina_image_splitter",
        "x-owner-app": "lumina",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/LuminaImageSplitterInput"
              },
              "examples": {
                "example1": {
                  "summary": "Three-by-three tiles",
                  "value": {
                    "images": {
                      "filename": "sample.png",
                      "contentType": "image/png",
                      "contentBase64": "iVBORw0KGgoAAAANSUhEUgAAACAAAAAgAQMAAABJtOi3AAAABlBMVEX/////AADrWueTAAAAEklEQVQI12NgIBb8/09dgjgAAPcnH+GApkH4AAAAAElFTkSuQmCC"
                    },
                    "rows": 3,
                    "columns": 3
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Calculation result envelope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LuminaImageSplitterResult"
                }
              }
            }
          },
          "400": {
            "description": "Malformed JSON body.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "Invalid input (see errors[]).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded (see Retry-After).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/tools/panelcraft-book-plan/calculate": {
      "post": {
        "operationId": "calculatePanelcraftBookPlan",
        "summary": "Plan a multi-page comic, contact sheet and folded booklet order.",
        "description": "Create an editable Panelcraft comic book with ordered pages and panel grids. Export a clean SVG contact sheet, complete lettering CSV and book project, plus a deterministic sheet-front and sheet-back imposition plan for a folded booklet.\n\nMethodology:\n- Create 1–12 pages using the same bounded Comic Desk page parser as the interactive workspace. Each page has 1–12 rectangular panels; page dimensions are 1000 × 1400 px at 150 DPI.\n- A contact sheet uses 360 px thumbnails, up to four columns, unique SVG definition IDs and a maximum area of 8 megapixels. It is an overview, not a print-size page export.\n- Booklet page count rounds up to a multiple of four. Sheet fronts pair the last and first remaining pages; backs pair the second and penultimate. Pages beyond the source count are blanks. Right-to-left binding reverses each pair. Consult the printer manual for duplex orientation.\n\nImposition is a page-order plan for manually arranging a folded booklet. It does not rescale pages to a printer sheet or set printer-specific duplex options.",
        "tags": [
          "apps"
        ],
        "x-mcp-tool": "panelcraft_book_plan",
        "x-owner-app": "panelcraft",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PanelcraftBookPlanInput"
              },
              "examples": {
                "example1": {
                  "summary": "An eight-page pocket comic",
                  "value": {}
                },
                "example2": {
                  "summary": "A six-page right-to-left draft",
                  "value": {
                    "pages": 6,
                    "reading": "rtl",
                    "rows": 1,
                    "columns": 2
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Calculation result envelope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PanelcraftBookPlanResult"
                }
              }
            }
          },
          "400": {
            "description": "Malformed JSON body.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "Invalid input (see errors[]).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded (see Retry-After).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/workflows": {
      "get": {
        "operationId": "listWorkflows",
        "summary": "Multi-tool workflows",
        "responses": {
          "200": {
            "description": "Workflow list.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "Problem": {
        "type": "object",
        "description": "RFC 9457 problem details. 422 responses include per-field `errors`.",
        "required": [
          "type",
          "title",
          "status",
          "detail"
        ],
        "properties": {
          "type": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "status": {
            "type": "integer"
          },
          "detail": {
            "type": "string"
          },
          "code": {
            "type": "string"
          },
          "errors": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "field",
                "message"
              ],
              "properties": {
                "field": {
                  "type": "string"
                },
                "message": {
                  "type": "string"
                }
              }
            }
          }
        }
      },
      "PrintshopQrCodeInput": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "content": {
            "title": "Content type",
            "type": "string",
            "enum": [
              "url",
              "text",
              "wifi",
              "email",
              "phone",
              "sms",
              "geo"
            ],
            "default": "url"
          },
          "text": {
            "title": "Content",
            "description": "The address, text, e-mail address, phone number or \"latitude, longitude\". Not used for Wi-Fi.",
            "type": "string",
            "maxLength": 4000,
            "default": "https://usefulweb.site/"
          },
          "ssid": {
            "title": "Wi-Fi network name (SSID)",
            "type": "string",
            "maxLength": 64,
            "default": ""
          },
          "password": {
            "title": "Wi-Fi password",
            "description": "Only used for the code; it is not shown in the result or stored in the share link.",
            "type": "string",
            "maxLength": 63,
            "default": ""
          },
          "security": {
            "title": "Wi-Fi security",
            "type": "string",
            "enum": [
              "WPA",
              "WEP",
              "nopass"
            ],
            "default": "WPA"
          },
          "hidden": {
            "title": "Hidden network",
            "type": "boolean",
            "default": false
          },
          "layout": {
            "title": "Print layout",
            "type": "string",
            "enum": [
              "one",
              "sheet",
              "wifi-card"
            ],
            "default": "one"
          },
          "ecc": {
            "title": "Error correction",
            "type": "string",
            "enum": [
              "L",
              "M",
              "Q",
              "H"
            ],
            "default": "M"
          },
          "size": {
            "title": "Code width (mm, with quiet zone)",
            "type": "number",
            "minimum": 10,
            "maximum": 400,
            "default": 60
          },
          "quiet": {
            "title": "Quiet zone (modules)",
            "type": "integer",
            "minimum": 0,
            "maximum": 10,
            "default": 4
          },
          "dark": {
            "title": "Dark colour",
            "type": "string",
            "maxLength": 7,
            "default": "#000000"
          },
          "light": {
            "title": "Light colour",
            "type": "string",
            "maxLength": 7,
            "default": "#ffffff"
          },
          "logo": {
            "title": "Logo-safe area (% of the code width)",
            "description": "Leaves an empty square in the centre for a logo and checks it against the error correction.",
            "type": "number",
            "minimum": 0,
            "maximum": 30,
            "default": 0
          },
          "caption": {
            "title": "Caption under the code",
            "type": "string",
            "maxLength": 200,
            "default": ""
          },
          "paper": {
            "title": "Paper size",
            "type": "string",
            "enum": [
              "a3",
              "a4",
              "a5",
              "a6",
              "b5",
              "letter",
              "legal",
              "tabloid",
              "halfletter"
            ],
            "default": "a4"
          },
          "orientation": {
            "title": "Orientation",
            "type": "string",
            "enum": [
              "portrait",
              "landscape"
            ],
            "default": "portrait"
          }
        },
        "required": []
      },
      "PrintshopQrCodeResult": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "schemaVersion",
          "tool",
          "computedAt",
          "inputs",
          "summary",
          "result",
          "units",
          "assumptions",
          "sources",
          "warnings",
          "presentation",
          "links"
        ],
        "properties": {
          "schemaVersion": {
            "type": "string",
            "const": "1.0"
          },
          "tool": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "id",
              "name",
              "version"
            ],
            "properties": {
              "id": {
                "type": "string"
              },
              "name": {
                "type": "string"
              },
              "version": {
                "type": "string"
              }
            }
          },
          "computedAt": {
            "type": "string",
            "format": "date-time"
          },
          "inputs": {
            "type": "object",
            "description": "Normalised inputs actually used, including applied defaults."
          },
          "summary": {
            "type": "string"
          },
          "result": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "version",
              "modules",
              "ecc",
              "mask",
              "segments",
              "dataBits",
              "capacityBits",
              "moduleMm",
              "payloadChars",
              "logo",
              "pages",
              "pageWidthMm",
              "pageHeightMm",
              "warnings",
              "files",
              "openInApp"
            ],
            "properties": {
              "version": {
                "type": "integer"
              },
              "modules": {
                "type": "integer"
              },
              "ecc": {
                "type": "string"
              },
              "mask": {
                "type": "integer"
              },
              "segments": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "dataBits": {
                "type": "integer"
              },
              "capacityBits": {
                "type": "integer"
              },
              "moduleMm": {
                "type": "number"
              },
              "payloadChars": {
                "type": "integer"
              },
              "logo": {
                "type": [
                  "object",
                  "null"
                ],
                "additionalProperties": false,
                "required": [
                  "safe",
                  "worstBlockCodewords",
                  "correctablePerBlock"
                ],
                "properties": {
                  "safe": {
                    "type": "boolean"
                  },
                  "worstBlockCodewords": {
                    "type": "integer"
                  },
                  "correctablePerBlock": {
                    "type": "integer"
                  }
                }
              },
              "pages": {
                "type": "integer"
              },
              "pageWidthMm": {
                "type": "number"
              },
              "pageHeightMm": {
                "type": "number"
              },
              "warnings": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "files": {
                "type": [
                  "object",
                  "null"
                ],
                "additionalProperties": false,
                "required": [
                  "pdf",
                  "svg",
                  "png"
                ],
                "properties": {
                  "pdf": {
                    "type": "object",
                    "additionalProperties": false,
                    "required": [
                      "artifactId",
                      "filename",
                      "mime",
                      "bytes",
                      "sha256",
                      "path"
                    ],
                    "properties": {
                      "artifactId": {
                        "type": "string"
                      },
                      "filename": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "sha256": {
                        "type": "string"
                      },
                      "path": {
                        "type": "string",
                        "description": "Download path on the same site (valid for about 2 hours)."
                      }
                    }
                  },
                  "svg": {
                    "type": "object",
                    "additionalProperties": false,
                    "required": [
                      "artifactId",
                      "filename",
                      "mime",
                      "bytes",
                      "sha256",
                      "path"
                    ],
                    "properties": {
                      "artifactId": {
                        "type": "string"
                      },
                      "filename": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "sha256": {
                        "type": "string"
                      },
                      "path": {
                        "type": "string",
                        "description": "Download path on the same site (valid for about 2 hours)."
                      }
                    }
                  },
                  "png": {
                    "type": "object",
                    "additionalProperties": false,
                    "required": [
                      "artifactId",
                      "filename",
                      "mime",
                      "bytes",
                      "sha256",
                      "path"
                    ],
                    "properties": {
                      "artifactId": {
                        "type": "string"
                      },
                      "filename": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "sha256": {
                        "type": "string"
                      },
                      "path": {
                        "type": "string",
                        "description": "Download path on the same site (valid for about 2 hours)."
                      }
                    }
                  }
                }
              },
              "openInApp": {
                "type": [
                  "string",
                  "null"
                ]
              }
            }
          },
          "units": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            }
          },
          "assumptions": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "sources": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": false,
              "required": [
                "title"
              ],
              "properties": {
                "title": {
                  "type": "string"
                },
                "url": {
                  "type": "string"
                },
                "publisher": {
                  "type": "string"
                },
                "retrievedAt": {
                  "type": "string"
                },
                "note": {
                  "type": "string"
                }
              }
            }
          },
          "warnings": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "presentation": {
            "type": "array",
            "items": {
              "type": "object"
            },
            "description": "Display blocks used by the human page (same data)."
          },
          "links": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "human",
              "api",
              "openapi",
              "methodology"
            ],
            "properties": {
              "human": {
                "type": "string",
                "format": "uri"
              },
              "api": {
                "type": "string",
                "format": "uri"
              },
              "openapi": {
                "type": "string",
                "format": "uri"
              },
              "methodology": {
                "type": "string",
                "format": "uri"
              }
            }
          }
        }
      },
      "PrintshopBarcodeInput": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "symbology": {
            "title": "Barcode type",
            "type": "string",
            "enum": [
              "ean13",
              "upca",
              "code128"
            ],
            "default": "ean13"
          },
          "data": {
            "title": "Data",
            "description": "EAN-13: 12 digits (the check digit is added) or 13 digits (it is checked). UPC-A: 11 or 12 digits. Code 128: up to 80 ASCII characters.",
            "type": "string",
            "maxLength": 80,
            "default": "400638133393"
          },
          "magnification": {
            "title": "Size (magnification)",
            "description": "EAN/UPC: 1 = 0.33 mm modules (GS1 nominal); Code 128: 1 = 0.30 mm modules.",
            "type": "number",
            "minimum": 0.8,
            "maximum": 2,
            "default": 1
          },
          "height": {
            "title": "Bar height (mm)",
            "type": "number",
            "minimum": 5,
            "maximum": 100,
            "default": 22.85
          },
          "text": {
            "title": "Print the digits under the bars",
            "type": "boolean",
            "default": true
          },
          "layout": {
            "title": "Print layout",
            "type": "string",
            "enum": [
              "one",
              "sheet"
            ],
            "default": "one"
          },
          "caption": {
            "title": "Caption above the barcode",
            "type": "string",
            "maxLength": 200,
            "default": ""
          },
          "paper": {
            "title": "Paper size",
            "type": "string",
            "enum": [
              "a3",
              "a4",
              "a5",
              "a6",
              "b5",
              "letter",
              "legal",
              "tabloid",
              "halfletter"
            ],
            "default": "a4"
          }
        },
        "required": []
      },
      "PrintshopBarcodeResult": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "schemaVersion",
          "tool",
          "computedAt",
          "inputs",
          "summary",
          "result",
          "units",
          "assumptions",
          "sources",
          "warnings",
          "presentation",
          "links"
        ],
        "properties": {
          "schemaVersion": {
            "type": "string",
            "const": "1.0"
          },
          "tool": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "id",
              "name",
              "version"
            ],
            "properties": {
              "id": {
                "type": "string"
              },
              "name": {
                "type": "string"
              },
              "version": {
                "type": "string"
              }
            }
          },
          "computedAt": {
            "type": "string",
            "format": "date-time"
          },
          "inputs": {
            "type": "object",
            "description": "Normalised inputs actually used, including applied defaults."
          },
          "summary": {
            "type": "string"
          },
          "result": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "symbology",
              "text",
              "checkDigit",
              "modules",
              "xMm",
              "widthMm",
              "codeSets",
              "symbolValues",
              "pages",
              "pageWidthMm",
              "pageHeightMm",
              "warnings",
              "files",
              "openInApp"
            ],
            "properties": {
              "symbology": {
                "type": "string"
              },
              "text": {
                "type": "string"
              },
              "checkDigit": {
                "type": [
                  "integer",
                  "null"
                ]
              },
              "modules": {
                "type": "integer"
              },
              "xMm": {
                "type": "number"
              },
              "widthMm": {
                "type": "number"
              },
              "codeSets": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "symbolValues": {
                "type": [
                  "array",
                  "null"
                ],
                "items": {
                  "type": "integer"
                }
              },
              "pages": {
                "type": "integer"
              },
              "pageWidthMm": {
                "type": "number"
              },
              "pageHeightMm": {
                "type": "number"
              },
              "warnings": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "files": {
                "type": [
                  "object",
                  "null"
                ],
                "additionalProperties": false,
                "required": [
                  "pdf",
                  "svg",
                  "png"
                ],
                "properties": {
                  "pdf": {
                    "type": "object",
                    "additionalProperties": false,
                    "required": [
                      "artifactId",
                      "filename",
                      "mime",
                      "bytes",
                      "sha256",
                      "path"
                    ],
                    "properties": {
                      "artifactId": {
                        "type": "string"
                      },
                      "filename": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "sha256": {
                        "type": "string"
                      },
                      "path": {
                        "type": "string",
                        "description": "Download path on the same site (valid for about 2 hours)."
                      }
                    }
                  },
                  "svg": {
                    "type": "object",
                    "additionalProperties": false,
                    "required": [
                      "artifactId",
                      "filename",
                      "mime",
                      "bytes",
                      "sha256",
                      "path"
                    ],
                    "properties": {
                      "artifactId": {
                        "type": "string"
                      },
                      "filename": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "sha256": {
                        "type": "string"
                      },
                      "path": {
                        "type": "string",
                        "description": "Download path on the same site (valid for about 2 hours)."
                      }
                    }
                  },
                  "png": {
                    "type": "object",
                    "additionalProperties": false,
                    "required": [
                      "artifactId",
                      "filename",
                      "mime",
                      "bytes",
                      "sha256",
                      "path"
                    ],
                    "properties": {
                      "artifactId": {
                        "type": "string"
                      },
                      "filename": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "sha256": {
                        "type": "string"
                      },
                      "path": {
                        "type": "string",
                        "description": "Download path on the same site (valid for about 2 hours)."
                      }
                    }
                  }
                }
              },
              "openInApp": {
                "type": [
                  "string",
                  "null"
                ]
              }
            }
          },
          "units": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            }
          },
          "assumptions": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "sources": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": false,
              "required": [
                "title"
              ],
              "properties": {
                "title": {
                  "type": "string"
                },
                "url": {
                  "type": "string"
                },
                "publisher": {
                  "type": "string"
                },
                "retrievedAt": {
                  "type": "string"
                },
                "note": {
                  "type": "string"
                }
              }
            }
          },
          "warnings": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "presentation": {
            "type": "array",
            "items": {
              "type": "object"
            },
            "description": "Display blocks used by the human page (same data)."
          },
          "links": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "human",
              "api",
              "openapi",
              "methodology"
            ],
            "properties": {
              "human": {
                "type": "string",
                "format": "uri"
              },
              "api": {
                "type": "string",
                "format": "uri"
              },
              "openapi": {
                "type": "string",
                "format": "uri"
              },
              "methodology": {
                "type": "string",
                "format": "uri"
              }
            }
          }
        }
      },
      "PrintshopCalendarInput": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "year": {
            "title": "Year",
            "type": "integer",
            "minimum": 1900,
            "maximum": 2200,
            "default": 2027
          },
          "startMonth": {
            "title": "First month",
            "type": "integer",
            "minimum": 1,
            "maximum": 12,
            "default": 1
          },
          "months": {
            "title": "Number of months",
            "type": "integer",
            "minimum": 1,
            "maximum": 24,
            "default": 12
          },
          "layout": {
            "title": "Layout",
            "type": "string",
            "enum": [
              "month",
              "year"
            ],
            "default": "month"
          },
          "lang": {
            "title": "Language of month and day names",
            "type": "string",
            "enum": [
              "en",
              "de",
              "fr",
              "es",
              "it",
              "pt",
              "nl",
              "pl",
              "tr",
              "ru",
              "uk",
              "ar",
              "hi",
              "zh",
              "ja",
              "ko",
              "id"
            ],
            "default": "en"
          },
          "country": {
            "title": "Public holidays",
            "type": "string",
            "enum": [
              "none",
              "DE",
              "AT",
              "CH",
              "US",
              "GB",
              "FR",
              "NL",
              "BE",
              "ES",
              "IT",
              "PL",
              "SE",
              "DK",
              "IE",
              "CA",
              "AU"
            ],
            "default": "none"
          },
          "subdivision": {
            "title": "Region (optional)",
            "description": "ISO 3166-2 code such as DE-BY, CH-ZH or US-CA for regional holidays.",
            "type": "string",
            "maxLength": 10,
            "default": ""
          },
          "localNames": {
            "title": "Holiday names in the local language",
            "type": "boolean",
            "default": true
          },
          "weekStart": {
            "title": "First day of the week",
            "type": "string",
            "enum": [
              "auto",
              "mon",
              "sun",
              "sat"
            ],
            "default": "auto"
          },
          "weekNumbers": {
            "title": "Week numbers",
            "type": "string",
            "enum": [
              "none",
              "iso",
              "us"
            ],
            "default": "none"
          },
          "paper": {
            "title": "Paper size",
            "type": "string",
            "enum": [
              "a3",
              "a4",
              "a5",
              "a6",
              "b5",
              "letter",
              "legal",
              "tabloid",
              "halfletter"
            ],
            "default": "a4"
          },
          "orientation": {
            "title": "Orientation",
            "type": "string",
            "enum": [
              "portrait",
              "landscape"
            ],
            "default": "portrait"
          },
          "accent": {
            "title": "Accent colour",
            "type": "string",
            "maxLength": 7,
            "default": "#1f6f8b"
          },
          "title": {
            "title": "Title (optional)",
            "type": "string",
            "maxLength": 120,
            "default": ""
          },
          "notes": {
            "title": "Notes lines under each month",
            "type": "boolean",
            "default": true
          }
        },
        "required": []
      },
      "PrintshopCalendarResult": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "schemaVersion",
          "tool",
          "computedAt",
          "inputs",
          "summary",
          "result",
          "units",
          "assumptions",
          "sources",
          "warnings",
          "presentation",
          "links"
        ],
        "properties": {
          "schemaVersion": {
            "type": "string",
            "const": "1.0"
          },
          "tool": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "id",
              "name",
              "version"
            ],
            "properties": {
              "id": {
                "type": "string"
              },
              "name": {
                "type": "string"
              },
              "version": {
                "type": "string"
              }
            }
          },
          "computedAt": {
            "type": "string",
            "format": "date-time"
          },
          "inputs": {
            "type": "object",
            "description": "Normalised inputs actually used, including applied defaults."
          },
          "summary": {
            "type": "string"
          },
          "result": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "year",
              "months",
              "firstWeekday",
              "holidays",
              "holidayDataCovers",
              "pages",
              "pageWidthMm",
              "pageHeightMm",
              "warnings",
              "files",
              "openInApp"
            ],
            "properties": {
              "year": {
                "type": "integer"
              },
              "months": {
                "type": "integer"
              },
              "firstWeekday": {
                "type": "string"
              },
              "holidayDataCovers": {
                "type": "boolean"
              },
              "holidays": {
                "type": "array",
                "items": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "date",
                    "name"
                  ],
                  "properties": {
                    "date": {
                      "type": "string"
                    },
                    "name": {
                      "type": "string"
                    }
                  }
                }
              },
              "pages": {
                "type": "integer"
              },
              "pageWidthMm": {
                "type": "number"
              },
              "pageHeightMm": {
                "type": "number"
              },
              "warnings": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "files": {
                "type": [
                  "object",
                  "null"
                ],
                "additionalProperties": false,
                "required": [
                  "pdf",
                  "svg",
                  "png"
                ],
                "properties": {
                  "pdf": {
                    "type": "object",
                    "additionalProperties": false,
                    "required": [
                      "artifactId",
                      "filename",
                      "mime",
                      "bytes",
                      "sha256",
                      "path"
                    ],
                    "properties": {
                      "artifactId": {
                        "type": "string"
                      },
                      "filename": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "sha256": {
                        "type": "string"
                      },
                      "path": {
                        "type": "string",
                        "description": "Download path on the same site (valid for about 2 hours)."
                      }
                    }
                  },
                  "svg": {
                    "type": "object",
                    "additionalProperties": false,
                    "required": [
                      "artifactId",
                      "filename",
                      "mime",
                      "bytes",
                      "sha256",
                      "path"
                    ],
                    "properties": {
                      "artifactId": {
                        "type": "string"
                      },
                      "filename": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "sha256": {
                        "type": "string"
                      },
                      "path": {
                        "type": "string",
                        "description": "Download path on the same site (valid for about 2 hours)."
                      }
                    }
                  },
                  "png": {
                    "type": "object",
                    "additionalProperties": false,
                    "required": [
                      "artifactId",
                      "filename",
                      "mime",
                      "bytes",
                      "sha256",
                      "path"
                    ],
                    "properties": {
                      "artifactId": {
                        "type": "string"
                      },
                      "filename": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "sha256": {
                        "type": "string"
                      },
                      "path": {
                        "type": "string",
                        "description": "Download path on the same site (valid for about 2 hours)."
                      }
                    }
                  }
                }
              },
              "openInApp": {
                "type": [
                  "string",
                  "null"
                ]
              }
            }
          },
          "units": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            }
          },
          "assumptions": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "sources": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": false,
              "required": [
                "title"
              ],
              "properties": {
                "title": {
                  "type": "string"
                },
                "url": {
                  "type": "string"
                },
                "publisher": {
                  "type": "string"
                },
                "retrievedAt": {
                  "type": "string"
                },
                "note": {
                  "type": "string"
                }
              }
            }
          },
          "warnings": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "presentation": {
            "type": "array",
            "items": {
              "type": "object"
            },
            "description": "Display blocks used by the human page (same data)."
          },
          "links": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "human",
              "api",
              "openapi",
              "methodology"
            ],
            "properties": {
              "human": {
                "type": "string",
                "format": "uri"
              },
              "api": {
                "type": "string",
                "format": "uri"
              },
              "openapi": {
                "type": "string",
                "format": "uri"
              },
              "methodology": {
                "type": "string",
                "format": "uri"
              }
            }
          }
        }
      },
      "PrintshopLabelSheetInput": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "sheet": {
            "title": "Sheet layout",
            "type": "string",
            "enum": [
              "a4-3x8-70x37",
              "a4-3x7-63x38",
              "a4-2x7-99x38",
              "a4-2x4-99x68",
              "a4-4x10-48x25",
              "a4-5x13-38x21",
              "a4-2x5-90x54",
              "a4-4x6-round40",
              "letter-3x10",
              "letter-2x10",
              "letter-2x5",
              "letter-4x20",
              "letter-3x4-round2",
              "custom"
            ],
            "default": "a4-3x8-70x37"
          },
          "paper": {
            "title": "Paper size (custom layout)",
            "type": "string",
            "enum": [
              "a3",
              "a4",
              "a5",
              "a6",
              "b5",
              "letter",
              "legal",
              "tabloid",
              "halfletter"
            ],
            "default": "a4"
          },
          "cols": {
            "title": "Columns (custom)",
            "type": "integer",
            "minimum": 1,
            "maximum": 30,
            "default": 3
          },
          "rows": {
            "title": "Rows (custom)",
            "type": "integer",
            "minimum": 1,
            "maximum": 30,
            "default": 8
          },
          "labelW": {
            "title": "Label width (mm, custom)",
            "type": "number",
            "minimum": 5,
            "maximum": 1200,
            "default": 70
          },
          "labelH": {
            "title": "Label height (mm, custom)",
            "type": "number",
            "minimum": 5,
            "maximum": 1200,
            "default": 37
          },
          "top": {
            "title": "Top margin (mm, custom)",
            "type": "number",
            "minimum": 0,
            "maximum": 600,
            "default": 0.5
          },
          "left": {
            "title": "Left margin (mm, custom)",
            "type": "number",
            "minimum": 0,
            "maximum": 600,
            "default": 0
          },
          "pitchX": {
            "title": "Horizontal pitch (mm, custom)",
            "description": "Distance from the left edge of one label to the left edge of the next.",
            "type": "number",
            "minimum": 5,
            "maximum": 1200,
            "default": 70
          },
          "pitchY": {
            "title": "Vertical pitch (mm, custom)",
            "type": "number",
            "minimum": 5,
            "maximum": 1200,
            "default": 37
          },
          "template": {
            "title": "Label text",
            "description": "Use {Column} for values from the CSV header.",
            "type": "string",
            "maxLength": 2000,
            "default": "{Name}\n{Street}\n{Postcode} {City}"
          },
          "csv": {
            "title": "CSV data (first row = column names)",
            "type": "string",
            "maxLength": 200000,
            "default": "Name,Street,Postcode,City\nAda Example,1 Sample Road,12345,Exampletown\nBo Sample,22 Test Lane,54321,Demoville"
          },
          "code": {
            "title": "Code on each label",
            "type": "string",
            "enum": [
              "none",
              "qr",
              "code128",
              "ean13"
            ],
            "default": "none"
          },
          "codeTemplate": {
            "title": "Code content",
            "description": "Template for the code, for example {SKU} or https://example.com/{Id}.",
            "type": "string",
            "maxLength": 500,
            "default": ""
          },
          "fontSize": {
            "title": "Font size (mm)",
            "description": "The text shrinks automatically when it does not fit.",
            "type": "number",
            "minimum": 1.5,
            "maximum": 20,
            "default": 3.6
          },
          "align": {
            "title": "Alignment",
            "type": "string",
            "enum": [
              "start",
              "middle",
              "end"
            ],
            "default": "start"
          },
          "startAt": {
            "title": "Start at label number",
            "description": "Skip labels already used on a partly used sheet (counted row by row).",
            "type": "integer",
            "minimum": 1,
            "maximum": 900,
            "default": 1
          },
          "copies": {
            "title": "Copies of each label",
            "type": "integer",
            "minimum": 1,
            "maximum": 100,
            "default": 1
          },
          "outlines": {
            "title": "Draw label outlines",
            "description": "Useful for a test print on plain paper; usually off for real label sheets.",
            "type": "boolean",
            "default": false
          }
        },
        "required": []
      },
      "PrintshopLabelSheetResult": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "schemaVersion",
          "tool",
          "computedAt",
          "inputs",
          "summary",
          "result",
          "units",
          "assumptions",
          "sources",
          "warnings",
          "presentation",
          "links"
        ],
        "properties": {
          "schemaVersion": {
            "type": "string",
            "const": "1.0"
          },
          "tool": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "id",
              "name",
              "version"
            ],
            "properties": {
              "id": {
                "type": "string"
              },
              "name": {
                "type": "string"
              },
              "version": {
                "type": "string"
              }
            }
          },
          "computedAt": {
            "type": "string",
            "format": "date-time"
          },
          "inputs": {
            "type": "object",
            "description": "Normalised inputs actually used, including applied defaults."
          },
          "summary": {
            "type": "string"
          },
          "result": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "labels",
              "records",
              "perSheet",
              "overflow",
              "missingFields",
              "codeErrors",
              "sheetLabel",
              "pages",
              "pageWidthMm",
              "pageHeightMm",
              "warnings",
              "files",
              "openInApp"
            ],
            "properties": {
              "labels": {
                "type": "integer"
              },
              "records": {
                "type": "integer"
              },
              "perSheet": {
                "type": "integer"
              },
              "overflow": {
                "type": "integer"
              },
              "missingFields": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "codeErrors": {
                "type": "integer"
              },
              "sheetLabel": {
                "type": "string"
              },
              "pages": {
                "type": "integer"
              },
              "pageWidthMm": {
                "type": "number"
              },
              "pageHeightMm": {
                "type": "number"
              },
              "warnings": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "files": {
                "type": [
                  "object",
                  "null"
                ],
                "additionalProperties": false,
                "required": [
                  "pdf",
                  "svg",
                  "png"
                ],
                "properties": {
                  "pdf": {
                    "type": "object",
                    "additionalProperties": false,
                    "required": [
                      "artifactId",
                      "filename",
                      "mime",
                      "bytes",
                      "sha256",
                      "path"
                    ],
                    "properties": {
                      "artifactId": {
                        "type": "string"
                      },
                      "filename": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "sha256": {
                        "type": "string"
                      },
                      "path": {
                        "type": "string",
                        "description": "Download path on the same site (valid for about 2 hours)."
                      }
                    }
                  },
                  "svg": {
                    "type": "object",
                    "additionalProperties": false,
                    "required": [
                      "artifactId",
                      "filename",
                      "mime",
                      "bytes",
                      "sha256",
                      "path"
                    ],
                    "properties": {
                      "artifactId": {
                        "type": "string"
                      },
                      "filename": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "sha256": {
                        "type": "string"
                      },
                      "path": {
                        "type": "string",
                        "description": "Download path on the same site (valid for about 2 hours)."
                      }
                    }
                  },
                  "png": {
                    "type": "object",
                    "additionalProperties": false,
                    "required": [
                      "artifactId",
                      "filename",
                      "mime",
                      "bytes",
                      "sha256",
                      "path"
                    ],
                    "properties": {
                      "artifactId": {
                        "type": "string"
                      },
                      "filename": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "sha256": {
                        "type": "string"
                      },
                      "path": {
                        "type": "string",
                        "description": "Download path on the same site (valid for about 2 hours)."
                      }
                    }
                  }
                }
              },
              "openInApp": {
                "type": [
                  "string",
                  "null"
                ]
              }
            }
          },
          "units": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            }
          },
          "assumptions": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "sources": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": false,
              "required": [
                "title"
              ],
              "properties": {
                "title": {
                  "type": "string"
                },
                "url": {
                  "type": "string"
                },
                "publisher": {
                  "type": "string"
                },
                "retrievedAt": {
                  "type": "string"
                },
                "note": {
                  "type": "string"
                }
              }
            }
          },
          "warnings": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "presentation": {
            "type": "array",
            "items": {
              "type": "object"
            },
            "description": "Display blocks used by the human page (same data)."
          },
          "links": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "human",
              "api",
              "openapi",
              "methodology"
            ],
            "properties": {
              "human": {
                "type": "string",
                "format": "uri"
              },
              "api": {
                "type": "string",
                "format": "uri"
              },
              "openapi": {
                "type": "string",
                "format": "uri"
              },
              "methodology": {
                "type": "string",
                "format": "uri"
              }
            }
          }
        }
      },
      "PrintshopGraphPaperInput": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "kind": {
            "title": "Paper type",
            "type": "string",
            "enum": [
              "grid",
              "dots",
              "isometric",
              "hex",
              "music",
              "lined"
            ],
            "default": "grid"
          },
          "spacing": {
            "title": "Spacing (mm, 0 = usual for the paper type)",
            "description": "Grid/dot pitch, triangle or hexagon side, line distance, or the distance between two staff lines. 0 uses 5 mm for grid and dots, 8 mm for isometric, hexagons and lined paper, 2 mm for music staves.",
            "type": "number",
            "minimum": 0,
            "maximum": 50,
            "default": 0
          },
          "majorEvery": {
            "title": "Major line every … cells",
            "type": "integer",
            "minimum": 0,
            "maximum": 20,
            "default": 5
          },
          "lineWidth": {
            "title": "Line width (mm)",
            "type": "number",
            "minimum": 0.05,
            "maximum": 2,
            "default": 0.15
          },
          "color": {
            "title": "Line colour",
            "type": "string",
            "maxLength": 7,
            "default": "#9db7d5"
          },
          "majorColor": {
            "title": "Major line colour",
            "type": "string",
            "maxLength": 7,
            "default": "#5f86b5"
          },
          "margin": {
            "title": "Margin (mm)",
            "type": "number",
            "minimum": 0,
            "maximum": 50,
            "default": 10
          },
          "marginLine": {
            "title": "Margin line for lined paper (mm from the left)",
            "type": "number",
            "minimum": 0,
            "maximum": 200,
            "default": 0
          },
          "header": {
            "title": "Name and date line at the top",
            "type": "boolean",
            "default": false
          },
          "hexOrientation": {
            "title": "Hexagon orientation",
            "type": "string",
            "enum": [
              "pointy",
              "flat"
            ],
            "default": "pointy"
          },
          "pages": {
            "title": "Pages",
            "type": "integer",
            "minimum": 1,
            "maximum": 50,
            "default": 1
          },
          "paper": {
            "title": "Paper size",
            "type": "string",
            "enum": [
              "a3",
              "a4",
              "a5",
              "a6",
              "b5",
              "letter",
              "legal",
              "tabloid",
              "halfletter"
            ],
            "default": "a4"
          },
          "orientation": {
            "title": "Orientation",
            "type": "string",
            "enum": [
              "portrait",
              "landscape"
            ],
            "default": "portrait"
          }
        },
        "required": []
      },
      "PrintshopGraphPaperResult": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "schemaVersion",
          "tool",
          "computedAt",
          "inputs",
          "summary",
          "result",
          "units",
          "assumptions",
          "sources",
          "warnings",
          "presentation",
          "links"
        ],
        "properties": {
          "schemaVersion": {
            "type": "string",
            "const": "1.0"
          },
          "tool": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "id",
              "name",
              "version"
            ],
            "properties": {
              "id": {
                "type": "string"
              },
              "name": {
                "type": "string"
              },
              "version": {
                "type": "string"
              }
            }
          },
          "computedAt": {
            "type": "string",
            "format": "date-time"
          },
          "inputs": {
            "type": "object",
            "description": "Normalised inputs actually used, including applied defaults."
          },
          "summary": {
            "type": "string"
          },
          "result": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "kind",
              "spacingMm",
              "cellsPerPage",
              "pages",
              "pageWidthMm",
              "pageHeightMm",
              "warnings",
              "files",
              "openInApp"
            ],
            "properties": {
              "kind": {
                "type": "string"
              },
              "spacingMm": {
                "type": "number"
              },
              "cellsPerPage": {
                "type": "integer"
              },
              "pages": {
                "type": "integer"
              },
              "pageWidthMm": {
                "type": "number"
              },
              "pageHeightMm": {
                "type": "number"
              },
              "warnings": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "files": {
                "type": [
                  "object",
                  "null"
                ],
                "additionalProperties": false,
                "required": [
                  "pdf",
                  "svg",
                  "png"
                ],
                "properties": {
                  "pdf": {
                    "type": "object",
                    "additionalProperties": false,
                    "required": [
                      "artifactId",
                      "filename",
                      "mime",
                      "bytes",
                      "sha256",
                      "path"
                    ],
                    "properties": {
                      "artifactId": {
                        "type": "string"
                      },
                      "filename": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "sha256": {
                        "type": "string"
                      },
                      "path": {
                        "type": "string",
                        "description": "Download path on the same site (valid for about 2 hours)."
                      }
                    }
                  },
                  "svg": {
                    "type": "object",
                    "additionalProperties": false,
                    "required": [
                      "artifactId",
                      "filename",
                      "mime",
                      "bytes",
                      "sha256",
                      "path"
                    ],
                    "properties": {
                      "artifactId": {
                        "type": "string"
                      },
                      "filename": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "sha256": {
                        "type": "string"
                      },
                      "path": {
                        "type": "string",
                        "description": "Download path on the same site (valid for about 2 hours)."
                      }
                    }
                  },
                  "png": {
                    "type": "object",
                    "additionalProperties": false,
                    "required": [
                      "artifactId",
                      "filename",
                      "mime",
                      "bytes",
                      "sha256",
                      "path"
                    ],
                    "properties": {
                      "artifactId": {
                        "type": "string"
                      },
                      "filename": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "sha256": {
                        "type": "string"
                      },
                      "path": {
                        "type": "string",
                        "description": "Download path on the same site (valid for about 2 hours)."
                      }
                    }
                  }
                }
              },
              "openInApp": {
                "type": [
                  "string",
                  "null"
                ]
              }
            }
          },
          "units": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            }
          },
          "assumptions": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "sources": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": false,
              "required": [
                "title"
              ],
              "properties": {
                "title": {
                  "type": "string"
                },
                "url": {
                  "type": "string"
                },
                "publisher": {
                  "type": "string"
                },
                "retrievedAt": {
                  "type": "string"
                },
                "note": {
                  "type": "string"
                }
              }
            }
          },
          "warnings": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "presentation": {
            "type": "array",
            "items": {
              "type": "object"
            },
            "description": "Display blocks used by the human page (same data)."
          },
          "links": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "human",
              "api",
              "openapi",
              "methodology"
            ],
            "properties": {
              "human": {
                "type": "string",
                "format": "uri"
              },
              "api": {
                "type": "string",
                "format": "uri"
              },
              "openapi": {
                "type": "string",
                "format": "uri"
              },
              "methodology": {
                "type": "string",
                "format": "uri"
              }
            }
          }
        }
      },
      "PrintshopPosterTilerInput": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "image": {
            "title": "Image (JPEG or PNG, optional)",
            "type": "object",
            "description": "Upload as {filename, contentType?, contentBase64}. Max 24414 KiB. Accepts image/jpeg,image/png.",
            "additionalProperties": false,
            "required": [
              "filename",
              "contentBase64"
            ],
            "properties": {
              "filename": {
                "type": "string"
              },
              "contentType": {
                "type": "string"
              },
              "contentBase64": {
                "type": "string"
              }
            }
          },
          "imageWidth": {
            "title": "Image width in pixels (when no file)",
            "type": "integer",
            "minimum": 1,
            "maximum": 100000,
            "default": 4000
          },
          "imageHeight": {
            "title": "Image height in pixels (when no file)",
            "type": "integer",
            "minimum": 1,
            "maximum": 100000,
            "default": 3000
          },
          "width": {
            "title": "Poster width (mm)",
            "type": "number",
            "minimum": 100,
            "maximum": 5000,
            "default": 600
          },
          "paper": {
            "title": "Paper size",
            "type": "string",
            "enum": [
              "a3",
              "a4",
              "a5",
              "a6",
              "b5",
              "letter",
              "legal",
              "tabloid",
              "halfletter"
            ],
            "default": "a4"
          },
          "orientation": {
            "title": "Sheet orientation",
            "type": "string",
            "enum": [
              "auto",
              "portrait",
              "landscape"
            ],
            "default": "auto"
          },
          "margin": {
            "title": "Printer margin (mm)",
            "description": "Most printers cannot print the outer 3–6 mm.",
            "type": "number",
            "minimum": 0,
            "maximum": 30,
            "default": 8
          },
          "overlap": {
            "title": "Overlap (mm)",
            "type": "number",
            "minimum": 0,
            "maximum": 40,
            "default": 10
          },
          "cropMarks": {
            "title": "Crop marks and alignment crosses",
            "type": "boolean",
            "default": true
          },
          "title": {
            "title": "Title on the cover page",
            "type": "string",
            "maxLength": 120,
            "default": "Poster"
          }
        },
        "required": []
      },
      "PrintshopPosterTilerResult": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "schemaVersion",
          "tool",
          "computedAt",
          "inputs",
          "summary",
          "result",
          "units",
          "assumptions",
          "sources",
          "warnings",
          "presentation",
          "links"
        ],
        "properties": {
          "schemaVersion": {
            "type": "string",
            "const": "1.0"
          },
          "tool": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "id",
              "name",
              "version"
            ],
            "properties": {
              "id": {
                "type": "string"
              },
              "name": {
                "type": "string"
              },
              "version": {
                "type": "string"
              }
            }
          },
          "computedAt": {
            "type": "string",
            "format": "date-time"
          },
          "inputs": {
            "type": "object",
            "description": "Normalised inputs actually used, including applied defaults."
          },
          "summary": {
            "type": "string"
          },
          "result": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "sheets",
              "cols",
              "rows",
              "orientation",
              "posterWidthMm",
              "posterHeightMm",
              "ppi",
              "tiles",
              "imageUsed",
              "pages",
              "pageWidthMm",
              "pageHeightMm",
              "warnings",
              "files",
              "openInApp"
            ],
            "properties": {
              "sheets": {
                "type": "integer"
              },
              "cols": {
                "type": "integer"
              },
              "rows": {
                "type": "integer"
              },
              "orientation": {
                "type": "string"
              },
              "posterWidthMm": {
                "type": "number"
              },
              "posterHeightMm": {
                "type": "number"
              },
              "ppi": {
                "type": [
                  "number",
                  "null"
                ]
              },
              "imageUsed": {
                "type": "boolean"
              },
              "tiles": {
                "type": "array",
                "items": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "name",
                    "xMm",
                    "yMm",
                    "widthMm",
                    "heightMm"
                  ],
                  "properties": {
                    "name": {
                      "type": "string"
                    },
                    "xMm": {
                      "type": "number"
                    },
                    "yMm": {
                      "type": "number"
                    },
                    "widthMm": {
                      "type": "number"
                    },
                    "heightMm": {
                      "type": "number"
                    }
                  }
                }
              },
              "pages": {
                "type": "integer"
              },
              "pageWidthMm": {
                "type": "number"
              },
              "pageHeightMm": {
                "type": "number"
              },
              "warnings": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "files": {
                "type": [
                  "object",
                  "null"
                ],
                "additionalProperties": false,
                "required": [
                  "pdf",
                  "svg",
                  "png"
                ],
                "properties": {
                  "pdf": {
                    "type": "object",
                    "additionalProperties": false,
                    "required": [
                      "artifactId",
                      "filename",
                      "mime",
                      "bytes",
                      "sha256",
                      "path"
                    ],
                    "properties": {
                      "artifactId": {
                        "type": "string"
                      },
                      "filename": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "sha256": {
                        "type": "string"
                      },
                      "path": {
                        "type": "string",
                        "description": "Download path on the same site (valid for about 2 hours)."
                      }
                    }
                  },
                  "svg": {
                    "type": "object",
                    "additionalProperties": false,
                    "required": [
                      "artifactId",
                      "filename",
                      "mime",
                      "bytes",
                      "sha256",
                      "path"
                    ],
                    "properties": {
                      "artifactId": {
                        "type": "string"
                      },
                      "filename": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "sha256": {
                        "type": "string"
                      },
                      "path": {
                        "type": "string",
                        "description": "Download path on the same site (valid for about 2 hours)."
                      }
                    }
                  },
                  "png": {
                    "type": "object",
                    "additionalProperties": false,
                    "required": [
                      "artifactId",
                      "filename",
                      "mime",
                      "bytes",
                      "sha256",
                      "path"
                    ],
                    "properties": {
                      "artifactId": {
                        "type": "string"
                      },
                      "filename": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "sha256": {
                        "type": "string"
                      },
                      "path": {
                        "type": "string",
                        "description": "Download path on the same site (valid for about 2 hours)."
                      }
                    }
                  }
                }
              },
              "openInApp": {
                "type": [
                  "string",
                  "null"
                ]
              }
            }
          },
          "units": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            }
          },
          "assumptions": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "sources": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": false,
              "required": [
                "title"
              ],
              "properties": {
                "title": {
                  "type": "string"
                },
                "url": {
                  "type": "string"
                },
                "publisher": {
                  "type": "string"
                },
                "retrievedAt": {
                  "type": "string"
                },
                "note": {
                  "type": "string"
                }
              }
            }
          },
          "warnings": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "presentation": {
            "type": "array",
            "items": {
              "type": "object"
            },
            "description": "Display blocks used by the human page (same data)."
          },
          "links": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "human",
              "api",
              "openapi",
              "methodology"
            ],
            "properties": {
              "human": {
                "type": "string",
                "format": "uri"
              },
              "api": {
                "type": "string",
                "format": "uri"
              },
              "openapi": {
                "type": "string",
                "format": "uri"
              },
              "methodology": {
                "type": "string",
                "format": "uri"
              }
            }
          }
        }
      },
      "PrintshopBookletInput": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "source": {
            "title": "Booklet pages",
            "type": "string",
            "enum": [
              "ruled",
              "calendar"
            ],
            "default": "ruled"
          },
          "pages": {
            "title": "Notebook pages",
            "type": "integer",
            "minimum": 1,
            "maximum": 200,
            "default": 16
          },
          "kind": {
            "title": "Notebook paper type",
            "type": "string",
            "enum": [
              "grid",
              "dots",
              "isometric",
              "hex",
              "music",
              "lined"
            ],
            "default": "dots"
          },
          "spacing": {
            "title": "Notebook spacing (mm)",
            "type": "number",
            "minimum": 1,
            "maximum": 50,
            "default": 5
          },
          "year": {
            "title": "Calendar year",
            "type": "integer",
            "minimum": 1900,
            "maximum": 2200,
            "default": 2027
          },
          "startMonth": {
            "title": "Calendar first month",
            "type": "integer",
            "minimum": 1,
            "maximum": 12,
            "default": 1
          },
          "lang": {
            "title": "Calendar language",
            "type": "string",
            "enum": [
              "en",
              "de",
              "fr",
              "es",
              "it",
              "pt",
              "nl",
              "pl",
              "tr",
              "ru",
              "uk",
              "ar",
              "hi",
              "zh",
              "ja",
              "ko",
              "id"
            ],
            "default": "en"
          },
          "paper": {
            "title": "Sheet size (folded in half)",
            "type": "string",
            "enum": [
              "a3",
              "a4",
              "a5",
              "a6",
              "b5",
              "letter",
              "legal",
              "tabloid",
              "halfletter"
            ],
            "default": "a4"
          },
          "reading": {
            "title": "Binding",
            "type": "string",
            "enum": [
              "ltr",
              "rtl"
            ],
            "default": "ltr"
          },
          "creep": {
            "title": "Creep compensation (mm per sheet)",
            "description": "About the paper thickness (0.1 mm for 80 g/m²) for thick booklets.",
            "type": "number",
            "minimum": 0,
            "maximum": 1,
            "default": 0
          },
          "pageNumbers": {
            "title": "Page numbers",
            "type": "boolean",
            "default": true
          }
        },
        "required": []
      },
      "PrintshopBookletResult": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "schemaVersion",
          "tool",
          "computedAt",
          "inputs",
          "summary",
          "result",
          "units",
          "assumptions",
          "sources",
          "warnings",
          "presentation",
          "links"
        ],
        "properties": {
          "schemaVersion": {
            "type": "string",
            "const": "1.0"
          },
          "tool": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "id",
              "name",
              "version"
            ],
            "properties": {
              "id": {
                "type": "string"
              },
              "name": {
                "type": "string"
              },
              "version": {
                "type": "string"
              }
            }
          },
          "computedAt": {
            "type": "string",
            "format": "date-time"
          },
          "inputs": {
            "type": "object",
            "description": "Normalised inputs actually used, including applied defaults."
          },
          "summary": {
            "type": "string"
          },
          "result": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "bookletPages",
              "sheets",
              "blankPages",
              "order",
              "pages",
              "pageWidthMm",
              "pageHeightMm",
              "warnings",
              "files",
              "openInApp"
            ],
            "properties": {
              "bookletPages": {
                "type": "integer"
              },
              "sheets": {
                "type": "integer"
              },
              "blankPages": {
                "type": "integer"
              },
              "order": {
                "type": "array",
                "items": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "sheet",
                    "front",
                    "back"
                  ],
                  "properties": {
                    "sheet": {
                      "type": "integer"
                    },
                    "front": {
                      "type": "array",
                      "items": {
                        "type": [
                          "integer",
                          "null"
                        ]
                      }
                    },
                    "back": {
                      "type": "array",
                      "items": {
                        "type": [
                          "integer",
                          "null"
                        ]
                      }
                    }
                  }
                }
              },
              "pages": {
                "type": "integer"
              },
              "pageWidthMm": {
                "type": "number"
              },
              "pageHeightMm": {
                "type": "number"
              },
              "warnings": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "files": {
                "type": [
                  "object",
                  "null"
                ],
                "additionalProperties": false,
                "required": [
                  "pdf",
                  "svg",
                  "png"
                ],
                "properties": {
                  "pdf": {
                    "type": "object",
                    "additionalProperties": false,
                    "required": [
                      "artifactId",
                      "filename",
                      "mime",
                      "bytes",
                      "sha256",
                      "path"
                    ],
                    "properties": {
                      "artifactId": {
                        "type": "string"
                      },
                      "filename": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "sha256": {
                        "type": "string"
                      },
                      "path": {
                        "type": "string",
                        "description": "Download path on the same site (valid for about 2 hours)."
                      }
                    }
                  },
                  "svg": {
                    "type": "object",
                    "additionalProperties": false,
                    "required": [
                      "artifactId",
                      "filename",
                      "mime",
                      "bytes",
                      "sha256",
                      "path"
                    ],
                    "properties": {
                      "artifactId": {
                        "type": "string"
                      },
                      "filename": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "sha256": {
                        "type": "string"
                      },
                      "path": {
                        "type": "string",
                        "description": "Download path on the same site (valid for about 2 hours)."
                      }
                    }
                  },
                  "png": {
                    "type": "object",
                    "additionalProperties": false,
                    "required": [
                      "artifactId",
                      "filename",
                      "mime",
                      "bytes",
                      "sha256",
                      "path"
                    ],
                    "properties": {
                      "artifactId": {
                        "type": "string"
                      },
                      "filename": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "sha256": {
                        "type": "string"
                      },
                      "path": {
                        "type": "string",
                        "description": "Download path on the same site (valid for about 2 hours)."
                      }
                    }
                  }
                }
              },
              "openInApp": {
                "type": [
                  "string",
                  "null"
                ]
              }
            }
          },
          "units": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            }
          },
          "assumptions": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "sources": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": false,
              "required": [
                "title"
              ],
              "properties": {
                "title": {
                  "type": "string"
                },
                "url": {
                  "type": "string"
                },
                "publisher": {
                  "type": "string"
                },
                "retrievedAt": {
                  "type": "string"
                },
                "note": {
                  "type": "string"
                }
              }
            }
          },
          "warnings": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "presentation": {
            "type": "array",
            "items": {
              "type": "object"
            },
            "description": "Display blocks used by the human page (same data)."
          },
          "links": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "human",
              "api",
              "openapi",
              "methodology"
            ],
            "properties": {
              "human": {
                "type": "string",
                "format": "uri"
              },
              "api": {
                "type": "string",
                "format": "uri"
              },
              "openapi": {
                "type": "string",
                "format": "uri"
              },
              "methodology": {
                "type": "string",
                "format": "uri"
              }
            }
          }
        }
      },
      "PrintshopSudokuInput": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "size": {
            "title": "Grid size",
            "type": "string",
            "enum": [
              "4",
              "6",
              "8",
              "9",
              "12",
              "16"
            ],
            "default": "9"
          },
          "difficulty": {
            "title": "Difficulty",
            "type": "string",
            "enum": [
              "easy",
              "medium",
              "hard",
              "expert"
            ],
            "default": "medium"
          },
          "count": {
            "title": "Number of sudokus",
            "type": "integer",
            "minimum": 1,
            "maximum": 12,
            "default": 4
          },
          "perPage": {
            "title": "Sudokus per page",
            "type": "string",
            "enum": [
              "1",
              "2",
              "4",
              "6"
            ],
            "default": "4"
          },
          "symmetric": {
            "title": "Symmetric clues (180° rotation)",
            "type": "boolean",
            "default": true
          },
          "seed": {
            "title": "Seed",
            "description": "The same seed and settings always give the same puzzles. Change it for new ones.",
            "type": "string",
            "maxLength": 80,
            "default": "sudoku-1"
          },
          "title": {
            "title": "Title on the page (optional)",
            "type": "string",
            "maxLength": 120,
            "default": ""
          },
          "answers": {
            "title": "Answer-key pages",
            "type": "boolean",
            "default": true
          },
          "header": {
            "title": "Name and date line",
            "type": "boolean",
            "default": true
          },
          "paper": {
            "title": "Paper size",
            "type": "string",
            "enum": [
              "a3",
              "a4",
              "a5",
              "a6",
              "b5",
              "letter",
              "legal",
              "tabloid",
              "halfletter"
            ],
            "default": "a4"
          },
          "orientation": {
            "title": "Orientation",
            "type": "string",
            "enum": [
              "portrait",
              "landscape"
            ],
            "default": "portrait"
          }
        },
        "required": []
      },
      "PrintshopSudokuResult": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "schemaVersion",
          "tool",
          "computedAt",
          "inputs",
          "summary",
          "result",
          "units",
          "assumptions",
          "sources",
          "warnings",
          "presentation",
          "links"
        ],
        "properties": {
          "schemaVersion": {
            "type": "string",
            "const": "1.0"
          },
          "tool": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "id",
              "name",
              "version"
            ],
            "properties": {
              "id": {
                "type": "string"
              },
              "name": {
                "type": "string"
              },
              "version": {
                "type": "string"
              }
            }
          },
          "computedAt": {
            "type": "string",
            "format": "date-time"
          },
          "inputs": {
            "type": "object",
            "description": "Normalised inputs actually used, including applied defaults."
          },
          "summary": {
            "type": "string"
          },
          "result": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "size",
              "puzzles",
              "seed",
              "pages",
              "puzzlePages",
              "answerPages",
              "pageWidthMm",
              "pageHeightMm",
              "warnings",
              "files",
              "openInApp"
            ],
            "properties": {
              "size": {
                "type": "integer"
              },
              "puzzles": {
                "type": "array",
                "items": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "puzzle",
                    "solution",
                    "clues",
                    "difficulty",
                    "requested"
                  ],
                  "properties": {
                    "puzzle": {
                      "type": "string"
                    },
                    "solution": {
                      "type": "string"
                    },
                    "clues": {
                      "type": "integer"
                    },
                    "difficulty": {
                      "type": "string"
                    },
                    "requested": {
                      "type": "string"
                    }
                  }
                }
              },
              "seed": {
                "type": "string"
              },
              "pages": {
                "type": "integer"
              },
              "puzzlePages": {
                "type": "integer"
              },
              "answerPages": {
                "type": "integer"
              },
              "pageWidthMm": {
                "type": "number"
              },
              "pageHeightMm": {
                "type": "number"
              },
              "warnings": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "files": {
                "type": [
                  "object",
                  "null"
                ],
                "additionalProperties": false,
                "required": [
                  "pdf",
                  "svg",
                  "png"
                ],
                "properties": {
                  "pdf": {
                    "type": "object",
                    "additionalProperties": false,
                    "required": [
                      "artifactId",
                      "filename",
                      "mime",
                      "bytes",
                      "sha256",
                      "path"
                    ],
                    "properties": {
                      "artifactId": {
                        "type": "string"
                      },
                      "filename": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "sha256": {
                        "type": "string"
                      },
                      "path": {
                        "type": "string",
                        "description": "Download path on the same site (valid for about 2 hours)."
                      }
                    }
                  },
                  "svg": {
                    "type": "object",
                    "additionalProperties": false,
                    "required": [
                      "artifactId",
                      "filename",
                      "mime",
                      "bytes",
                      "sha256",
                      "path"
                    ],
                    "properties": {
                      "artifactId": {
                        "type": "string"
                      },
                      "filename": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "sha256": {
                        "type": "string"
                      },
                      "path": {
                        "type": "string",
                        "description": "Download path on the same site (valid for about 2 hours)."
                      }
                    }
                  },
                  "png": {
                    "type": "object",
                    "additionalProperties": false,
                    "required": [
                      "artifactId",
                      "filename",
                      "mime",
                      "bytes",
                      "sha256",
                      "path"
                    ],
                    "properties": {
                      "artifactId": {
                        "type": "string"
                      },
                      "filename": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "sha256": {
                        "type": "string"
                      },
                      "path": {
                        "type": "string",
                        "description": "Download path on the same site (valid for about 2 hours)."
                      }
                    }
                  }
                }
              },
              "openInApp": {
                "type": [
                  "string",
                  "null"
                ]
              }
            }
          },
          "units": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            }
          },
          "assumptions": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "sources": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": false,
              "required": [
                "title"
              ],
              "properties": {
                "title": {
                  "type": "string"
                },
                "url": {
                  "type": "string"
                },
                "publisher": {
                  "type": "string"
                },
                "retrievedAt": {
                  "type": "string"
                },
                "note": {
                  "type": "string"
                }
              }
            }
          },
          "warnings": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "presentation": {
            "type": "array",
            "items": {
              "type": "object"
            },
            "description": "Display blocks used by the human page (same data)."
          },
          "links": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "human",
              "api",
              "openapi",
              "methodology"
            ],
            "properties": {
              "human": {
                "type": "string",
                "format": "uri"
              },
              "api": {
                "type": "string",
                "format": "uri"
              },
              "openapi": {
                "type": "string",
                "format": "uri"
              },
              "methodology": {
                "type": "string",
                "format": "uri"
              }
            }
          }
        }
      },
      "PrintshopMazeInput": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "shape": {
            "title": "Cells",
            "type": "string",
            "enum": [
              "rect",
              "hex",
              "circle"
            ],
            "default": "rect"
          },
          "cols": {
            "title": "Columns",
            "type": "integer",
            "minimum": 2,
            "maximum": 80,
            "default": 16
          },
          "rows": {
            "title": "Rows (rings for a round maze)",
            "type": "integer",
            "minimum": 2,
            "maximum": 80,
            "default": 20
          },
          "mask": {
            "title": "Outline",
            "type": "string",
            "enum": [
              "none",
              "heart",
              "star",
              "circle",
              "diamond",
              "triangle",
              "custom"
            ],
            "default": "none"
          },
          "maskText": {
            "title": "Own shape (# = inside)",
            "description": "One text line per row; # marks a cell inside the maze. Columns and rows then come from the drawing.",
            "type": "string",
            "maxLength": 8000,
            "default": ""
          },
          "algorithm": {
            "title": "Algorithm",
            "type": "string",
            "enum": [
              "backtracker",
              "kruskal",
              "wilson"
            ],
            "default": "backtracker"
          },
          "count": {
            "title": "Number of mazes",
            "type": "integer",
            "minimum": 1,
            "maximum": 24,
            "default": 1
          },
          "perPage": {
            "title": "Mazes per page",
            "type": "string",
            "enum": [
              "1",
              "2",
              "4",
              "6"
            ],
            "default": "1"
          },
          "seed": {
            "title": "Seed",
            "description": "The same seed and settings always give the same puzzles. Change it for new ones.",
            "type": "string",
            "maxLength": 80,
            "default": "maze-1"
          },
          "title": {
            "title": "Title on the page (optional)",
            "type": "string",
            "maxLength": 120,
            "default": ""
          },
          "answers": {
            "title": "Answer-key pages",
            "type": "boolean",
            "default": true
          },
          "header": {
            "title": "Name and date line",
            "type": "boolean",
            "default": true
          },
          "paper": {
            "title": "Paper size",
            "type": "string",
            "enum": [
              "a3",
              "a4",
              "a5",
              "a6",
              "b5",
              "letter",
              "legal",
              "tabloid",
              "halfletter"
            ],
            "default": "a4"
          },
          "orientation": {
            "title": "Orientation",
            "type": "string",
            "enum": [
              "portrait",
              "landscape"
            ],
            "default": "portrait"
          }
        },
        "required": []
      },
      "PrintshopMazeResult": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "schemaVersion",
          "tool",
          "computedAt",
          "inputs",
          "summary",
          "result",
          "units",
          "assumptions",
          "sources",
          "warnings",
          "presentation",
          "links"
        ],
        "properties": {
          "schemaVersion": {
            "type": "string",
            "const": "1.0"
          },
          "tool": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "id",
              "name",
              "version"
            ],
            "properties": {
              "id": {
                "type": "string"
              },
              "name": {
                "type": "string"
              },
              "version": {
                "type": "string"
              }
            }
          },
          "computedAt": {
            "type": "string",
            "format": "date-time"
          },
          "inputs": {
            "type": "object",
            "description": "Normalised inputs actually used, including applied defaults."
          },
          "summary": {
            "type": "string"
          },
          "result": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "shape",
              "algorithm",
              "mazes",
              "seed",
              "pages",
              "puzzlePages",
              "answerPages",
              "pageWidthMm",
              "pageHeightMm",
              "warnings",
              "files",
              "openInApp"
            ],
            "properties": {
              "shape": {
                "type": "string"
              },
              "algorithm": {
                "type": "string"
              },
              "mazes": {
                "type": "array",
                "items": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "cells",
                    "deadEnds",
                    "solutionCells"
                  ],
                  "properties": {
                    "cells": {
                      "type": "integer"
                    },
                    "deadEnds": {
                      "type": "integer"
                    },
                    "solutionCells": {
                      "type": "integer"
                    }
                  }
                }
              },
              "seed": {
                "type": "string"
              },
              "pages": {
                "type": "integer"
              },
              "puzzlePages": {
                "type": "integer"
              },
              "answerPages": {
                "type": "integer"
              },
              "pageWidthMm": {
                "type": "number"
              },
              "pageHeightMm": {
                "type": "number"
              },
              "warnings": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "files": {
                "type": [
                  "object",
                  "null"
                ],
                "additionalProperties": false,
                "required": [
                  "pdf",
                  "svg",
                  "png"
                ],
                "properties": {
                  "pdf": {
                    "type": "object",
                    "additionalProperties": false,
                    "required": [
                      "artifactId",
                      "filename",
                      "mime",
                      "bytes",
                      "sha256",
                      "path"
                    ],
                    "properties": {
                      "artifactId": {
                        "type": "string"
                      },
                      "filename": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "sha256": {
                        "type": "string"
                      },
                      "path": {
                        "type": "string",
                        "description": "Download path on the same site (valid for about 2 hours)."
                      }
                    }
                  },
                  "svg": {
                    "type": "object",
                    "additionalProperties": false,
                    "required": [
                      "artifactId",
                      "filename",
                      "mime",
                      "bytes",
                      "sha256",
                      "path"
                    ],
                    "properties": {
                      "artifactId": {
                        "type": "string"
                      },
                      "filename": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "sha256": {
                        "type": "string"
                      },
                      "path": {
                        "type": "string",
                        "description": "Download path on the same site (valid for about 2 hours)."
                      }
                    }
                  },
                  "png": {
                    "type": "object",
                    "additionalProperties": false,
                    "required": [
                      "artifactId",
                      "filename",
                      "mime",
                      "bytes",
                      "sha256",
                      "path"
                    ],
                    "properties": {
                      "artifactId": {
                        "type": "string"
                      },
                      "filename": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "sha256": {
                        "type": "string"
                      },
                      "path": {
                        "type": "string",
                        "description": "Download path on the same site (valid for about 2 hours)."
                      }
                    }
                  }
                }
              },
              "openInApp": {
                "type": [
                  "string",
                  "null"
                ]
              }
            }
          },
          "units": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            }
          },
          "assumptions": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "sources": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": false,
              "required": [
                "title"
              ],
              "properties": {
                "title": {
                  "type": "string"
                },
                "url": {
                  "type": "string"
                },
                "publisher": {
                  "type": "string"
                },
                "retrievedAt": {
                  "type": "string"
                },
                "note": {
                  "type": "string"
                }
              }
            }
          },
          "warnings": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "presentation": {
            "type": "array",
            "items": {
              "type": "object"
            },
            "description": "Display blocks used by the human page (same data)."
          },
          "links": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "human",
              "api",
              "openapi",
              "methodology"
            ],
            "properties": {
              "human": {
                "type": "string",
                "format": "uri"
              },
              "api": {
                "type": "string",
                "format": "uri"
              },
              "openapi": {
                "type": "string",
                "format": "uri"
              },
              "methodology": {
                "type": "string",
                "format": "uri"
              }
            }
          }
        }
      },
      "PrintshopWordSearchInput": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "words": {
            "title": "Words",
            "description": "One word per line or separated by commas. Spaces and hyphens are dropped in the grid. Up to 60 words.",
            "type": "string",
            "maxLength": 4000,
            "default": "Planet\nComet\nGalaxy\nOrbit\nRocket\nMeteor\nNebula\nGravity\nTelescope\nAstronaut\nSaturn\nEclipse"
          },
          "size": {
            "title": "Grid size (0 = automatic)",
            "type": "integer",
            "minimum": 0,
            "maximum": 30,
            "default": 0
          },
          "diagonal": {
            "title": "Diagonal words",
            "type": "boolean",
            "default": true
          },
          "backwards": {
            "title": "Backwards words",
            "type": "boolean",
            "default": false
          },
          "overlap": {
            "title": "Words may share letters",
            "type": "boolean",
            "default": true
          },
          "uppercase": {
            "title": "Capital letters",
            "type": "boolean",
            "default": true
          },
          "lang": {
            "title": "Language (for capital letters)",
            "type": "string",
            "enum": [
              "en",
              "de",
              "fr",
              "es",
              "it",
              "pt",
              "nl",
              "pl",
              "tr",
              "ru",
              "uk",
              "ar",
              "hi",
              "zh",
              "ja",
              "ko",
              "id"
            ],
            "default": "en"
          },
          "seed": {
            "title": "Seed",
            "description": "The same seed and settings always give the same puzzles. Change it for new ones.",
            "type": "string",
            "maxLength": 80,
            "default": "words-1"
          },
          "title": {
            "title": "Title on the page (optional)",
            "type": "string",
            "maxLength": 120,
            "default": ""
          },
          "answers": {
            "title": "Answer-key pages",
            "type": "boolean",
            "default": true
          },
          "header": {
            "title": "Name and date line",
            "type": "boolean",
            "default": true
          },
          "paper": {
            "title": "Paper size",
            "type": "string",
            "enum": [
              "a3",
              "a4",
              "a5",
              "a6",
              "b5",
              "letter",
              "legal",
              "tabloid",
              "halfletter"
            ],
            "default": "a4"
          },
          "orientation": {
            "title": "Orientation",
            "type": "string",
            "enum": [
              "portrait",
              "landscape"
            ],
            "default": "portrait"
          }
        },
        "required": []
      },
      "PrintshopWordSearchResult": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "schemaVersion",
          "tool",
          "computedAt",
          "inputs",
          "summary",
          "result",
          "units",
          "assumptions",
          "sources",
          "warnings",
          "presentation",
          "links"
        ],
        "properties": {
          "schemaVersion": {
            "type": "string",
            "const": "1.0"
          },
          "tool": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "id",
              "name",
              "version"
            ],
            "properties": {
              "id": {
                "type": "string"
              },
              "name": {
                "type": "string"
              },
              "version": {
                "type": "string"
              }
            }
          },
          "computedAt": {
            "type": "string",
            "format": "date-time"
          },
          "inputs": {
            "type": "object",
            "description": "Normalised inputs actually used, including applied defaults."
          },
          "summary": {
            "type": "string"
          },
          "result": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "size",
              "rightToLeft",
              "grid",
              "words",
              "missing",
              "seed",
              "pages",
              "puzzlePages",
              "answerPages",
              "pageWidthMm",
              "pageHeightMm",
              "warnings",
              "files",
              "openInApp"
            ],
            "properties": {
              "size": {
                "type": "integer"
              },
              "rightToLeft": {
                "type": "boolean"
              },
              "grid": {
                "type": "array",
                "items": {
                  "type": "array",
                  "items": {
                    "type": "string"
                  }
                }
              },
              "words": {
                "type": "array",
                "items": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "word",
                    "row",
                    "col",
                    "direction",
                    "length"
                  ],
                  "properties": {
                    "word": {
                      "type": "string"
                    },
                    "row": {
                      "type": "integer"
                    },
                    "col": {
                      "type": "integer"
                    },
                    "direction": {
                      "type": "string"
                    },
                    "length": {
                      "type": "integer"
                    }
                  }
                }
              },
              "missing": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "seed": {
                "type": "string"
              },
              "pages": {
                "type": "integer"
              },
              "puzzlePages": {
                "type": "integer"
              },
              "answerPages": {
                "type": "integer"
              },
              "pageWidthMm": {
                "type": "number"
              },
              "pageHeightMm": {
                "type": "number"
              },
              "warnings": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "files": {
                "type": [
                  "object",
                  "null"
                ],
                "additionalProperties": false,
                "required": [
                  "pdf",
                  "svg",
                  "png"
                ],
                "properties": {
                  "pdf": {
                    "type": "object",
                    "additionalProperties": false,
                    "required": [
                      "artifactId",
                      "filename",
                      "mime",
                      "bytes",
                      "sha256",
                      "path"
                    ],
                    "properties": {
                      "artifactId": {
                        "type": "string"
                      },
                      "filename": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "sha256": {
                        "type": "string"
                      },
                      "path": {
                        "type": "string",
                        "description": "Download path on the same site (valid for about 2 hours)."
                      }
                    }
                  },
                  "svg": {
                    "type": "object",
                    "additionalProperties": false,
                    "required": [
                      "artifactId",
                      "filename",
                      "mime",
                      "bytes",
                      "sha256",
                      "path"
                    ],
                    "properties": {
                      "artifactId": {
                        "type": "string"
                      },
                      "filename": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "sha256": {
                        "type": "string"
                      },
                      "path": {
                        "type": "string",
                        "description": "Download path on the same site (valid for about 2 hours)."
                      }
                    }
                  },
                  "png": {
                    "type": "object",
                    "additionalProperties": false,
                    "required": [
                      "artifactId",
                      "filename",
                      "mime",
                      "bytes",
                      "sha256",
                      "path"
                    ],
                    "properties": {
                      "artifactId": {
                        "type": "string"
                      },
                      "filename": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "sha256": {
                        "type": "string"
                      },
                      "path": {
                        "type": "string",
                        "description": "Download path on the same site (valid for about 2 hours)."
                      }
                    }
                  }
                }
              },
              "openInApp": {
                "type": [
                  "string",
                  "null"
                ]
              }
            }
          },
          "units": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            }
          },
          "assumptions": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "sources": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": false,
              "required": [
                "title"
              ],
              "properties": {
                "title": {
                  "type": "string"
                },
                "url": {
                  "type": "string"
                },
                "publisher": {
                  "type": "string"
                },
                "retrievedAt": {
                  "type": "string"
                },
                "note": {
                  "type": "string"
                }
              }
            }
          },
          "warnings": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "presentation": {
            "type": "array",
            "items": {
              "type": "object"
            },
            "description": "Display blocks used by the human page (same data)."
          },
          "links": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "human",
              "api",
              "openapi",
              "methodology"
            ],
            "properties": {
              "human": {
                "type": "string",
                "format": "uri"
              },
              "api": {
                "type": "string",
                "format": "uri"
              },
              "openapi": {
                "type": "string",
                "format": "uri"
              },
              "methodology": {
                "type": "string",
                "format": "uri"
              }
            }
          }
        }
      },
      "PrintshopCrosswordFillInput": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "words": {
            "title": "Words and clues",
            "description": "One per line: word, then a colon and the clue (“Anchor: Heavy hook that keeps a ship in place”). Up to 60 words.",
            "type": "string",
            "maxLength": 8000,
            "default": "Lighthouse: Tower with a lamp that guides ships\nHarbour: Sheltered water where boats are moored\nAnchor: Heavy hook that keeps a ship in place\nSeagull: Noisy white bird of the coast\nTide: Twice-daily rise and fall of the sea\nSail: Cloth that catches the wind\nCompass: It always points north\nWave: Moving ridge of water\nIsland: Land with water all around"
          },
          "uppercase": {
            "title": "Capital letters",
            "type": "boolean",
            "default": true
          },
          "lang": {
            "title": "Language (for capital letters)",
            "type": "string",
            "enum": [
              "en",
              "de",
              "fr",
              "es",
              "it",
              "pt",
              "nl",
              "pl",
              "tr",
              "ru",
              "uk",
              "ar",
              "hi",
              "zh",
              "ja",
              "ko",
              "id"
            ],
            "default": "en"
          },
          "seed": {
            "title": "Seed",
            "description": "The same seed and settings always give the same puzzles. Change it for new ones.",
            "type": "string",
            "maxLength": 80,
            "default": "cross-1"
          },
          "title": {
            "title": "Title on the page (optional)",
            "type": "string",
            "maxLength": 120,
            "default": ""
          },
          "answers": {
            "title": "Answer-key pages",
            "type": "boolean",
            "default": true
          },
          "header": {
            "title": "Name and date line",
            "type": "boolean",
            "default": true
          },
          "paper": {
            "title": "Paper size",
            "type": "string",
            "enum": [
              "a3",
              "a4",
              "a5",
              "a6",
              "b5",
              "letter",
              "legal",
              "tabloid",
              "halfletter"
            ],
            "default": "a4"
          },
          "orientation": {
            "title": "Orientation",
            "type": "string",
            "enum": [
              "portrait",
              "landscape"
            ],
            "default": "portrait"
          }
        },
        "required": []
      },
      "PrintshopCrosswordFillResult": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "schemaVersion",
          "tool",
          "computedAt",
          "inputs",
          "summary",
          "result",
          "units",
          "assumptions",
          "sources",
          "warnings",
          "presentation",
          "links"
        ],
        "properties": {
          "schemaVersion": {
            "type": "string",
            "const": "1.0"
          },
          "tool": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "id",
              "name",
              "version"
            ],
            "properties": {
              "id": {
                "type": "string"
              },
              "name": {
                "type": "string"
              },
              "version": {
                "type": "string"
              }
            }
          },
          "computedAt": {
            "type": "string",
            "format": "date-time"
          },
          "inputs": {
            "type": "object",
            "description": "Normalised inputs actually used, including applied defaults."
          },
          "summary": {
            "type": "string"
          },
          "result": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "width",
              "height",
              "crossings",
              "entries",
              "missing",
              "seed",
              "pages",
              "puzzlePages",
              "answerPages",
              "pageWidthMm",
              "pageHeightMm",
              "warnings",
              "files",
              "openInApp"
            ],
            "properties": {
              "width": {
                "type": "integer"
              },
              "height": {
                "type": "integer"
              },
              "crossings": {
                "type": "integer"
              },
              "entries": {
                "type": "array",
                "items": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "number",
                    "direction",
                    "word",
                    "clue",
                    "row",
                    "col",
                    "length"
                  ],
                  "properties": {
                    "number": {
                      "type": "integer"
                    },
                    "direction": {
                      "type": "string"
                    },
                    "word": {
                      "type": "string"
                    },
                    "clue": {
                      "type": "string"
                    },
                    "row": {
                      "type": "integer"
                    },
                    "col": {
                      "type": "integer"
                    },
                    "length": {
                      "type": "integer"
                    }
                  }
                }
              },
              "missing": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "seed": {
                "type": "string"
              },
              "pages": {
                "type": "integer"
              },
              "puzzlePages": {
                "type": "integer"
              },
              "answerPages": {
                "type": "integer"
              },
              "pageWidthMm": {
                "type": "number"
              },
              "pageHeightMm": {
                "type": "number"
              },
              "warnings": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "files": {
                "type": [
                  "object",
                  "null"
                ],
                "additionalProperties": false,
                "required": [
                  "pdf",
                  "svg",
                  "png"
                ],
                "properties": {
                  "pdf": {
                    "type": "object",
                    "additionalProperties": false,
                    "required": [
                      "artifactId",
                      "filename",
                      "mime",
                      "bytes",
                      "sha256",
                      "path"
                    ],
                    "properties": {
                      "artifactId": {
                        "type": "string"
                      },
                      "filename": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "sha256": {
                        "type": "string"
                      },
                      "path": {
                        "type": "string",
                        "description": "Download path on the same site (valid for about 2 hours)."
                      }
                    }
                  },
                  "svg": {
                    "type": "object",
                    "additionalProperties": false,
                    "required": [
                      "artifactId",
                      "filename",
                      "mime",
                      "bytes",
                      "sha256",
                      "path"
                    ],
                    "properties": {
                      "artifactId": {
                        "type": "string"
                      },
                      "filename": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "sha256": {
                        "type": "string"
                      },
                      "path": {
                        "type": "string",
                        "description": "Download path on the same site (valid for about 2 hours)."
                      }
                    }
                  },
                  "png": {
                    "type": "object",
                    "additionalProperties": false,
                    "required": [
                      "artifactId",
                      "filename",
                      "mime",
                      "bytes",
                      "sha256",
                      "path"
                    ],
                    "properties": {
                      "artifactId": {
                        "type": "string"
                      },
                      "filename": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "sha256": {
                        "type": "string"
                      },
                      "path": {
                        "type": "string",
                        "description": "Download path on the same site (valid for about 2 hours)."
                      }
                    }
                  }
                }
              },
              "openInApp": {
                "type": [
                  "string",
                  "null"
                ]
              }
            }
          },
          "units": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            }
          },
          "assumptions": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "sources": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": false,
              "required": [
                "title"
              ],
              "properties": {
                "title": {
                  "type": "string"
                },
                "url": {
                  "type": "string"
                },
                "publisher": {
                  "type": "string"
                },
                "retrievedAt": {
                  "type": "string"
                },
                "note": {
                  "type": "string"
                }
              }
            }
          },
          "warnings": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "presentation": {
            "type": "array",
            "items": {
              "type": "object"
            },
            "description": "Display blocks used by the human page (same data)."
          },
          "links": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "human",
              "api",
              "openapi",
              "methodology"
            ],
            "properties": {
              "human": {
                "type": "string",
                "format": "uri"
              },
              "api": {
                "type": "string",
                "format": "uri"
              },
              "openapi": {
                "type": "string",
                "format": "uri"
              },
              "methodology": {
                "type": "string",
                "format": "uri"
              }
            }
          }
        }
      },
      "PrintshopNonogramInput": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "source": {
            "title": "Picture from",
            "type": "string",
            "enum": [
              "picture",
              "grid",
              "image"
            ],
            "default": "picture"
          },
          "picture": {
            "title": "Built-in picture",
            "type": "string",
            "enum": [
              "heart",
              "house",
              "cat",
              "tree",
              "fish",
              "rocket"
            ],
            "default": "cat"
          },
          "grid": {
            "title": "Drawing (# = filled, . = empty)",
            "description": "One line per row, up to 50 × 50.",
            "type": "string",
            "maxLength": 4000,
            "default": ""
          },
          "image": {
            "title": "PNG image",
            "type": "object",
            "description": "Upload as {filename, contentType?, contentBase64}. Max 7813 KiB. Accepts image/png.",
            "additionalProperties": false,
            "required": [
              "filename",
              "contentBase64"
            ],
            "properties": {
              "filename": {
                "type": "string"
              },
              "contentType": {
                "type": "string"
              },
              "contentBase64": {
                "type": "string"
              }
            }
          },
          "cols": {
            "title": "Columns (image)",
            "type": "integer",
            "minimum": 2,
            "maximum": 50,
            "default": 20
          },
          "rows": {
            "title": "Rows (image)",
            "type": "integer",
            "minimum": 2,
            "maximum": 50,
            "default": 20
          },
          "threshold": {
            "title": "Darkness threshold (image, 0–255)",
            "description": "Cells darker than this are filled.",
            "type": "integer",
            "minimum": 1,
            "maximum": 254,
            "default": 128
          },
          "invert": {
            "title": "Invert (light cells filled)",
            "type": "boolean",
            "default": false
          },
          "fix": {
            "title": "Add givens until it solves line by line",
            "type": "boolean",
            "default": true
          },
          "seed": {
            "title": "Seed",
            "description": "The same seed and settings always give the same puzzles. Change it for new ones.",
            "type": "string",
            "maxLength": 80,
            "default": "nonogram-1"
          },
          "title": {
            "title": "Title on the page (optional)",
            "type": "string",
            "maxLength": 120,
            "default": ""
          },
          "answers": {
            "title": "Answer-key pages",
            "type": "boolean",
            "default": true
          },
          "header": {
            "title": "Name and date line",
            "type": "boolean",
            "default": true
          },
          "paper": {
            "title": "Paper size",
            "type": "string",
            "enum": [
              "a3",
              "a4",
              "a5",
              "a6",
              "b5",
              "letter",
              "legal",
              "tabloid",
              "halfletter"
            ],
            "default": "a4"
          },
          "orientation": {
            "title": "Orientation",
            "type": "string",
            "enum": [
              "portrait",
              "landscape"
            ],
            "default": "portrait"
          }
        },
        "required": []
      },
      "PrintshopNonogramResult": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "schemaVersion",
          "tool",
          "computedAt",
          "inputs",
          "summary",
          "result",
          "units",
          "assumptions",
          "sources",
          "warnings",
          "presentation",
          "links"
        ],
        "properties": {
          "schemaVersion": {
            "type": "string",
            "const": "1.0"
          },
          "tool": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "id",
              "name",
              "version"
            ],
            "properties": {
              "id": {
                "type": "string"
              },
              "name": {
                "type": "string"
              },
              "version": {
                "type": "string"
              }
            }
          },
          "computedAt": {
            "type": "string",
            "format": "date-time"
          },
          "inputs": {
            "type": "object",
            "description": "Normalised inputs actually used, including applied defaults."
          },
          "summary": {
            "type": "string"
          },
          "result": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "rows",
              "cols",
              "rowClues",
              "colClues",
              "lineSolvable",
              "givens",
              "filledCells",
              "solution",
              "seed",
              "pages",
              "puzzlePages",
              "answerPages",
              "pageWidthMm",
              "pageHeightMm",
              "warnings",
              "files",
              "openInApp"
            ],
            "properties": {
              "rows": {
                "type": "integer"
              },
              "cols": {
                "type": "integer"
              },
              "rowClues": {
                "type": "array",
                "items": {
                  "type": "array",
                  "items": {
                    "type": "integer"
                  }
                }
              },
              "colClues": {
                "type": "array",
                "items": {
                  "type": "array",
                  "items": {
                    "type": "integer"
                  }
                }
              },
              "lineSolvable": {
                "type": "boolean"
              },
              "givens": {
                "type": "integer"
              },
              "filledCells": {
                "type": "integer"
              },
              "solution": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "seed": {
                "type": "string"
              },
              "pages": {
                "type": "integer"
              },
              "puzzlePages": {
                "type": "integer"
              },
              "answerPages": {
                "type": "integer"
              },
              "pageWidthMm": {
                "type": "number"
              },
              "pageHeightMm": {
                "type": "number"
              },
              "warnings": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "files": {
                "type": [
                  "object",
                  "null"
                ],
                "additionalProperties": false,
                "required": [
                  "pdf",
                  "svg",
                  "png"
                ],
                "properties": {
                  "pdf": {
                    "type": "object",
                    "additionalProperties": false,
                    "required": [
                      "artifactId",
                      "filename",
                      "mime",
                      "bytes",
                      "sha256",
                      "path"
                    ],
                    "properties": {
                      "artifactId": {
                        "type": "string"
                      },
                      "filename": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "sha256": {
                        "type": "string"
                      },
                      "path": {
                        "type": "string",
                        "description": "Download path on the same site (valid for about 2 hours)."
                      }
                    }
                  },
                  "svg": {
                    "type": "object",
                    "additionalProperties": false,
                    "required": [
                      "artifactId",
                      "filename",
                      "mime",
                      "bytes",
                      "sha256",
                      "path"
                    ],
                    "properties": {
                      "artifactId": {
                        "type": "string"
                      },
                      "filename": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "sha256": {
                        "type": "string"
                      },
                      "path": {
                        "type": "string",
                        "description": "Download path on the same site (valid for about 2 hours)."
                      }
                    }
                  },
                  "png": {
                    "type": "object",
                    "additionalProperties": false,
                    "required": [
                      "artifactId",
                      "filename",
                      "mime",
                      "bytes",
                      "sha256",
                      "path"
                    ],
                    "properties": {
                      "artifactId": {
                        "type": "string"
                      },
                      "filename": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "sha256": {
                        "type": "string"
                      },
                      "path": {
                        "type": "string",
                        "description": "Download path on the same site (valid for about 2 hours)."
                      }
                    }
                  }
                }
              },
              "openInApp": {
                "type": [
                  "string",
                  "null"
                ]
              }
            }
          },
          "units": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            }
          },
          "assumptions": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "sources": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": false,
              "required": [
                "title"
              ],
              "properties": {
                "title": {
                  "type": "string"
                },
                "url": {
                  "type": "string"
                },
                "publisher": {
                  "type": "string"
                },
                "retrievedAt": {
                  "type": "string"
                },
                "note": {
                  "type": "string"
                }
              }
            }
          },
          "warnings": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "presentation": {
            "type": "array",
            "items": {
              "type": "object"
            },
            "description": "Display blocks used by the human page (same data)."
          },
          "links": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "human",
              "api",
              "openapi",
              "methodology"
            ],
            "properties": {
              "human": {
                "type": "string",
                "format": "uri"
              },
              "api": {
                "type": "string",
                "format": "uri"
              },
              "openapi": {
                "type": "string",
                "format": "uri"
              },
              "methodology": {
                "type": "string",
                "format": "uri"
              }
            }
          }
        }
      },
      "PrintshopMathWorksheetInput": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "kind": {
            "title": "Exercises",
            "type": "string",
            "enum": [
              "times",
              "add",
              "sub",
              "mul",
              "div",
              "fractions",
              "mixed"
            ],
            "default": "times"
          },
          "count": {
            "title": "Problems per variant",
            "type": "integer",
            "minimum": 1,
            "maximum": 100,
            "default": 30
          },
          "variants": {
            "title": "Variants (A, B, C …)",
            "type": "integer",
            "minimum": 1,
            "maximum": 6,
            "default": 3
          },
          "tables": {
            "title": "Times tables",
            "description": "For times tables and mixed facts, e.g. 2-10 or 3, 4, 7.",
            "type": "string",
            "maxLength": 60,
            "default": "2-10"
          },
          "maxFactor": {
            "title": "Largest factor",
            "type": "integer",
            "minimum": 2,
            "maximum": 20,
            "default": 10
          },
          "digits": {
            "title": "Digits per number (column sums, multiplication)",
            "type": "integer",
            "minimum": 1,
            "maximum": 6,
            "default": 3
          },
          "regroup": {
            "title": "Carrying and borrowing",
            "type": "boolean",
            "default": true
          },
          "digits2": {
            "title": "Digits of the second number (multiplication, division)",
            "type": "integer",
            "minimum": 1,
            "maximum": 3,
            "default": 1
          },
          "remainder": {
            "title": "Division with remainders",
            "type": "boolean",
            "default": false
          },
          "maxDenominator": {
            "title": "Largest denominator (fractions)",
            "type": "integer",
            "minimum": 2,
            "maximum": 20,
            "default": 10
          },
          "fractionOps": {
            "title": "Fraction operations",
            "type": "string",
            "enum": [
              "add",
              "sub",
              "both"
            ],
            "default": "add"
          },
          "sameDenominator": {
            "title": "Same denominators only",
            "type": "boolean",
            "default": false
          },
          "seed": {
            "title": "Seed",
            "description": "The same seed and settings always give the same puzzles. Change it for new ones.",
            "type": "string",
            "maxLength": 80,
            "default": "class-1"
          },
          "title": {
            "title": "Title on the page (optional)",
            "type": "string",
            "maxLength": 120,
            "default": ""
          },
          "answers": {
            "title": "Answer-key pages",
            "type": "boolean",
            "default": true
          },
          "header": {
            "title": "Name and date line",
            "type": "boolean",
            "default": true
          },
          "paper": {
            "title": "Paper size",
            "type": "string",
            "enum": [
              "a3",
              "a4",
              "a5",
              "a6",
              "b5",
              "letter",
              "legal",
              "tabloid",
              "halfletter"
            ],
            "default": "a4"
          },
          "orientation": {
            "title": "Orientation",
            "type": "string",
            "enum": [
              "portrait",
              "landscape"
            ],
            "default": "portrait"
          }
        },
        "required": []
      },
      "PrintshopMathWorksheetResult": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "schemaVersion",
          "tool",
          "computedAt",
          "inputs",
          "summary",
          "result",
          "units",
          "assumptions",
          "sources",
          "warnings",
          "presentation",
          "links"
        ],
        "properties": {
          "schemaVersion": {
            "type": "string",
            "const": "1.0"
          },
          "tool": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "id",
              "name",
              "version"
            ],
            "properties": {
              "id": {
                "type": "string"
              },
              "name": {
                "type": "string"
              },
              "version": {
                "type": "string"
              }
            }
          },
          "computedAt": {
            "type": "string",
            "format": "date-time"
          },
          "inputs": {
            "type": "object",
            "description": "Normalised inputs actually used, including applied defaults."
          },
          "summary": {
            "type": "string"
          },
          "result": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "kind",
              "variants",
              "seed",
              "pages",
              "puzzlePages",
              "answerPages",
              "pageWidthMm",
              "pageHeightMm",
              "warnings",
              "files",
              "openInApp"
            ],
            "properties": {
              "kind": {
                "type": "string"
              },
              "variants": {
                "type": "array",
                "items": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "variant",
                    "problems"
                  ],
                  "properties": {
                    "variant": {
                      "type": "string"
                    },
                    "problems": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "additionalProperties": false,
                        "required": [
                          "question",
                          "answer"
                        ],
                        "properties": {
                          "question": {
                            "type": "string"
                          },
                          "answer": {
                            "type": "string"
                          }
                        }
                      }
                    }
                  }
                }
              },
              "seed": {
                "type": "string"
              },
              "pages": {
                "type": "integer"
              },
              "puzzlePages": {
                "type": "integer"
              },
              "answerPages": {
                "type": "integer"
              },
              "pageWidthMm": {
                "type": "number"
              },
              "pageHeightMm": {
                "type": "number"
              },
              "warnings": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "files": {
                "type": [
                  "object",
                  "null"
                ],
                "additionalProperties": false,
                "required": [
                  "pdf",
                  "svg",
                  "png"
                ],
                "properties": {
                  "pdf": {
                    "type": "object",
                    "additionalProperties": false,
                    "required": [
                      "artifactId",
                      "filename",
                      "mime",
                      "bytes",
                      "sha256",
                      "path"
                    ],
                    "properties": {
                      "artifactId": {
                        "type": "string"
                      },
                      "filename": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "sha256": {
                        "type": "string"
                      },
                      "path": {
                        "type": "string",
                        "description": "Download path on the same site (valid for about 2 hours)."
                      }
                    }
                  },
                  "svg": {
                    "type": "object",
                    "additionalProperties": false,
                    "required": [
                      "artifactId",
                      "filename",
                      "mime",
                      "bytes",
                      "sha256",
                      "path"
                    ],
                    "properties": {
                      "artifactId": {
                        "type": "string"
                      },
                      "filename": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "sha256": {
                        "type": "string"
                      },
                      "path": {
                        "type": "string",
                        "description": "Download path on the same site (valid for about 2 hours)."
                      }
                    }
                  },
                  "png": {
                    "type": "object",
                    "additionalProperties": false,
                    "required": [
                      "artifactId",
                      "filename",
                      "mime",
                      "bytes",
                      "sha256",
                      "path"
                    ],
                    "properties": {
                      "artifactId": {
                        "type": "string"
                      },
                      "filename": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "sha256": {
                        "type": "string"
                      },
                      "path": {
                        "type": "string",
                        "description": "Download path on the same site (valid for about 2 hours)."
                      }
                    }
                  }
                }
              },
              "openInApp": {
                "type": [
                  "string",
                  "null"
                ]
              }
            }
          },
          "units": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            }
          },
          "assumptions": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "sources": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": false,
              "required": [
                "title"
              ],
              "properties": {
                "title": {
                  "type": "string"
                },
                "url": {
                  "type": "string"
                },
                "publisher": {
                  "type": "string"
                },
                "retrievedAt": {
                  "type": "string"
                },
                "note": {
                  "type": "string"
                }
              }
            }
          },
          "warnings": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "presentation": {
            "type": "array",
            "items": {
              "type": "object"
            },
            "description": "Display blocks used by the human page (same data)."
          },
          "links": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "human",
              "api",
              "openapi",
              "methodology"
            ],
            "properties": {
              "human": {
                "type": "string",
                "format": "uri"
              },
              "api": {
                "type": "string",
                "format": "uri"
              },
              "openapi": {
                "type": "string",
                "format": "uri"
              },
              "methodology": {
                "type": "string",
                "format": "uri"
              }
            }
          }
        }
      },
      "RuledateInput": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "startDate": {
            "title": "Start date",
            "type": "string",
            "format": "date"
          },
          "operations": {
            "title": "Operations (applied in order)",
            "type": "array",
            "minItems": 1,
            "maxItems": 20,
            "items": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "op": {
                  "title": "Operation",
                  "type": "string",
                  "enum": [
                    "add-business-days",
                    "add-calendar-days",
                    "add-weeks",
                    "add-months",
                    "end-of-month",
                    "next-business-day",
                    "previous-business-day"
                  ]
                },
                "amount": {
                  "title": "Amount",
                  "description": "Negative values go backwards.",
                  "type": "integer",
                  "minimum": -3650,
                  "maximum": 3650,
                  "default": 0
                }
              },
              "required": [
                "op"
              ]
            }
          },
          "country": {
            "title": "Holiday calendar",
            "type": "string",
            "enum": [
              "none",
              "DE",
              "AT",
              "CH",
              "US",
              "GB",
              "FR",
              "NL",
              "BE",
              "ES",
              "IT",
              "PL",
              "SE",
              "DK",
              "IE",
              "CA",
              "AU"
            ],
            "default": "DE"
          },
          "subdivision": {
            "title": "Subdivision (optional)",
            "description": "ISO 3166-2 code, e.g. DE-BY (Bavaria), CH-ZH, US-CA. Without it only nationwide holidays count.",
            "type": "string",
            "maxLength": 10
          },
          "weekendDays": {
            "title": "Weekend days",
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "sun",
                "mon",
                "tue",
                "wed",
                "thu",
                "fri",
                "sat"
              ]
            },
            "default": [
              "sat",
              "sun"
            ]
          },
          "closures": {
            "title": "Extra closure dates",
            "description": "One YYYY-MM-DD per line (company holidays, bridge days).",
            "type": "array",
            "items": {
              "type": "string"
            },
            "maxItems": 366
          },
          "monthEndRule": {
            "title": "Month arithmetic",
            "type": "string",
            "enum": [
              "clamp",
              "overflow"
            ],
            "default": "clamp"
          },
          "finalRule": {
            "title": "Final adjustment",
            "type": "string",
            "enum": [
              "none",
              "bgb193"
            ],
            "default": "none"
          }
        },
        "required": [
          "startDate",
          "operations"
        ]
      },
      "RuledateResult": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "schemaVersion",
          "tool",
          "computedAt",
          "inputs",
          "summary",
          "result",
          "units",
          "assumptions",
          "sources",
          "warnings",
          "presentation",
          "links"
        ],
        "properties": {
          "schemaVersion": {
            "type": "string",
            "const": "1.0"
          },
          "tool": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "id",
              "name",
              "version"
            ],
            "properties": {
              "id": {
                "type": "string"
              },
              "name": {
                "type": "string"
              },
              "version": {
                "type": "string"
              }
            }
          },
          "computedAt": {
            "type": "string",
            "format": "date-time"
          },
          "inputs": {
            "type": "object",
            "description": "Normalised inputs actually used, including applied defaults."
          },
          "summary": {
            "type": "string"
          },
          "result": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "startDate",
              "finalDate",
              "finalWeekday",
              "country",
              "subdivision",
              "weekendDays",
              "steps",
              "holidaysApplied",
              "dataRange",
              "outsideDataRange"
            ],
            "properties": {
              "startDate": {
                "type": "string",
                "format": "date"
              },
              "finalDate": {
                "type": "string",
                "format": "date"
              },
              "finalWeekday": {
                "type": "string"
              },
              "country": {
                "type": "string"
              },
              "subdivision": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "weekendDays": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "steps": {
                "type": "array",
                "items": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "step",
                    "operation",
                    "amount",
                    "from",
                    "to",
                    "skipped",
                    "note"
                  ],
                  "properties": {
                    "step": {
                      "type": "integer",
                      "minimum": 1
                    },
                    "operation": {
                      "type": "string"
                    },
                    "amount": {
                      "type": "integer"
                    },
                    "from": {
                      "type": "string",
                      "format": "date"
                    },
                    "to": {
                      "type": "string",
                      "format": "date"
                    },
                    "note": {
                      "type": "string"
                    },
                    "skipped": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "additionalProperties": false,
                        "required": [
                          "date",
                          "weekday",
                          "reasons"
                        ],
                        "properties": {
                          "date": {
                            "type": "string",
                            "format": "date"
                          },
                          "weekday": {
                            "type": "string"
                          },
                          "reasons": {
                            "type": "array",
                            "items": {
                              "type": "string"
                            }
                          }
                        }
                      }
                    }
                  }
                }
              },
              "holidaysApplied": {
                "type": "array",
                "items": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "date",
                    "name",
                    "localName",
                    "scope"
                  ],
                  "properties": {
                    "date": {
                      "type": "string",
                      "format": "date"
                    },
                    "name": {
                      "type": "string"
                    },
                    "localName": {
                      "type": "string"
                    },
                    "scope": {
                      "type": "string"
                    }
                  }
                }
              },
              "dataRange": {
                "type": "object",
                "additionalProperties": false,
                "required": [
                  "firstYear",
                  "lastYear"
                ],
                "properties": {
                  "firstYear": {
                    "type": "integer"
                  },
                  "lastYear": {
                    "type": "integer"
                  }
                }
              },
              "outsideDataRange": {
                "type": "boolean"
              }
            }
          },
          "units": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            }
          },
          "assumptions": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "sources": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": false,
              "required": [
                "title"
              ],
              "properties": {
                "title": {
                  "type": "string"
                },
                "url": {
                  "type": "string"
                },
                "publisher": {
                  "type": "string"
                },
                "retrievedAt": {
                  "type": "string"
                },
                "note": {
                  "type": "string"
                }
              }
            }
          },
          "warnings": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "presentation": {
            "type": "array",
            "items": {
              "type": "object"
            },
            "description": "Display blocks used by the human page (same data)."
          },
          "links": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "human",
              "api",
              "openapi",
              "methodology"
            ],
            "properties": {
              "human": {
                "type": "string",
                "format": "uri"
              },
              "api": {
                "type": "string",
                "format": "uri"
              },
              "openapi": {
                "type": "string",
                "format": "uri"
              },
              "methodology": {
                "type": "string",
                "format": "uri"
              }
            }
          }
        }
      },
      "LuminaPrintPlannerInput": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "width": {
            "title": "Photo width (px)",
            "type": "integer",
            "minimum": 1,
            "maximum": 100000,
            "default": 6000
          },
          "height": {
            "title": "Photo height (px)",
            "type": "integer",
            "minimum": 1,
            "maximum": 100000,
            "default": 4000
          },
          "ppi": {
            "title": "Print resolution (PPI)",
            "type": "integer",
            "minimum": 1,
            "maximum": 2400,
            "default": 300
          }
        },
        "required": []
      },
      "LuminaPrintPlannerResult": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "schemaVersion",
          "tool",
          "computedAt",
          "inputs",
          "summary",
          "result",
          "units",
          "assumptions",
          "sources",
          "warnings",
          "presentation",
          "links"
        ],
        "properties": {
          "schemaVersion": {
            "type": "string",
            "const": "1.0"
          },
          "tool": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "id",
              "name",
              "version"
            ],
            "properties": {
              "id": {
                "type": "string"
              },
              "name": {
                "type": "string"
              },
              "version": {
                "type": "string"
              }
            }
          },
          "computedAt": {
            "type": "string",
            "format": "date-time"
          },
          "inputs": {
            "type": "object",
            "description": "Normalised inputs actually used, including applied defaults."
          },
          "summary": {
            "type": "string"
          },
          "result": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "widthInches",
              "heightInches",
              "widthCm",
              "heightCm",
              "ppi",
              "megapixels"
            ],
            "properties": {
              "widthInches": {
                "type": "number"
              },
              "heightInches": {
                "type": "number"
              },
              "widthCm": {
                "type": "number"
              },
              "heightCm": {
                "type": "number"
              },
              "ppi": {
                "type": "number"
              },
              "megapixels": {
                "type": "number"
              }
            }
          },
          "units": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            }
          },
          "assumptions": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "sources": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": false,
              "required": [
                "title"
              ],
              "properties": {
                "title": {
                  "type": "string"
                },
                "url": {
                  "type": "string"
                },
                "publisher": {
                  "type": "string"
                },
                "retrievedAt": {
                  "type": "string"
                },
                "note": {
                  "type": "string"
                }
              }
            }
          },
          "warnings": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "presentation": {
            "type": "array",
            "items": {
              "type": "object"
            },
            "description": "Display blocks used by the human page (same data)."
          },
          "links": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "human",
              "api",
              "openapi",
              "methodology"
            ],
            "properties": {
              "human": {
                "type": "string",
                "format": "uri"
              },
              "api": {
                "type": "string",
                "format": "uri"
              },
              "openapi": {
                "type": "string",
                "format": "uri"
              },
              "methodology": {
                "type": "string",
                "format": "uri"
              }
            }
          }
        }
      },
      "LuminaImageSplitterInput": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "images": {
            "title": "Single photo (PNG, JPEG, WebP or GIF)",
            "description": "Exactly one PNG, JPEG, WebP or GIF image (first frame), up to 16 MP decoded; a ZIP containing exactly one photo also works. To split several photos, run the tool once per photo. Upload as {filename, contentType?, contentBase64}. Max 78125 KiB. Accepts .zip,.png,.jpg,.jpeg,.webp,.gif.",
            "type": "object",
            "additionalProperties": false,
            "required": [
              "filename",
              "contentBase64"
            ],
            "properties": {
              "filename": {
                "type": "string"
              },
              "contentType": {
                "type": "string"
              },
              "contentBase64": {
                "type": "string"
              }
            }
          },
          "rows": {
            "title": "Rows",
            "type": "integer",
            "minimum": 1,
            "maximum": 12,
            "default": 3
          },
          "columns": {
            "title": "Columns",
            "type": "integer",
            "minimum": 1,
            "maximum": 12,
            "default": 3
          }
        },
        "required": [
          "images"
        ]
      },
      "LuminaImageSplitterResult": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "schemaVersion",
          "tool",
          "computedAt",
          "inputs",
          "summary",
          "result",
          "units",
          "assumptions",
          "sources",
          "warnings",
          "presentation",
          "links"
        ],
        "properties": {
          "schemaVersion": {
            "type": "string",
            "const": "1.0"
          },
          "tool": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "id",
              "name",
              "version"
            ],
            "properties": {
              "id": {
                "type": "string"
              },
              "name": {
                "type": "string"
              },
              "version": {
                "type": "string"
              }
            }
          },
          "computedAt": {
            "type": "string",
            "format": "date-time"
          },
          "inputs": {
            "type": "object",
            "description": "Normalised inputs actually used, including applied defaults."
          },
          "summary": {
            "type": "string"
          },
          "result": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "width",
              "height",
              "tiles",
              "artifact"
            ],
            "properties": {
              "width": {
                "type": "integer"
              },
              "height": {
                "type": "integer"
              },
              "tiles": {
                "type": "integer"
              },
              "artifact": {
                "type": "object",
                "additionalProperties": false,
                "required": [
                  "artifactId",
                  "filename",
                  "mime",
                  "bytes",
                  "sha256",
                  "path"
                ],
                "properties": {
                  "artifactId": {
                    "type": "string"
                  },
                  "filename": {
                    "type": "string"
                  },
                  "mime": {
                    "type": "string"
                  },
                  "bytes": {
                    "type": "integer"
                  },
                  "sha256": {
                    "type": "string"
                  },
                  "path": {
                    "type": "string",
                    "description": "Download path on the same site (valid for about 2 hours)."
                  }
                }
              }
            }
          },
          "units": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            }
          },
          "assumptions": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "sources": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": false,
              "required": [
                "title"
              ],
              "properties": {
                "title": {
                  "type": "string"
                },
                "url": {
                  "type": "string"
                },
                "publisher": {
                  "type": "string"
                },
                "retrievedAt": {
                  "type": "string"
                },
                "note": {
                  "type": "string"
                }
              }
            }
          },
          "warnings": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "presentation": {
            "type": "array",
            "items": {
              "type": "object"
            },
            "description": "Display blocks used by the human page (same data)."
          },
          "links": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "human",
              "api",
              "openapi",
              "methodology"
            ],
            "properties": {
              "human": {
                "type": "string",
                "format": "uri"
              },
              "api": {
                "type": "string",
                "format": "uri"
              },
              "openapi": {
                "type": "string",
                "format": "uri"
              },
              "methodology": {
                "type": "string",
                "format": "uri"
              }
            }
          }
        }
      },
      "PanelcraftBookPlanInput": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "name": {
            "title": "Book title",
            "type": "string",
            "maxLength": 120,
            "default": "A small adventure"
          },
          "author": {
            "title": "Author or credit",
            "type": "string",
            "maxLength": 120,
            "default": ""
          },
          "pages": {
            "title": "Book pages",
            "type": "integer",
            "minimum": 1,
            "maximum": 12,
            "default": 8
          },
          "rows": {
            "title": "Panel rows",
            "type": "integer",
            "minimum": 1,
            "maximum": 12,
            "default": 2
          },
          "columns": {
            "title": "Panel columns",
            "type": "integer",
            "minimum": 1,
            "maximum": 12,
            "default": 2
          },
          "reading": {
            "title": "Reading and binding direction",
            "type": "string",
            "enum": [
              "ltr",
              "rtl"
            ],
            "default": "ltr"
          },
          "sheetColumns": {
            "title": "Contact-sheet columns",
            "type": "integer",
            "minimum": 1,
            "maximum": 4,
            "default": 3
          }
        },
        "required": []
      },
      "PanelcraftBookPlanResult": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "schemaVersion",
          "tool",
          "computedAt",
          "inputs",
          "summary",
          "result",
          "units",
          "assumptions",
          "sources",
          "warnings",
          "presentation",
          "links"
        ],
        "properties": {
          "schemaVersion": {
            "type": "string",
            "const": "1.0"
          },
          "tool": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "id",
              "name",
              "version"
            ],
            "properties": {
              "id": {
                "type": "string"
              },
              "name": {
                "type": "string"
              },
              "version": {
                "type": "string"
              }
            }
          },
          "computedAt": {
            "type": "string",
            "format": "date-time"
          },
          "inputs": {
            "type": "object",
            "description": "Normalised inputs actually used, including applied defaults."
          },
          "summary": {
            "type": "string"
          },
          "result": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "project",
              "report",
              "imposition",
              "contactSheet",
              "projectFile",
              "letteringCsv",
              "openInApp"
            ],
            "properties": {
              "project": {
                "type": "object",
                "additionalProperties": false,
                "required": [
                  "format",
                  "version",
                  "name",
                  "author",
                  "reading",
                  "pages"
                ],
                "properties": {
                  "format": {
                    "const": "panelcraft-book"
                  },
                  "version": {
                    "const": 1
                  },
                  "name": {
                    "type": "string",
                    "maxLength": 120
                  },
                  "author": {
                    "type": "string",
                    "maxLength": 120
                  },
                  "reading": {
                    "enum": [
                      "ltr",
                      "rtl"
                    ]
                  },
                  "pages": {
                    "type": "array",
                    "minItems": 1,
                    "maxItems": 12,
                    "items": {
                      "type": "object",
                      "additionalProperties": false,
                      "required": [
                        "id",
                        "notes",
                        "comic"
                      ],
                      "properties": {
                        "id": {
                          "type": "string",
                          "pattern": "^[-a-zA-Z0-9_]{1,64}$"
                        },
                        "notes": {
                          "type": "string",
                          "maxLength": 2000
                        },
                        "comic": {
                          "type": "object",
                          "additionalProperties": false,
                          "required": [
                            "format",
                            "version",
                            "name",
                            "width",
                            "height",
                            "dpi",
                            "margin",
                            "gutter",
                            "border",
                            "paper",
                            "reading",
                            "panels",
                            "balloons",
                            "artwork"
                          ],
                          "properties": {
                            "format": {
                              "const": "flipline-comic"
                            },
                            "version": {
                              "const": 1
                            },
                            "name": {
                              "type": "string",
                              "maxLength": 120
                            },
                            "width": {
                              "type": "integer",
                              "minimum": 400,
                              "maximum": 2400
                            },
                            "height": {
                              "type": "integer",
                              "minimum": 400,
                              "maximum": 4000
                            },
                            "dpi": {
                              "type": "integer",
                              "minimum": 72,
                              "maximum": 600
                            },
                            "margin": {
                              "type": "number"
                            },
                            "gutter": {
                              "type": "number"
                            },
                            "border": {
                              "type": "number"
                            },
                            "paper": {
                              "type": "string"
                            },
                            "reading": {
                              "enum": [
                                "ltr",
                                "rtl"
                              ]
                            },
                            "panels": {
                              "type": "array",
                              "minItems": 1,
                              "maxItems": 12,
                              "items": {
                                "type": "object",
                                "additionalProperties": false,
                                "required": [
                                  "id",
                                  "name",
                                  "x",
                                  "y",
                                  "width",
                                  "height",
                                  "paper",
                                  "fit",
                                  "zoom",
                                  "panX",
                                  "panY",
                                  "sourceWidth",
                                  "sourceHeight",
                                  "tone"
                                ],
                                "properties": {
                                  "id": {
                                    "type": "string",
                                    "maxLength": 64
                                  },
                                  "name": {
                                    "type": "string",
                                    "maxLength": 80
                                  },
                                  "x": {
                                    "type": "number"
                                  },
                                  "y": {
                                    "type": "number"
                                  },
                                  "width": {
                                    "type": "number"
                                  },
                                  "height": {
                                    "type": "number"
                                  },
                                  "paper": {
                                    "type": "string"
                                  },
                                  "fit": {
                                    "enum": [
                                      "contain",
                                      "cover"
                                    ]
                                  },
                                  "zoom": {
                                    "type": "number"
                                  },
                                  "panX": {
                                    "type": "number"
                                  },
                                  "panY": {
                                    "type": "number"
                                  },
                                  "sourceWidth": {
                                    "type": "integer"
                                  },
                                  "sourceHeight": {
                                    "type": "integer"
                                  },
                                  "tone": {
                                    "type": "object",
                                    "additionalProperties": false,
                                    "required": [
                                      "kind",
                                      "pitch",
                                      "coverage",
                                      "angle",
                                      "ink",
                                      "over"
                                    ],
                                    "properties": {
                                      "kind": {
                                        "enum": [
                                          "none",
                                          "dots",
                                          "lines",
                                          "crosshatch"
                                        ]
                                      },
                                      "pitch": {
                                        "type": "number",
                                        "minimum": 4,
                                        "maximum": 80
                                      },
                                      "coverage": {
                                        "type": "number",
                                        "minimum": 0.05,
                                        "maximum": 0.75
                                      },
                                      "angle": {
                                        "type": "number",
                                        "minimum": -90,
                                        "maximum": 90
                                      },
                                      "ink": {
                                        "type": "string",
                                        "pattern": "^#[a-fA-F0-9]{6}$"
                                      },
                                      "over": {
                                        "type": "boolean"
                                      }
                                    }
                                  }
                                }
                              }
                            },
                            "balloons": {
                              "type": "array",
                              "maxItems": 36,
                              "items": {
                                "type": "object",
                                "additionalProperties": false,
                                "required": [
                                  "id",
                                  "panel",
                                  "kind",
                                  "x",
                                  "y",
                                  "width",
                                  "height",
                                  "tailX",
                                  "tailY",
                                  "text",
                                  "fontSize",
                                  "ink",
                                  "paper"
                                ],
                                "properties": {
                                  "id": {
                                    "type": "string",
                                    "maxLength": 64
                                  },
                                  "panel": {
                                    "type": "string",
                                    "maxLength": 64
                                  },
                                  "kind": {
                                    "enum": [
                                      "speech",
                                      "thought",
                                      "caption"
                                    ]
                                  },
                                  "x": {
                                    "type": "number"
                                  },
                                  "y": {
                                    "type": "number"
                                  },
                                  "width": {
                                    "type": "number"
                                  },
                                  "height": {
                                    "type": "number"
                                  },
                                  "tailX": {
                                    "type": "number"
                                  },
                                  "tailY": {
                                    "type": "number"
                                  },
                                  "text": {
                                    "type": "string",
                                    "maxLength": 600
                                  },
                                  "fontSize": {
                                    "type": "number"
                                  },
                                  "ink": {
                                    "type": "string"
                                  },
                                  "paper": {
                                    "type": "string"
                                  }
                                }
                              }
                            },
                            "artwork": {
                              "type": "object",
                              "additionalProperties": false,
                              "required": [
                                "format",
                                "version",
                                "name",
                                "width",
                                "height",
                                "fps",
                                "paper",
                                "boards"
                              ],
                              "properties": {
                                "format": {
                                  "const": "flipline-story"
                                },
                                "version": {
                                  "const": 1
                                },
                                "name": {
                                  "type": "string",
                                  "maxLength": 120
                                },
                                "width": {
                                  "type": "integer",
                                  "minimum": 32,
                                  "maximum": 1600
                                },
                                "height": {
                                  "type": "integer",
                                  "minimum": 32,
                                  "maximum": 1600
                                },
                                "fps": {
                                  "type": "integer",
                                  "minimum": 1,
                                  "maximum": 30
                                },
                                "paper": {
                                  "type": "string",
                                  "pattern": "^#[a-fA-F0-9]{6}$"
                                },
                                "boards": {
                                  "type": "array",
                                  "minItems": 1,
                                  "maxItems": 48,
                                  "items": {
                                    "type": "object",
                                    "additionalProperties": false,
                                    "required": [
                                      "id",
                                      "title",
                                      "scene",
                                      "shot",
                                      "camera",
                                      "frames",
                                      "action",
                                      "dialogue",
                                      "notes",
                                      "locked",
                                      "marks",
                                      "reference"
                                    ],
                                    "properties": {
                                      "id": {
                                        "type": "string",
                                        "pattern": "^[-a-zA-Z0-9_]{1,80}$"
                                      },
                                      "title": {
                                        "type": "string",
                                        "maxLength": 80
                                      },
                                      "scene": {
                                        "type": "string",
                                        "maxLength": 80
                                      },
                                      "shot": {
                                        "enum": [
                                          "wide",
                                          "medium",
                                          "close",
                                          "detail",
                                          "over-shoulder"
                                        ]
                                      },
                                      "camera": {
                                        "enum": [
                                          "static",
                                          "pan-left",
                                          "pan-right",
                                          "tilt-up",
                                          "tilt-down",
                                          "push-in",
                                          "pull-out",
                                          "handheld"
                                        ]
                                      },
                                      "frames": {
                                        "type": "integer",
                                        "minimum": 1,
                                        "maximum": 3600
                                      },
                                      "action": {
                                        "type": "string",
                                        "maxLength": 1200
                                      },
                                      "dialogue": {
                                        "type": "string",
                                        "maxLength": 1200
                                      },
                                      "notes": {
                                        "type": "string",
                                        "maxLength": 1200
                                      },
                                      "locked": {
                                        "type": "boolean"
                                      },
                                      "marks": {
                                        "type": "array",
                                        "maxItems": 500,
                                        "items": {
                                          "type": "object",
                                          "additionalProperties": false,
                                          "required": [
                                            "id",
                                            "kind",
                                            "points",
                                            "color",
                                            "size",
                                            "fill"
                                          ],
                                          "properties": {
                                            "brush": {
                                              "type": "object",
                                              "additionalProperties": false,
                                              "required": [
                                                "kind",
                                                "opacity",
                                                "flow",
                                                "spacing",
                                                "texture",
                                                "pressure",
                                                "seed"
                                              ],
                                              "properties": {
                                                "kind": {
                                                  "enum": [
                                                    "ink",
                                                    "pencil",
                                                    "marker",
                                                    "wash",
                                                    "airbrush"
                                                  ]
                                                },
                                                "opacity": {
                                                  "type": "number",
                                                  "minimum": 0,
                                                  "maximum": 1
                                                },
                                                "flow": {
                                                  "type": "number",
                                                  "minimum": 0,
                                                  "maximum": 1
                                                },
                                                "spacing": {
                                                  "type": "number",
                                                  "minimum": 0.08,
                                                  "maximum": 1
                                                },
                                                "texture": {
                                                  "type": "number",
                                                  "minimum": 0,
                                                  "maximum": 1
                                                },
                                                "pressure": {
                                                  "type": "boolean"
                                                },
                                                "seed": {
                                                  "type": "integer",
                                                  "minimum": 0,
                                                  "maximum": 4294967295
                                                }
                                              }
                                            },
                                            "pressures": {
                                              "type": "array",
                                              "minItems": 1,
                                              "maxItems": 4096,
                                              "items": {
                                                "type": "number",
                                                "minimum": 0,
                                                "maximum": 1
                                              }
                                            },
                                            "id": {
                                              "type": "string",
                                              "minLength": 1,
                                              "maxLength": 80
                                            },
                                            "kind": {
                                              "enum": [
                                                "pen",
                                                "eraser",
                                                "line",
                                                "rect",
                                                "ellipse",
                                                "image"
                                              ]
                                            },
                                            "points": {
                                              "type": "array",
                                              "minItems": 1,
                                              "maxItems": 4096,
                                              "items": {
                                                "type": "array",
                                                "minItems": 2,
                                                "maxItems": 2,
                                                "items": {
                                                  "type": "number",
                                                  "minimum": 0,
                                                  "maximum": 1
                                                }
                                              }
                                            },
                                            "color": {
                                              "type": "string",
                                              "pattern": "^#[a-fA-F0-9]{6}$"
                                            },
                                            "size": {
                                              "type": "number",
                                              "minimum": 1,
                                              "maximum": 100
                                            },
                                            "fill": {
                                              "type": "boolean"
                                            },
                                            "source": {
                                              "type": "string",
                                              "pattern": "^data:image/(png|jpeg|webp);base64,[A-Za-z0-9+/=]+$"
                                            },
                                            "angle": {
                                              "type": "number",
                                              "minimum": -360,
                                              "maximum": 360,
                                              "description": "Clockwise rotation in degrees around the center of the mark bounds (normalized to -180…180)."
                                            },
                                            "flipX": {
                                              "type": "boolean",
                                              "description": "Mirror horizontally around the mark center."
                                            },
                                            "flipY": {
                                              "type": "boolean",
                                              "description": "Mirror vertically around the mark center."
                                            }
                                          }
                                        }
                                      },
                                      "reference": {
                                        "type": [
                                          "object",
                                          "null"
                                        ],
                                        "additionalProperties": false,
                                        "required": [
                                          "source",
                                          "opacity",
                                          "visible"
                                        ],
                                        "properties": {
                                          "source": {
                                            "type": "string",
                                            "pattern": "^data:image/(png|jpeg|webp);base64,[A-Za-z0-9+/=]+$"
                                          },
                                          "opacity": {
                                            "type": "number",
                                            "minimum": 0,
                                            "maximum": 1
                                          },
                                          "visible": {
                                            "type": "boolean"
                                          }
                                        }
                                      }
                                    }
                                  }
                                }
                              },
                              "description": "Story Desk. Frame-based board durations, half-open timeline intervals and non-drop-frame timecodes. Up to 600 seconds total and 120 seconds per board at the chosen FPS. Canvas up to 2 MP, 50000 points, 2000 marks and 6 million source-image characters across all boards. Ink erasers affect preceding ink only; the independent reference is preserved. Camera moves are planning labels, not animated camera paths."
                            }
                          },
                          "description": "Comic Desk page. At most 6 MP, 12 panels and 36 balloons. Panel/artwork board IDs align by index. Shared Story Desk mark budgets apply; image marks are disallowed. PNG references match declared dimensions, at most 2 MP each and 8 MP total. All embedded references together fit 6 million characters. Text overflow is reported, never silently exported by the workspace."
                        }
                      }
                    }
                  }
                },
                "description": "Panelcraft 1.0 comic book, 1–12 ordered pages. Each comic follows the Flipline Comic Desk schema. Aggregate normalized page JSON must fit 24 million characters. Page IDs are unique. Per-page art and image limits apply. Reading sets booklet binding; each page retains its own panel reading direction."
              },
              "report": {
                "type": "object",
                "additionalProperties": false,
                "required": [
                  "pages",
                  "panels",
                  "balloons",
                  "overflow",
                  "embeddedCharacters"
                ],
                "properties": {
                  "pages": {
                    "type": "integer"
                  },
                  "panels": {
                    "type": "integer"
                  },
                  "balloons": {
                    "type": "integer"
                  },
                  "overflow": {
                    "type": "array",
                    "items": {
                      "type": "object",
                      "additionalProperties": false,
                      "required": [
                        "page",
                        "id"
                      ],
                      "properties": {
                        "page": {
                          "type": "integer"
                        },
                        "id": {
                          "type": "string"
                        }
                      }
                    }
                  },
                  "embeddedCharacters": {
                    "type": "integer"
                  }
                }
              },
              "imposition": {
                "type": "object",
                "additionalProperties": false,
                "required": [
                  "pages",
                  "paddedPages",
                  "blankPages",
                  "sheets"
                ],
                "properties": {
                  "pages": {
                    "type": "integer"
                  },
                  "paddedPages": {
                    "type": "integer"
                  },
                  "blankPages": {
                    "type": "integer"
                  },
                  "sheets": {
                    "type": "array",
                    "items": {
                      "type": "object",
                      "additionalProperties": false,
                      "required": [
                        "sheet",
                        "front",
                        "back"
                      ],
                      "properties": {
                        "sheet": {
                          "type": "integer"
                        },
                        "front": {
                          "type": "array",
                          "minItems": 2,
                          "maxItems": 2,
                          "items": {
                            "type": [
                              "integer",
                              "null"
                            ]
                          }
                        },
                        "back": {
                          "type": "array",
                          "minItems": 2,
                          "maxItems": 2,
                          "items": {
                            "type": [
                              "integer",
                              "null"
                            ]
                          }
                        }
                      }
                    }
                  }
                }
              },
              "contactSheet": {
                "type": "object",
                "additionalProperties": false,
                "required": [
                  "artifactId",
                  "filename",
                  "mime",
                  "bytes",
                  "sha256",
                  "path"
                ],
                "properties": {
                  "artifactId": {
                    "type": "string"
                  },
                  "filename": {
                    "type": "string"
                  },
                  "mime": {
                    "type": "string"
                  },
                  "bytes": {
                    "type": "integer"
                  },
                  "sha256": {
                    "type": "string"
                  },
                  "path": {
                    "type": "string",
                    "description": "Download path on the same site (valid for about 2 hours)."
                  }
                }
              },
              "projectFile": {
                "type": "object",
                "additionalProperties": false,
                "required": [
                  "artifactId",
                  "filename",
                  "mime",
                  "bytes",
                  "sha256",
                  "path"
                ],
                "properties": {
                  "artifactId": {
                    "type": "string"
                  },
                  "filename": {
                    "type": "string"
                  },
                  "mime": {
                    "type": "string"
                  },
                  "bytes": {
                    "type": "integer"
                  },
                  "sha256": {
                    "type": "string"
                  },
                  "path": {
                    "type": "string",
                    "description": "Download path on the same site (valid for about 2 hours)."
                  }
                }
              },
              "letteringCsv": {
                "type": "object",
                "additionalProperties": false,
                "required": [
                  "artifactId",
                  "filename",
                  "mime",
                  "bytes",
                  "sha256",
                  "path"
                ],
                "properties": {
                  "artifactId": {
                    "type": "string"
                  },
                  "filename": {
                    "type": "string"
                  },
                  "mime": {
                    "type": "string"
                  },
                  "bytes": {
                    "type": "integer"
                  },
                  "sha256": {
                    "type": "string"
                  },
                  "path": {
                    "type": "string",
                    "description": "Download path on the same site (valid for about 2 hours)."
                  }
                }
              },
              "openInApp": {
                "type": [
                  "string",
                  "null"
                ]
              }
            }
          },
          "units": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            }
          },
          "assumptions": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "sources": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": false,
              "required": [
                "title"
              ],
              "properties": {
                "title": {
                  "type": "string"
                },
                "url": {
                  "type": "string"
                },
                "publisher": {
                  "type": "string"
                },
                "retrievedAt": {
                  "type": "string"
                },
                "note": {
                  "type": "string"
                }
              }
            }
          },
          "warnings": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "presentation": {
            "type": "array",
            "items": {
              "type": "object"
            },
            "description": "Display blocks used by the human page (same data)."
          },
          "links": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "human",
              "api",
              "openapi",
              "methodology"
            ],
            "properties": {
              "human": {
                "type": "string",
                "format": "uri"
              },
              "api": {
                "type": "string",
                "format": "uri"
              },
              "openapi": {
                "type": "string",
                "format": "uri"
              },
              "methodology": {
                "type": "string",
                "format": "uri"
              }
            }
          }
        }
      }
    }
  }
}