{
    "openapi": "3.1.0",
    "info": {
        "title": "Digital Greenhouse free tools API",
        "version": "1.0",
        "description": "Free, keyless endpoints for AI agents and scripts to check their work or look something up: Australian GST and ABN/ACN checks, DNS and email-setup checks, calculators, encoders and converters. Same maths as the tool pages at https://digitalgreenhouse.com.au/tools. Fair use: calculators 120/min per IP, dns-lookup 20/min, mx-email-check 6/min. General information only.",
        "contact": {
            "name": "Digital Greenhouse",
            "url": "https://digitalgreenhouse.com.au/contact"
        }
    },
    "servers": [
        {
            "url": "https://digitalgreenhouse.com.au/api/tools"
        }
    ],
    "externalDocs": {
        "url": "https://digitalgreenhouse.com.au/tools/api"
    },
    "paths": {
        "/gst-calculator": {
            "get": {
                "operationId": "gstCalculator",
                "summary": "GST Calculator (Australia)",
                "description": "Add Australia's 10% GST to a price, or work out the GST already included in a total. Human page: https://digitalgreenhouse.com.au/tools/gst-calculator",
                "tags": [
                    "Australian business"
                ],
                "parameters": [
                    {
                        "name": "amount",
                        "in": "query",
                        "required": true,
                        "description": "The amount in AUD. \"$1,100\" style input is accepted.",
                        "schema": {
                            "type": "number"
                        },
                        "example": "110"
                    },
                    {
                        "name": "mode",
                        "in": "query",
                        "required": false,
                        "description": "add = the amount excludes GST; remove = the amount already includes GST.",
                        "schema": {
                            "type": "string",
                            "enum": [
                                "add",
                                "remove"
                            ],
                            "default": "add"
                        },
                        "example": "remove"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Result",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Result"
                                }
                            }
                        }
                    },
                    "400": {
                        "description": "Bad input",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "Rate limited; see the Retry-After header",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    }
                }
            },
            "post": {
                "operationId": "gstCalculatorPost",
                "summary": "GST Calculator (Australia) (POST body)",
                "description": "Add Australia's 10% GST to a price, or work out the GST already included in a total.",
                "tags": [
                    "Australian business"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "amount": {
                                        "type": "number",
                                        "description": "The amount in AUD. \"$1,100\" style input is accepted."
                                    },
                                    "mode": {
                                        "type": "string",
                                        "enum": [
                                            "add",
                                            "remove"
                                        ],
                                        "default": "add",
                                        "description": "add = the amount excludes GST; remove = the amount already includes GST."
                                    }
                                },
                                "required": [
                                    "amount"
                                ]
                            }
                        },
                        "application/x-www-form-urlencoded": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "amount": {
                                        "type": "number",
                                        "description": "The amount in AUD. \"$1,100\" style input is accepted."
                                    },
                                    "mode": {
                                        "type": "string",
                                        "enum": [
                                            "add",
                                            "remove"
                                        ],
                                        "default": "add",
                                        "description": "add = the amount excludes GST; remove = the amount already includes GST."
                                    }
                                },
                                "required": [
                                    "amount"
                                ]
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Result",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Result"
                                }
                            }
                        }
                    },
                    "400": {
                        "description": "Bad input",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "Rate limited; see the Retry-After header",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/abn-validator": {
            "get": {
                "operationId": "abnValidator",
                "summary": "ABN / ACN Validator",
                "description": "Check an Australian Business Number (11 digits) or Australian Company Number (9 digits) against its official checksum. Spaces and punctuation are ignored. Checksum only, no register call; the site page for this moved into ABN Lookup (abn-lookup), which runs the same check before asking the register. This endpoint stays for scripts. Human page: https://digitalgreenhouse.com.au/tools/abn-validator",
                "tags": [
                    "Australian business"
                ],
                "parameters": [
                    {
                        "name": "number",
                        "in": "query",
                        "required": true,
                        "description": "The ABN or ACN.",
                        "schema": {
                            "type": "string",
                            "maxLength": 64
                        },
                        "example": "51824753556"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Result",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Result"
                                }
                            }
                        }
                    },
                    "400": {
                        "description": "Bad input",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "Rate limited; see the Retry-After header",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    }
                }
            },
            "post": {
                "operationId": "abnValidatorPost",
                "summary": "ABN / ACN Validator (POST body)",
                "description": "Check an Australian Business Number (11 digits) or Australian Company Number (9 digits) against its official checksum. Spaces and punctuation are ignored. Checksum only, no register call; the site page for this moved into ABN Lookup (abn-lookup), which runs the same check before asking the register. This endpoint stays for scripts.",
                "tags": [
                    "Australian business"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "number": {
                                        "type": "string",
                                        "maxLength": 64,
                                        "description": "The ABN or ACN."
                                    }
                                },
                                "required": [
                                    "number"
                                ]
                            }
                        },
                        "application/x-www-form-urlencoded": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "number": {
                                        "type": "string",
                                        "maxLength": 64,
                                        "description": "The ABN or ACN."
                                    }
                                },
                                "required": [
                                    "number"
                                ]
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Result",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Result"
                                }
                            }
                        }
                    },
                    "400": {
                        "description": "Bad input",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "Rate limited; see the Retry-After header",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/abn-lookup": {
            "get": {
                "operationId": "abnLookup",
                "summary": "ABN Lookup",
                "description": "Looks up an ABN, an ACN or a business name on the Australian Business Register (the register behind the official ABN Lookup site), using the ABR's current web methods: entity name (name parts for a sole trader), ABN status with its dates, entity type, GST registration (or when it ended), state and postcode, business names with their registration dates, deductible gift recipient (DGR), ACNC and charity status where they apply, when the record was last updated, and the full history on request. A name search returns up to 20 matching ABNs (50 on the API) with their status, active ABNs only by default, and can be limited to a state or postcode. A number that fails its check digit is answered without asking the register. \"found\": false means the register has no such ABN. One lookup per request; bulk harvesting is not allowed. Human page: https://digitalgreenhouse.com.au/tools/abn-lookup",
                "tags": [
                    "Australian business"
                ],
                "parameters": [
                    {
                        "name": "query",
                        "in": "query",
                        "required": true,
                        "description": "An ABN (11 digits), an ACN (9 digits) or a business name. Spaces and punctuation in numbers are ignored.",
                        "schema": {
                            "type": "string",
                            "maxLength": 200
                        },
                        "example": "51824753556"
                    },
                    {
                        "name": "history",
                        "in": "query",
                        "required": false,
                        "description": "true = also return previous names, locations and status changes for an ABN or ACN (the register's history).",
                        "schema": {
                            "type": "boolean",
                            "default": false
                        }
                    },
                    {
                        "name": "active",
                        "in": "query",
                        "required": false,
                        "description": "Name searches only: true = active ABNs only (the default); false = include cancelled ABNs.",
                        "schema": {
                            "type": "boolean",
                            "default": true
                        }
                    },
                    {
                        "name": "state",
                        "in": "query",
                        "required": false,
                        "description": "Name searches only: limit matches to one state or territory by the main business location.",
                        "schema": {
                            "type": "string",
                            "enum": [
                                "all",
                                "nsw",
                                "vic",
                                "qld",
                                "wa",
                                "sa",
                                "tas",
                                "act",
                                "nt"
                            ],
                            "default": "all"
                        },
                        "example": "nsw"
                    },
                    {
                        "name": "postcode",
                        "in": "query",
                        "required": false,
                        "description": "Name searches only: limit matches to a 4-digit postcode.",
                        "schema": {
                            "type": "string",
                            "maxLength": 12
                        }
                    },
                    {
                        "name": "limit",
                        "in": "query",
                        "required": false,
                        "description": "Name searches only: how many matches to return (1 to 50).",
                        "schema": {
                            "type": "integer",
                            "default": 20,
                            "minimum": 1,
                            "maximum": 50
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Result",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Result"
                                }
                            }
                        }
                    },
                    "400": {
                        "description": "Bad input",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "Rate limited; see the Retry-After header",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    }
                }
            },
            "post": {
                "operationId": "abnLookupPost",
                "summary": "ABN Lookup (POST body)",
                "description": "Looks up an ABN, an ACN or a business name on the Australian Business Register (the register behind the official ABN Lookup site), using the ABR's current web methods: entity name (name parts for a sole trader), ABN status with its dates, entity type, GST registration (or when it ended), state and postcode, business names with their registration dates, deductible gift recipient (DGR), ACNC and charity status where they apply, when the record was last updated, and the full history on request. A name search returns up to 20 matching ABNs (50 on the API) with their status, active ABNs only by default, and can be limited to a state or postcode. A number that fails its check digit is answered without asking the register. \"found\": false means the register has no such ABN. One lookup per request; bulk harvesting is not allowed.",
                "tags": [
                    "Australian business"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "query": {
                                        "type": "string",
                                        "maxLength": 200,
                                        "description": "An ABN (11 digits), an ACN (9 digits) or a business name. Spaces and punctuation in numbers are ignored."
                                    },
                                    "history": {
                                        "type": "boolean",
                                        "default": false,
                                        "description": "true = also return previous names, locations and status changes for an ABN or ACN (the register's history)."
                                    },
                                    "active": {
                                        "type": "boolean",
                                        "default": true,
                                        "description": "Name searches only: true = active ABNs only (the default); false = include cancelled ABNs."
                                    },
                                    "state": {
                                        "type": "string",
                                        "enum": [
                                            "all",
                                            "nsw",
                                            "vic",
                                            "qld",
                                            "wa",
                                            "sa",
                                            "tas",
                                            "act",
                                            "nt"
                                        ],
                                        "default": "all",
                                        "description": "Name searches only: limit matches to one state or territory by the main business location."
                                    },
                                    "postcode": {
                                        "type": "string",
                                        "maxLength": 12,
                                        "description": "Name searches only: limit matches to a 4-digit postcode."
                                    },
                                    "limit": {
                                        "type": "integer",
                                        "default": 20,
                                        "minimum": 1,
                                        "maximum": 50,
                                        "description": "Name searches only: how many matches to return (1 to 50)."
                                    }
                                },
                                "required": [
                                    "query"
                                ]
                            }
                        },
                        "application/x-www-form-urlencoded": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "query": {
                                        "type": "string",
                                        "maxLength": 200,
                                        "description": "An ABN (11 digits), an ACN (9 digits) or a business name. Spaces and punctuation in numbers are ignored."
                                    },
                                    "history": {
                                        "type": "boolean",
                                        "default": false,
                                        "description": "true = also return previous names, locations and status changes for an ABN or ACN (the register's history)."
                                    },
                                    "active": {
                                        "type": "boolean",
                                        "default": true,
                                        "description": "Name searches only: true = active ABNs only (the default); false = include cancelled ABNs."
                                    },
                                    "state": {
                                        "type": "string",
                                        "enum": [
                                            "all",
                                            "nsw",
                                            "vic",
                                            "qld",
                                            "wa",
                                            "sa",
                                            "tas",
                                            "act",
                                            "nt"
                                        ],
                                        "default": "all",
                                        "description": "Name searches only: limit matches to one state or territory by the main business location."
                                    },
                                    "postcode": {
                                        "type": "string",
                                        "maxLength": 12,
                                        "description": "Name searches only: limit matches to a 4-digit postcode."
                                    },
                                    "limit": {
                                        "type": "integer",
                                        "default": 20,
                                        "minimum": 1,
                                        "maximum": 50,
                                        "description": "Name searches only: how many matches to return (1 to 50)."
                                    }
                                },
                                "required": [
                                    "query"
                                ]
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Result",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Result"
                                }
                            }
                        }
                    },
                    "400": {
                        "description": "Bad input",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "Rate limited; see the Retry-After header",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/bsb-lookup": {
            "get": {
                "operationId": "bsbLookup",
                "summary": "BSB Lookup",
                "description": "Which Australian bank or institution issued a BSB, from its 2- or 3-digit prefix, plus whether the format is right and the state it usually belongs to (where the institution codes it in the third digit). Institution level only: no branch names or addresses. Dashes, spaces and a trailing account number are ignored. Human page: https://digitalgreenhouse.com.au/tools/bsb-lookup",
                "tags": [
                    "Australian business"
                ],
                "parameters": [
                    {
                        "name": "bsb",
                        "in": "query",
                        "required": true,
                        "description": "The BSB, e.g. 062-000.",
                        "schema": {
                            "type": "string",
                            "maxLength": 64
                        },
                        "example": "062-000"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Result",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Result"
                                }
                            }
                        }
                    },
                    "400": {
                        "description": "Bad input",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "Rate limited; see the Retry-After header",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    }
                }
            },
            "post": {
                "operationId": "bsbLookupPost",
                "summary": "BSB Lookup (POST body)",
                "description": "Which Australian bank or institution issued a BSB, from its 2- or 3-digit prefix, plus whether the format is right and the state it usually belongs to (where the institution codes it in the third digit). Institution level only: no branch names or addresses. Dashes, spaces and a trailing account number are ignored.",
                "tags": [
                    "Australian business"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "bsb": {
                                        "type": "string",
                                        "maxLength": 64,
                                        "description": "The BSB, e.g. 062-000."
                                    }
                                },
                                "required": [
                                    "bsb"
                                ]
                            }
                        },
                        "application/x-www-form-urlencoded": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "bsb": {
                                        "type": "string",
                                        "maxLength": 64,
                                        "description": "The BSB, e.g. 062-000."
                                    }
                                },
                                "required": [
                                    "bsb"
                                ]
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Result",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Result"
                                }
                            }
                        }
                    },
                    "400": {
                        "description": "Bad input",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "Rate limited; see the Retry-After header",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/invoice-due-date": {
            "get": {
                "operationId": "invoiceDueDate",
                "summary": "Invoice Due-Date Calculator (Australia)",
                "description": "The due date for an invoice from its payment terms (net days, days after end of month, a day of the following month, business days, or on receipt), moved off weekends and Australian public holidays for the chosen state or territory. Only full-day statewide public holidays count. Human page: https://digitalgreenhouse.com.au/tools/invoice-due-date",
                "tags": [
                    "Australian business"
                ],
                "parameters": [
                    {
                        "name": "date",
                        "in": "query",
                        "required": true,
                        "description": "Invoice date, YYYY-MM-DD.",
                        "schema": {
                            "type": "string"
                        },
                        "example": "2026-11-27"
                    },
                    {
                        "name": "terms",
                        "in": "query",
                        "required": false,
                        "description": "net = days after the invoice date; eom = days after the end of the invoice month; following = a day of the following month (set day); business = business days after the invoice date; receipt = due on the invoice date.",
                        "schema": {
                            "type": "string",
                            "enum": [
                                "net",
                                "eom",
                                "following",
                                "business",
                                "receipt"
                            ],
                            "default": "net"
                        },
                        "example": "net"
                    },
                    {
                        "name": "days",
                        "in": "query",
                        "required": false,
                        "description": "Number of days for net, eom and business terms.",
                        "schema": {
                            "type": "integer",
                            "default": 30,
                            "minimum": 0,
                            "maximum": 365
                        },
                        "example": "30"
                    },
                    {
                        "name": "day",
                        "in": "query",
                        "required": false,
                        "description": "Day of the following month for \"following\" terms (clamped to the month's length).",
                        "schema": {
                            "type": "integer",
                            "default": 20,
                            "minimum": 1,
                            "maximum": 31
                        }
                    },
                    {
                        "name": "state",
                        "in": "query",
                        "required": false,
                        "description": "Whose public holidays to skip: nsw, vic, qld, wa, sa, tas, act, nt, or national (only the holidays every state shares).",
                        "schema": {
                            "type": "string",
                            "enum": [
                                "nsw",
                                "vic",
                                "qld",
                                "wa",
                                "sa",
                                "tas",
                                "act",
                                "nt",
                                "national"
                            ],
                            "default": "nsw"
                        },
                        "example": "nsw"
                    },
                    {
                        "name": "roll",
                        "in": "query",
                        "required": false,
                        "description": "If the due date lands on a weekend or public holiday: move to the next business day, the previous one, or leave it.",
                        "schema": {
                            "type": "string",
                            "enum": [
                                "next",
                                "previous",
                                "none"
                            ],
                            "default": "next"
                        }
                    },
                    {
                        "name": "holidays",
                        "in": "query",
                        "required": false,
                        "description": "false = skip weekends only.",
                        "schema": {
                            "type": "boolean",
                            "default": true
                        }
                    },
                    {
                        "name": "today",
                        "in": "query",
                        "required": false,
                        "description": "Date to count \"days from today\" from, YYYY-MM-DD. Defaults to today in Australia/Sydney.",
                        "schema": {
                            "type": "string"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Result",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Result"
                                }
                            }
                        }
                    },
                    "400": {
                        "description": "Bad input",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "Rate limited; see the Retry-After header",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    }
                }
            },
            "post": {
                "operationId": "invoiceDueDatePost",
                "summary": "Invoice Due-Date Calculator (Australia) (POST body)",
                "description": "The due date for an invoice from its payment terms (net days, days after end of month, a day of the following month, business days, or on receipt), moved off weekends and Australian public holidays for the chosen state or territory. Only full-day statewide public holidays count.",
                "tags": [
                    "Australian business"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "date": {
                                        "type": "string",
                                        "description": "Invoice date, YYYY-MM-DD."
                                    },
                                    "terms": {
                                        "type": "string",
                                        "enum": [
                                            "net",
                                            "eom",
                                            "following",
                                            "business",
                                            "receipt"
                                        ],
                                        "default": "net",
                                        "description": "net = days after the invoice date; eom = days after the end of the invoice month; following = a day of the following month (set day); business = business days after the invoice date; receipt = due on the invoice date."
                                    },
                                    "days": {
                                        "type": "integer",
                                        "default": 30,
                                        "minimum": 0,
                                        "maximum": 365,
                                        "description": "Number of days for net, eom and business terms."
                                    },
                                    "day": {
                                        "type": "integer",
                                        "default": 20,
                                        "minimum": 1,
                                        "maximum": 31,
                                        "description": "Day of the following month for \"following\" terms (clamped to the month's length)."
                                    },
                                    "state": {
                                        "type": "string",
                                        "enum": [
                                            "nsw",
                                            "vic",
                                            "qld",
                                            "wa",
                                            "sa",
                                            "tas",
                                            "act",
                                            "nt",
                                            "national"
                                        ],
                                        "default": "nsw",
                                        "description": "Whose public holidays to skip: nsw, vic, qld, wa, sa, tas, act, nt, or national (only the holidays every state shares)."
                                    },
                                    "roll": {
                                        "type": "string",
                                        "enum": [
                                            "next",
                                            "previous",
                                            "none"
                                        ],
                                        "default": "next",
                                        "description": "If the due date lands on a weekend or public holiday: move to the next business day, the previous one, or leave it."
                                    },
                                    "holidays": {
                                        "type": "boolean",
                                        "default": true,
                                        "description": "false = skip weekends only."
                                    },
                                    "today": {
                                        "type": "string",
                                        "description": "Date to count \"days from today\" from, YYYY-MM-DD. Defaults to today in Australia/Sydney."
                                    }
                                },
                                "required": [
                                    "date"
                                ]
                            }
                        },
                        "application/x-www-form-urlencoded": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "date": {
                                        "type": "string",
                                        "description": "Invoice date, YYYY-MM-DD."
                                    },
                                    "terms": {
                                        "type": "string",
                                        "enum": [
                                            "net",
                                            "eom",
                                            "following",
                                            "business",
                                            "receipt"
                                        ],
                                        "default": "net",
                                        "description": "net = days after the invoice date; eom = days after the end of the invoice month; following = a day of the following month (set day); business = business days after the invoice date; receipt = due on the invoice date."
                                    },
                                    "days": {
                                        "type": "integer",
                                        "default": 30,
                                        "minimum": 0,
                                        "maximum": 365,
                                        "description": "Number of days for net, eom and business terms."
                                    },
                                    "day": {
                                        "type": "integer",
                                        "default": 20,
                                        "minimum": 1,
                                        "maximum": 31,
                                        "description": "Day of the following month for \"following\" terms (clamped to the month's length)."
                                    },
                                    "state": {
                                        "type": "string",
                                        "enum": [
                                            "nsw",
                                            "vic",
                                            "qld",
                                            "wa",
                                            "sa",
                                            "tas",
                                            "act",
                                            "nt",
                                            "national"
                                        ],
                                        "default": "nsw",
                                        "description": "Whose public holidays to skip: nsw, vic, qld, wa, sa, tas, act, nt, or national (only the holidays every state shares)."
                                    },
                                    "roll": {
                                        "type": "string",
                                        "enum": [
                                            "next",
                                            "previous",
                                            "none"
                                        ],
                                        "default": "next",
                                        "description": "If the due date lands on a weekend or public holiday: move to the next business day, the previous one, or leave it."
                                    },
                                    "holidays": {
                                        "type": "boolean",
                                        "default": true,
                                        "description": "false = skip weekends only."
                                    },
                                    "today": {
                                        "type": "string",
                                        "description": "Date to count \"days from today\" from, YYYY-MM-DD. Defaults to today in Australia/Sydney."
                                    }
                                },
                                "required": [
                                    "date"
                                ]
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Result",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Result"
                                }
                            }
                        }
                    },
                    "400": {
                        "description": "Bad input",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "Rate limited; see the Retry-After header",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/dns-lookup": {
            "get": {
                "operationId": "dnsLookup",
                "summary": "DNS Record Lookup",
                "description": "Live A, AAAA, CNAME, MX, TXT, NS, SOA and CAA records for a domain, with plain-English notes and the DNSSEC status. Resolved over DNS-over-HTTPS (Cloudflare, falling back to Google). Human page: https://digitalgreenhouse.com.au/tools/dns-lookup",
                "tags": [
                    "Domain, DNS & network"
                ],
                "parameters": [
                    {
                        "name": "domain",
                        "in": "query",
                        "required": true,
                        "description": "Domain name. A URL or email address also works; the host part is used.",
                        "schema": {
                            "type": "string",
                            "maxLength": 300
                        },
                        "example": "digitalgreenhouse.com.au"
                    },
                    {
                        "name": "type",
                        "in": "query",
                        "required": false,
                        "description": "Record type(s), comma-separated: A, AAAA, CNAME, MX, TXT, NS, SOA, CAA, or all.",
                        "schema": {
                            "type": "string",
                            "default": "all"
                        },
                        "example": "MX,TXT"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Result",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Result"
                                }
                            }
                        }
                    },
                    "400": {
                        "description": "Bad input",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "Rate limited; see the Retry-After header",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    }
                }
            },
            "post": {
                "operationId": "dnsLookupPost",
                "summary": "DNS Record Lookup (POST body)",
                "description": "Live A, AAAA, CNAME, MX, TXT, NS, SOA and CAA records for a domain, with plain-English notes and the DNSSEC status. Resolved over DNS-over-HTTPS (Cloudflare, falling back to Google).",
                "tags": [
                    "Domain, DNS & network"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "domain": {
                                        "type": "string",
                                        "maxLength": 300,
                                        "description": "Domain name. A URL or email address also works; the host part is used."
                                    },
                                    "type": {
                                        "type": "string",
                                        "default": "all",
                                        "description": "Record type(s), comma-separated: A, AAAA, CNAME, MX, TXT, NS, SOA, CAA, or all."
                                    }
                                },
                                "required": [
                                    "domain"
                                ]
                            }
                        },
                        "application/x-www-form-urlencoded": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "domain": {
                                        "type": "string",
                                        "maxLength": 300,
                                        "description": "Domain name. A URL or email address also works; the host part is used."
                                    },
                                    "type": {
                                        "type": "string",
                                        "default": "all",
                                        "description": "Record type(s), comma-separated: A, AAAA, CNAME, MX, TXT, NS, SOA, CAA, or all."
                                    }
                                },
                                "required": [
                                    "domain"
                                ]
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Result",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Result"
                                }
                            }
                        }
                    },
                    "400": {
                        "description": "Bad input",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "Rate limited; see the Retry-After header",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/whois-lookup": {
            "get": {
                "operationId": "whoisLookup",
                "summary": "WHOIS / RDAP Domain Lookup",
                "description": "Who a domain is registered with, when it was registered and expires, its status codes in plain English, nameservers and DNSSEC, straight from the registry over RDAP (the modern replacement for WHOIS). .au domains also show the registrant and eligibility the .au registry publishes. A 404-style \"registered\": false means the registry has no such domain. One domain per request; registries do not allow bulk harvesting. Human page: https://digitalgreenhouse.com.au/tools/whois-lookup",
                "tags": [
                    "Domain, DNS & network"
                ],
                "parameters": [
                    {
                        "name": "domain",
                        "in": "query",
                        "required": true,
                        "description": "Domain name. A URL, email address or subdomain also works; the registered domain is looked up.",
                        "schema": {
                            "type": "string",
                            "maxLength": 300
                        },
                        "example": "digitalgreenhouse.com.au"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Result",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Result"
                                }
                            }
                        }
                    },
                    "400": {
                        "description": "Bad input",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "Rate limited; see the Retry-After header",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    }
                }
            },
            "post": {
                "operationId": "whoisLookupPost",
                "summary": "WHOIS / RDAP Domain Lookup (POST body)",
                "description": "Who a domain is registered with, when it was registered and expires, its status codes in plain English, nameservers and DNSSEC, straight from the registry over RDAP (the modern replacement for WHOIS). .au domains also show the registrant and eligibility the .au registry publishes. A 404-style \"registered\": false means the registry has no such domain. One domain per request; registries do not allow bulk harvesting.",
                "tags": [
                    "Domain, DNS & network"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "domain": {
                                        "type": "string",
                                        "maxLength": 300,
                                        "description": "Domain name. A URL, email address or subdomain also works; the registered domain is looked up."
                                    }
                                },
                                "required": [
                                    "domain"
                                ]
                            }
                        },
                        "application/x-www-form-urlencoded": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "domain": {
                                        "type": "string",
                                        "maxLength": 300,
                                        "description": "Domain name. A URL, email address or subdomain also works; the registered domain is looked up."
                                    }
                                },
                                "required": [
                                    "domain"
                                ]
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Result",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Result"
                                }
                            }
                        }
                    },
                    "400": {
                        "description": "Bad input",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "Rate limited; see the Retry-After header",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/ssl-checker": {
            "get": {
                "operationId": "sslChecker",
                "summary": "SSL / TLS Certificate Checker",
                "description": "Connects to a host on port 443 and reports the certificate it presents: who it is for (subject and every name it covers), who issued it, valid-from and expiry dates with days left, whether it chains to a trusted root (spotting self-signed certificates and missing or expired intermediates), whether it matches the name asked for and its bare/www twin, plus the TLS version, cipher, key, signature algorithm and SHA-256 fingerprint. \"trusted\" is true only when the chain verifies, the dates are current and the name matches; \"problems\" lists anything to fix in plain English. \"chain_ok\" is null while the certificate is out of date (the chain can't be checked then). Revocation is not checked. Port 443 only; public hosts only. Human page: https://digitalgreenhouse.com.au/tools/ssl-checker",
                "tags": [
                    "Domain, DNS & network"
                ],
                "parameters": [
                    {
                        "name": "domain",
                        "in": "query",
                        "required": true,
                        "description": "Host name to check. A URL also works; its host is checked (subdomains are checked as given, not reduced to the registered domain).",
                        "schema": {
                            "type": "string",
                            "maxLength": 300
                        },
                        "example": "digitalgreenhouse.com.au"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Result",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Result"
                                }
                            }
                        }
                    },
                    "400": {
                        "description": "Bad input",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "Rate limited; see the Retry-After header",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    }
                }
            },
            "post": {
                "operationId": "sslCheckerPost",
                "summary": "SSL / TLS Certificate Checker (POST body)",
                "description": "Connects to a host on port 443 and reports the certificate it presents: who it is for (subject and every name it covers), who issued it, valid-from and expiry dates with days left, whether it chains to a trusted root (spotting self-signed certificates and missing or expired intermediates), whether it matches the name asked for and its bare/www twin, plus the TLS version, cipher, key, signature algorithm and SHA-256 fingerprint. \"trusted\" is true only when the chain verifies, the dates are current and the name matches; \"problems\" lists anything to fix in plain English. \"chain_ok\" is null while the certificate is out of date (the chain can't be checked then). Revocation is not checked. Port 443 only; public hosts only.",
                "tags": [
                    "Domain, DNS & network"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "domain": {
                                        "type": "string",
                                        "maxLength": 300,
                                        "description": "Host name to check. A URL also works; its host is checked (subdomains are checked as given, not reduced to the registered domain)."
                                    }
                                },
                                "required": [
                                    "domain"
                                ]
                            }
                        },
                        "application/x-www-form-urlencoded": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "domain": {
                                        "type": "string",
                                        "maxLength": 300,
                                        "description": "Host name to check. A URL also works; its host is checked (subdomains are checked as given, not reduced to the registered domain)."
                                    }
                                },
                                "required": [
                                    "domain"
                                ]
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Result",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Result"
                                }
                            }
                        }
                    },
                    "400": {
                        "description": "Bad input",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "Rate limited; see the Retry-After header",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/mx-email-check": {
            "get": {
                "operationId": "mxEmailCheck",
                "summary": "MX & Email Setup Check",
                "description": "Checks a domain's email setup: MX servers (and whether they resolve), SPF (following every include and counting DNS lookups against the limit of 10), DKIM under 23 common selectors (or yours) with RSA key length, and DMARC policy. Returns a verdict and a plain-English list of what to fix, with copy-paste records. Human page: https://digitalgreenhouse.com.au/tools/mx-email-check",
                "tags": [
                    "Domain, DNS & network"
                ],
                "parameters": [
                    {
                        "name": "domain",
                        "in": "query",
                        "required": true,
                        "description": "Domain name. A URL or email address also works.",
                        "schema": {
                            "type": "string",
                            "maxLength": 300
                        },
                        "example": "digitalgreenhouse.com.au"
                    },
                    {
                        "name": "selector",
                        "in": "query",
                        "required": false,
                        "description": "Optional DKIM selector to check as well as the common ones (the s= value in a DKIM-Signature header).",
                        "schema": {
                            "type": "string",
                            "maxLength": 140
                        },
                        "example": "selector1"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Result",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Result"
                                }
                            }
                        }
                    },
                    "400": {
                        "description": "Bad input",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "Rate limited; see the Retry-After header",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    }
                }
            },
            "post": {
                "operationId": "mxEmailCheckPost",
                "summary": "MX & Email Setup Check (POST body)",
                "description": "Checks a domain's email setup: MX servers (and whether they resolve), SPF (following every include and counting DNS lookups against the limit of 10), DKIM under 23 common selectors (or yours) with RSA key length, and DMARC policy. Returns a verdict and a plain-English list of what to fix, with copy-paste records.",
                "tags": [
                    "Domain, DNS & network"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "domain": {
                                        "type": "string",
                                        "maxLength": 300,
                                        "description": "Domain name. A URL or email address also works."
                                    },
                                    "selector": {
                                        "type": "string",
                                        "maxLength": 140,
                                        "description": "Optional DKIM selector to check as well as the common ones (the s= value in a DKIM-Signature header)."
                                    }
                                },
                                "required": [
                                    "domain"
                                ]
                            }
                        },
                        "application/x-www-form-urlencoded": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "domain": {
                                        "type": "string",
                                        "maxLength": 300,
                                        "description": "Domain name. A URL or email address also works."
                                    },
                                    "selector": {
                                        "type": "string",
                                        "maxLength": 140,
                                        "description": "Optional DKIM selector to check as well as the common ones (the s= value in a DKIM-Signature header)."
                                    }
                                },
                                "required": [
                                    "domain"
                                ]
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Result",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Result"
                                }
                            }
                        }
                    },
                    "400": {
                        "description": "Bad input",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "Rate limited; see the Retry-After header",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/subnet-calculator": {
            "get": {
                "operationId": "subnetCalculator",
                "summary": "Subnet / CIDR Calculator",
                "description": "Network, broadcast, netmask, wildcard, host range and usable host count for an IPv4 CIDR block. Human page: https://digitalgreenhouse.com.au/tools/subnet-calculator",
                "tags": [
                    "Domain, DNS & network"
                ],
                "parameters": [
                    {
                        "name": "cidr",
                        "in": "query",
                        "required": true,
                        "description": "IPv4 address with prefix length.",
                        "schema": {
                            "type": "string",
                            "maxLength": 40
                        },
                        "example": "192.168.10.37/26"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Result",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Result"
                                }
                            }
                        }
                    },
                    "400": {
                        "description": "Bad input",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "Rate limited; see the Retry-After header",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    }
                }
            },
            "post": {
                "operationId": "subnetCalculatorPost",
                "summary": "Subnet / CIDR Calculator (POST body)",
                "description": "Network, broadcast, netmask, wildcard, host range and usable host count for an IPv4 CIDR block.",
                "tags": [
                    "Domain, DNS & network"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "cidr": {
                                        "type": "string",
                                        "maxLength": 40,
                                        "description": "IPv4 address with prefix length."
                                    }
                                },
                                "required": [
                                    "cidr"
                                ]
                            }
                        },
                        "application/x-www-form-urlencoded": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "cidr": {
                                        "type": "string",
                                        "maxLength": 40,
                                        "description": "IPv4 address with prefix length."
                                    }
                                },
                                "required": [
                                    "cidr"
                                ]
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Result",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Result"
                                }
                            }
                        }
                    },
                    "400": {
                        "description": "Bad input",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "Rate limited; see the Retry-After header",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/whats-my-ip": {
            "get": {
                "operationId": "whatsMyIp",
                "summary": "What's My IP",
                "description": "The public IP address the request came from, and its reverse DNS name. Called by an agent, this is the agent's own server address. Human page: https://digitalgreenhouse.com.au/tools/whats-my-ip",
                "tags": [
                    "Domain, DNS & network"
                ],
                "parameters": [],
                "responses": {
                    "200": {
                        "description": "Result",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Result"
                                }
                            }
                        }
                    },
                    "400": {
                        "description": "Bad input",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "Rate limited; see the Retry-After header",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    }
                }
            },
            "post": {
                "operationId": "whatsMyIpPost",
                "summary": "What's My IP (POST body)",
                "description": "The public IP address the request came from, and its reverse DNS name. Called by an agent, this is the agent's own server address.",
                "tags": [
                    "Domain, DNS & network"
                ],
                "requestBody": {
                    "required": false,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "properties": {}
                            }
                        },
                        "application/x-www-form-urlencoded": {
                            "schema": {
                                "type": "object",
                                "properties": {}
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Result",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Result"
                                }
                            }
                        }
                    },
                    "400": {
                        "description": "Bad input",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "Rate limited; see the Retry-After header",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/website-health-check": {
            "get": {
                "operationId": "websiteHealthCheck",
                "summary": "Website Health Check",
                "description": "A scored report card for one web page: HTTPS and the certificate, whether http redirects to https, the redirect chain, security headers, mixed content, server response time from Australia, HTML size and compression, render-blocking files, title, meta description, H1, canonical, mobile viewport, language, Open Graph, structured data, image alt text, favicon, noindex, robots.txt and the XML sitemap. Each check is pass, warn or fail with a plain-English fix; the score is 0-100 with a grade A-F. Only public websites on ports 80 and 443 can be checked, and a check takes up to about 25 seconds. Human page: https://digitalgreenhouse.com.au/tools/website-health-check",
                "tags": [
                    "Web & SEO"
                ],
                "parameters": [
                    {
                        "name": "url",
                        "in": "query",
                        "required": true,
                        "description": "Web address of the page to check. A bare domain checks its home page over HTTPS.",
                        "schema": {
                            "type": "string",
                            "maxLength": 2000
                        },
                        "example": "digitalgreenhouse.com.au"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Result",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Result"
                                }
                            }
                        }
                    },
                    "400": {
                        "description": "Bad input",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "Rate limited; see the Retry-After header",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    }
                }
            },
            "post": {
                "operationId": "websiteHealthCheckPost",
                "summary": "Website Health Check (POST body)",
                "description": "A scored report card for one web page: HTTPS and the certificate, whether http redirects to https, the redirect chain, security headers, mixed content, server response time from Australia, HTML size and compression, render-blocking files, title, meta description, H1, canonical, mobile viewport, language, Open Graph, structured data, image alt text, favicon, noindex, robots.txt and the XML sitemap. Each check is pass, warn or fail with a plain-English fix; the score is 0-100 with a grade A-F. Only public websites on ports 80 and 443 can be checked, and a check takes up to about 25 seconds.",
                "tags": [
                    "Web & SEO"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "url": {
                                        "type": "string",
                                        "maxLength": 2000,
                                        "description": "Web address of the page to check. A bare domain checks its home page over HTTPS."
                                    }
                                },
                                "required": [
                                    "url"
                                ]
                            }
                        },
                        "application/x-www-form-urlencoded": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "url": {
                                        "type": "string",
                                        "maxLength": 2000,
                                        "description": "Web address of the page to check. A bare domain checks its home page over HTTPS."
                                    }
                                },
                                "required": [
                                    "url"
                                ]
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Result",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Result"
                                }
                            }
                        }
                    },
                    "400": {
                        "description": "Bad input",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "Rate limited; see the Retry-After header",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/percentage-calculator": {
            "get": {
                "operationId": "percentageCalculator",
                "summary": "Percentage Calculator",
                "description": "From two numbers x and y: x% of y, x as a percentage of y, and the percentage change from x to y. Human page: https://digitalgreenhouse.com.au/tools/percentage-calculator",
                "tags": [
                    "Everyday & calculators"
                ],
                "parameters": [
                    {
                        "name": "x",
                        "in": "query",
                        "required": true,
                        "description": "First number.",
                        "schema": {
                            "type": "number"
                        },
                        "example": "15"
                    },
                    {
                        "name": "y",
                        "in": "query",
                        "required": true,
                        "description": "Second number.",
                        "schema": {
                            "type": "number"
                        },
                        "example": "80"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Result",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Result"
                                }
                            }
                        }
                    },
                    "400": {
                        "description": "Bad input",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "Rate limited; see the Retry-After header",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    }
                }
            },
            "post": {
                "operationId": "percentageCalculatorPost",
                "summary": "Percentage Calculator (POST body)",
                "description": "From two numbers x and y: x% of y, x as a percentage of y, and the percentage change from x to y.",
                "tags": [
                    "Everyday & calculators"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "x": {
                                        "type": "number",
                                        "description": "First number."
                                    },
                                    "y": {
                                        "type": "number",
                                        "description": "Second number."
                                    }
                                },
                                "required": [
                                    "x",
                                    "y"
                                ]
                            }
                        },
                        "application/x-www-form-urlencoded": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "x": {
                                        "type": "number",
                                        "description": "First number."
                                    },
                                    "y": {
                                        "type": "number",
                                        "description": "Second number."
                                    }
                                },
                                "required": [
                                    "x",
                                    "y"
                                ]
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Result",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Result"
                                }
                            }
                        }
                    },
                    "400": {
                        "description": "Bad input",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "Rate limited; see the Retry-After header",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/discount-calculator": {
            "get": {
                "operationId": "discountCalculator",
                "summary": "Discount / Sale Price",
                "description": "Sale price and saving after a percentage discount, with an optional stacked \"extra % off\". Human page: https://digitalgreenhouse.com.au/tools/discount-calculator",
                "tags": [
                    "Everyday & calculators"
                ],
                "parameters": [
                    {
                        "name": "price",
                        "in": "query",
                        "required": true,
                        "description": "Original price.",
                        "schema": {
                            "type": "number",
                            "minimum": 0
                        },
                        "example": "249.95"
                    },
                    {
                        "name": "discount",
                        "in": "query",
                        "required": true,
                        "description": "Percentage off.",
                        "schema": {
                            "type": "number",
                            "minimum": 0,
                            "maximum": 100
                        },
                        "example": "30"
                    },
                    {
                        "name": "extra",
                        "in": "query",
                        "required": false,
                        "description": "Optional further percentage off the already-reduced price.",
                        "schema": {
                            "type": "number",
                            "minimum": 0,
                            "maximum": 100
                        },
                        "example": "10"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Result",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Result"
                                }
                            }
                        }
                    },
                    "400": {
                        "description": "Bad input",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "Rate limited; see the Retry-After header",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    }
                }
            },
            "post": {
                "operationId": "discountCalculatorPost",
                "summary": "Discount / Sale Price (POST body)",
                "description": "Sale price and saving after a percentage discount, with an optional stacked \"extra % off\".",
                "tags": [
                    "Everyday & calculators"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "price": {
                                        "type": "number",
                                        "minimum": 0,
                                        "description": "Original price."
                                    },
                                    "discount": {
                                        "type": "number",
                                        "minimum": 0,
                                        "maximum": 100,
                                        "description": "Percentage off."
                                    },
                                    "extra": {
                                        "type": "number",
                                        "minimum": 0,
                                        "maximum": 100,
                                        "description": "Optional further percentage off the already-reduced price."
                                    }
                                },
                                "required": [
                                    "price",
                                    "discount"
                                ]
                            }
                        },
                        "application/x-www-form-urlencoded": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "price": {
                                        "type": "number",
                                        "minimum": 0,
                                        "description": "Original price."
                                    },
                                    "discount": {
                                        "type": "number",
                                        "minimum": 0,
                                        "maximum": 100,
                                        "description": "Percentage off."
                                    },
                                    "extra": {
                                        "type": "number",
                                        "minimum": 0,
                                        "maximum": 100,
                                        "description": "Optional further percentage off the already-reduced price."
                                    }
                                },
                                "required": [
                                    "price",
                                    "discount"
                                ]
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Result",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Result"
                                }
                            }
                        }
                    },
                    "400": {
                        "description": "Bad input",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "Rate limited; see the Retry-After header",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/loan-calculator": {
            "get": {
                "operationId": "loanCalculator",
                "summary": "Loan Repayment Calculator",
                "description": "Monthly repayment, total repaid and total interest for a fixed-rate loan (standard amortisation, monthly compounding). Human page: https://digitalgreenhouse.com.au/tools/loan-calculator",
                "tags": [
                    "Everyday & calculators"
                ],
                "parameters": [
                    {
                        "name": "amount",
                        "in": "query",
                        "required": true,
                        "description": "Amount borrowed.",
                        "schema": {
                            "type": "number",
                            "minimum": 0.01
                        },
                        "example": "35000"
                    },
                    {
                        "name": "rate",
                        "in": "query",
                        "required": true,
                        "description": "Annual interest rate in percent.",
                        "schema": {
                            "type": "number",
                            "minimum": 0,
                            "maximum": 100
                        },
                        "example": "8.5"
                    },
                    {
                        "name": "years",
                        "in": "query",
                        "required": true,
                        "description": "Loan term in years (decimals allowed).",
                        "schema": {
                            "type": "number",
                            "minimum": 0.08,
                            "maximum": 50
                        },
                        "example": "5"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Result",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Result"
                                }
                            }
                        }
                    },
                    "400": {
                        "description": "Bad input",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "Rate limited; see the Retry-After header",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    }
                }
            },
            "post": {
                "operationId": "loanCalculatorPost",
                "summary": "Loan Repayment Calculator (POST body)",
                "description": "Monthly repayment, total repaid and total interest for a fixed-rate loan (standard amortisation, monthly compounding).",
                "tags": [
                    "Everyday & calculators"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "amount": {
                                        "type": "number",
                                        "minimum": 0.01,
                                        "description": "Amount borrowed."
                                    },
                                    "rate": {
                                        "type": "number",
                                        "minimum": 0,
                                        "maximum": 100,
                                        "description": "Annual interest rate in percent."
                                    },
                                    "years": {
                                        "type": "number",
                                        "minimum": 0.08,
                                        "maximum": 50,
                                        "description": "Loan term in years (decimals allowed)."
                                    }
                                },
                                "required": [
                                    "amount",
                                    "rate",
                                    "years"
                                ]
                            }
                        },
                        "application/x-www-form-urlencoded": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "amount": {
                                        "type": "number",
                                        "minimum": 0.01,
                                        "description": "Amount borrowed."
                                    },
                                    "rate": {
                                        "type": "number",
                                        "minimum": 0,
                                        "maximum": 100,
                                        "description": "Annual interest rate in percent."
                                    },
                                    "years": {
                                        "type": "number",
                                        "minimum": 0.08,
                                        "maximum": 50,
                                        "description": "Loan term in years (decimals allowed)."
                                    }
                                },
                                "required": [
                                    "amount",
                                    "rate",
                                    "years"
                                ]
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Result",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Result"
                                }
                            }
                        }
                    },
                    "400": {
                        "description": "Bad input",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "Rate limited; see the Retry-After header",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/bill-splitter": {
            "get": {
                "operationId": "billSplitter",
                "summary": "Bill Splitter & Tip",
                "description": "Split a bill between people, with an optional tip percentage. Each share is rounded up to the cent. Human page: https://digitalgreenhouse.com.au/tools/bill-splitter",
                "tags": [
                    "Everyday & calculators"
                ],
                "parameters": [
                    {
                        "name": "total",
                        "in": "query",
                        "required": true,
                        "description": "Bill total.",
                        "schema": {
                            "type": "number",
                            "minimum": 0
                        },
                        "example": "187.40"
                    },
                    {
                        "name": "people",
                        "in": "query",
                        "required": true,
                        "description": "Number of people.",
                        "schema": {
                            "type": "integer",
                            "minimum": 1,
                            "maximum": 1000
                        },
                        "example": "4"
                    },
                    {
                        "name": "tip",
                        "in": "query",
                        "required": false,
                        "description": "Tip percentage.",
                        "schema": {
                            "type": "number",
                            "default": 0,
                            "minimum": 0,
                            "maximum": 100
                        },
                        "example": "10"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Result",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Result"
                                }
                            }
                        }
                    },
                    "400": {
                        "description": "Bad input",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "Rate limited; see the Retry-After header",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    }
                }
            },
            "post": {
                "operationId": "billSplitterPost",
                "summary": "Bill Splitter & Tip (POST body)",
                "description": "Split a bill between people, with an optional tip percentage. Each share is rounded up to the cent.",
                "tags": [
                    "Everyday & calculators"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "total": {
                                        "type": "number",
                                        "minimum": 0,
                                        "description": "Bill total."
                                    },
                                    "people": {
                                        "type": "integer",
                                        "minimum": 1,
                                        "maximum": 1000,
                                        "description": "Number of people."
                                    },
                                    "tip": {
                                        "type": "number",
                                        "default": 0,
                                        "minimum": 0,
                                        "maximum": 100,
                                        "description": "Tip percentage."
                                    }
                                },
                                "required": [
                                    "total",
                                    "people"
                                ]
                            }
                        },
                        "application/x-www-form-urlencoded": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "total": {
                                        "type": "number",
                                        "minimum": 0,
                                        "description": "Bill total."
                                    },
                                    "people": {
                                        "type": "integer",
                                        "minimum": 1,
                                        "maximum": 1000,
                                        "description": "Number of people."
                                    },
                                    "tip": {
                                        "type": "number",
                                        "default": 0,
                                        "minimum": 0,
                                        "maximum": 100,
                                        "description": "Tip percentage."
                                    }
                                },
                                "required": [
                                    "total",
                                    "people"
                                ]
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Result",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Result"
                                }
                            }
                        }
                    },
                    "400": {
                        "description": "Bad input",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "Rate limited; see the Retry-After header",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/bmi-calculator": {
            "get": {
                "operationId": "bmiCalculator",
                "summary": "BMI Calculator",
                "description": "Body Mass Index and its standard category, from metric or imperial measurements. Screening number only, not medical advice. Human page: https://digitalgreenhouse.com.au/tools/bmi-calculator",
                "tags": [
                    "Everyday & calculators"
                ],
                "parameters": [
                    {
                        "name": "weight_kg",
                        "in": "query",
                        "required": false,
                        "description": "Weight in kilograms (metric).",
                        "schema": {
                            "type": "number",
                            "minimum": 0
                        },
                        "example": "72"
                    },
                    {
                        "name": "height_cm",
                        "in": "query",
                        "required": false,
                        "description": "Height in centimetres (metric).",
                        "schema": {
                            "type": "number",
                            "minimum": 0
                        },
                        "example": "178"
                    },
                    {
                        "name": "weight_lb",
                        "in": "query",
                        "required": false,
                        "description": "Weight in pounds (imperial).",
                        "schema": {
                            "type": "number",
                            "minimum": 0
                        }
                    },
                    {
                        "name": "height_ft",
                        "in": "query",
                        "required": false,
                        "description": "Height, feet part (imperial).",
                        "schema": {
                            "type": "number",
                            "minimum": 0
                        }
                    },
                    {
                        "name": "height_in",
                        "in": "query",
                        "required": false,
                        "description": "Height, inches part (imperial).",
                        "schema": {
                            "type": "number",
                            "minimum": 0
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Result",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Result"
                                }
                            }
                        }
                    },
                    "400": {
                        "description": "Bad input",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "Rate limited; see the Retry-After header",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    }
                }
            },
            "post": {
                "operationId": "bmiCalculatorPost",
                "summary": "BMI Calculator (POST body)",
                "description": "Body Mass Index and its standard category, from metric or imperial measurements. Screening number only, not medical advice.",
                "tags": [
                    "Everyday & calculators"
                ],
                "requestBody": {
                    "required": false,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "weight_kg": {
                                        "type": "number",
                                        "minimum": 0,
                                        "description": "Weight in kilograms (metric)."
                                    },
                                    "height_cm": {
                                        "type": "number",
                                        "minimum": 0,
                                        "description": "Height in centimetres (metric)."
                                    },
                                    "weight_lb": {
                                        "type": "number",
                                        "minimum": 0,
                                        "description": "Weight in pounds (imperial)."
                                    },
                                    "height_ft": {
                                        "type": "number",
                                        "minimum": 0,
                                        "description": "Height, feet part (imperial)."
                                    },
                                    "height_in": {
                                        "type": "number",
                                        "minimum": 0,
                                        "description": "Height, inches part (imperial)."
                                    }
                                }
                            }
                        },
                        "application/x-www-form-urlencoded": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "weight_kg": {
                                        "type": "number",
                                        "minimum": 0,
                                        "description": "Weight in kilograms (metric)."
                                    },
                                    "height_cm": {
                                        "type": "number",
                                        "minimum": 0,
                                        "description": "Height in centimetres (metric)."
                                    },
                                    "weight_lb": {
                                        "type": "number",
                                        "minimum": 0,
                                        "description": "Weight in pounds (imperial)."
                                    },
                                    "height_ft": {
                                        "type": "number",
                                        "minimum": 0,
                                        "description": "Height, feet part (imperial)."
                                    },
                                    "height_in": {
                                        "type": "number",
                                        "minimum": 0,
                                        "description": "Height, inches part (imperial)."
                                    }
                                }
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Result",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Result"
                                }
                            }
                        }
                    },
                    "400": {
                        "description": "Bad input",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "Rate limited; see the Retry-After header",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/age-calculator": {
            "get": {
                "operationId": "ageCalculator",
                "summary": "Age Calculator",
                "description": "Exact age in years, months and days on a date (default today in Sydney), plus totals and days until the next birthday. Also works as a date-difference calculator. Human page: https://digitalgreenhouse.com.au/tools/age-calculator",
                "tags": [
                    "Everyday & calculators"
                ],
                "parameters": [
                    {
                        "name": "dob",
                        "in": "query",
                        "required": true,
                        "description": "Date of birth (or start date), YYYY-MM-DD.",
                        "schema": {
                            "type": "string"
                        },
                        "example": "1990-02-28"
                    },
                    {
                        "name": "on",
                        "in": "query",
                        "required": false,
                        "description": "Date to measure to, YYYY-MM-DD. Defaults to today in Australia/Sydney.",
                        "schema": {
                            "type": "string"
                        },
                        "example": "2026-10-02"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Result",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Result"
                                }
                            }
                        }
                    },
                    "400": {
                        "description": "Bad input",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "Rate limited; see the Retry-After header",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    }
                }
            },
            "post": {
                "operationId": "ageCalculatorPost",
                "summary": "Age Calculator (POST body)",
                "description": "Exact age in years, months and days on a date (default today in Sydney), plus totals and days until the next birthday. Also works as a date-difference calculator.",
                "tags": [
                    "Everyday & calculators"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "dob": {
                                        "type": "string",
                                        "description": "Date of birth (or start date), YYYY-MM-DD."
                                    },
                                    "on": {
                                        "type": "string",
                                        "description": "Date to measure to, YYYY-MM-DD. Defaults to today in Australia/Sydney."
                                    }
                                },
                                "required": [
                                    "dob"
                                ]
                            }
                        },
                        "application/x-www-form-urlencoded": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "dob": {
                                        "type": "string",
                                        "description": "Date of birth (or start date), YYYY-MM-DD."
                                    },
                                    "on": {
                                        "type": "string",
                                        "description": "Date to measure to, YYYY-MM-DD. Defaults to today in Australia/Sydney."
                                    }
                                },
                                "required": [
                                    "dob"
                                ]
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Result",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Result"
                                }
                            }
                        }
                    },
                    "400": {
                        "description": "Bad input",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "Rate limited; see the Retry-After header",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/unit-converter": {
            "get": {
                "operationId": "unitConverter",
                "summary": "Unit Converter",
                "description": "Convert length, weight, volume (US measures), area, speed and temperature. Units: m km cm mm mi yd ft in · kg g mg t lb oz st · L mL gal qt pt cup floz · m2 km2 ha ft2 acre · m/s km/h mph kn · C F K (common names like \"pounds\" or \"celsius\" also work). Human page: https://digitalgreenhouse.com.au/tools/unit-converter",
                "tags": [
                    "Everyday & calculators"
                ],
                "parameters": [
                    {
                        "name": "value",
                        "in": "query",
                        "required": true,
                        "description": "The number to convert.",
                        "schema": {
                            "type": "number"
                        },
                        "example": "26.2"
                    },
                    {
                        "name": "from",
                        "in": "query",
                        "required": true,
                        "description": "Unit to convert from.",
                        "schema": {
                            "type": "string"
                        },
                        "example": "mi"
                    },
                    {
                        "name": "to",
                        "in": "query",
                        "required": true,
                        "description": "Unit to convert to.",
                        "schema": {
                            "type": "string"
                        },
                        "example": "km"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Result",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Result"
                                }
                            }
                        }
                    },
                    "400": {
                        "description": "Bad input",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "Rate limited; see the Retry-After header",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    }
                }
            },
            "post": {
                "operationId": "unitConverterPost",
                "summary": "Unit Converter (POST body)",
                "description": "Convert length, weight, volume (US measures), area, speed and temperature. Units: m km cm mm mi yd ft in · kg g mg t lb oz st · L mL gal qt pt cup floz · m2 km2 ha ft2 acre · m/s km/h mph kn · C F K (common names like \"pounds\" or \"celsius\" also work).",
                "tags": [
                    "Everyday & calculators"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "value": {
                                        "type": "number",
                                        "description": "The number to convert."
                                    },
                                    "from": {
                                        "type": "string",
                                        "description": "Unit to convert from."
                                    },
                                    "to": {
                                        "type": "string",
                                        "description": "Unit to convert to."
                                    }
                                },
                                "required": [
                                    "value",
                                    "from",
                                    "to"
                                ]
                            }
                        },
                        "application/x-www-form-urlencoded": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "value": {
                                        "type": "number",
                                        "description": "The number to convert."
                                    },
                                    "from": {
                                        "type": "string",
                                        "description": "Unit to convert from."
                                    },
                                    "to": {
                                        "type": "string",
                                        "description": "Unit to convert to."
                                    }
                                },
                                "required": [
                                    "value",
                                    "from",
                                    "to"
                                ]
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Result",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Result"
                                }
                            }
                        }
                    },
                    "400": {
                        "description": "Bad input",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "Rate limited; see the Retry-After header",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/epoch-converter": {
            "get": {
                "operationId": "epochConverter",
                "summary": "Unix Timestamp Converter",
                "description": "Convert a Unix timestamp (seconds or milliseconds) to UTC, ISO 8601 and Sydney time (AEST/AEDT), or a date to a timestamp. With neither, returns the current time. Human page: https://digitalgreenhouse.com.au/tools/epoch-converter",
                "tags": [
                    "Encoders & converters"
                ],
                "parameters": [
                    {
                        "name": "timestamp",
                        "in": "query",
                        "required": false,
                        "description": "Unix timestamp in seconds or milliseconds.",
                        "schema": {
                            "type": "string",
                            "maxLength": 40
                        },
                        "example": "1759363200"
                    },
                    {
                        "name": "unit",
                        "in": "query",
                        "required": false,
                        "description": "auto treats 13+ digits as milliseconds.",
                        "schema": {
                            "type": "string",
                            "enum": [
                                "auto",
                                "s",
                                "ms"
                            ],
                            "default": "auto"
                        }
                    },
                    {
                        "name": "date",
                        "in": "query",
                        "required": false,
                        "description": "A date/time to convert to a timestamp, ideally ISO 8601 (2026-10-02T09:30:00+10:00). Without an offset it is read in tz.",
                        "schema": {
                            "type": "string",
                            "maxLength": 100
                        }
                    },
                    {
                        "name": "tz",
                        "in": "query",
                        "required": false,
                        "description": "IANA time zone for reading \"date\" and for an extra local-time view, e.g. Australia/Perth.",
                        "schema": {
                            "type": "string",
                            "default": "Australia/Sydney",
                            "maxLength": 64
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Result",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Result"
                                }
                            }
                        }
                    },
                    "400": {
                        "description": "Bad input",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "Rate limited; see the Retry-After header",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    }
                }
            },
            "post": {
                "operationId": "epochConverterPost",
                "summary": "Unix Timestamp Converter (POST body)",
                "description": "Convert a Unix timestamp (seconds or milliseconds) to UTC, ISO 8601 and Sydney time (AEST/AEDT), or a date to a timestamp. With neither, returns the current time.",
                "tags": [
                    "Encoders & converters"
                ],
                "requestBody": {
                    "required": false,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "timestamp": {
                                        "type": "string",
                                        "maxLength": 40,
                                        "description": "Unix timestamp in seconds or milliseconds."
                                    },
                                    "unit": {
                                        "type": "string",
                                        "enum": [
                                            "auto",
                                            "s",
                                            "ms"
                                        ],
                                        "default": "auto",
                                        "description": "auto treats 13+ digits as milliseconds."
                                    },
                                    "date": {
                                        "type": "string",
                                        "maxLength": 100,
                                        "description": "A date/time to convert to a timestamp, ideally ISO 8601 (2026-10-02T09:30:00+10:00). Without an offset it is read in tz."
                                    },
                                    "tz": {
                                        "type": "string",
                                        "default": "Australia/Sydney",
                                        "maxLength": 64,
                                        "description": "IANA time zone for reading \"date\" and for an extra local-time view, e.g. Australia/Perth."
                                    }
                                }
                            }
                        },
                        "application/x-www-form-urlencoded": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "timestamp": {
                                        "type": "string",
                                        "maxLength": 40,
                                        "description": "Unix timestamp in seconds or milliseconds."
                                    },
                                    "unit": {
                                        "type": "string",
                                        "enum": [
                                            "auto",
                                            "s",
                                            "ms"
                                        ],
                                        "default": "auto",
                                        "description": "auto treats 13+ digits as milliseconds."
                                    },
                                    "date": {
                                        "type": "string",
                                        "maxLength": 100,
                                        "description": "A date/time to convert to a timestamp, ideally ISO 8601 (2026-10-02T09:30:00+10:00). Without an offset it is read in tz."
                                    },
                                    "tz": {
                                        "type": "string",
                                        "default": "Australia/Sydney",
                                        "maxLength": 64,
                                        "description": "IANA time zone for reading \"date\" and for an extra local-time view, e.g. Australia/Perth."
                                    }
                                }
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Result",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Result"
                                }
                            }
                        }
                    },
                    "400": {
                        "description": "Bad input",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "Rate limited; see the Retry-After header",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/base64": {
            "get": {
                "operationId": "base64",
                "summary": "Base64 Encode / Decode",
                "description": "Encode UTF-8 text to Base64, or decode Base64 (standard or URL-safe) back to text. Binary results come back as hex. Human page: https://digitalgreenhouse.com.au/tools/base64",
                "tags": [
                    "Encoders & converters"
                ],
                "parameters": [
                    {
                        "name": "text",
                        "in": "query",
                        "required": true,
                        "description": "Text to encode, or Base64 to decode.",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "mode",
                        "in": "query",
                        "required": false,
                        "description": "encode or decode.",
                        "schema": {
                            "type": "string",
                            "enum": [
                                "encode",
                                "decode"
                            ],
                            "default": "encode"
                        }
                    },
                    {
                        "name": "urlsafe",
                        "in": "query",
                        "required": false,
                        "description": "Use the URL-safe alphabet (- and _, no padding).",
                        "schema": {
                            "type": "boolean",
                            "default": false
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Result",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Result"
                                }
                            }
                        }
                    },
                    "400": {
                        "description": "Bad input",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "Rate limited; see the Retry-After header",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    }
                }
            },
            "post": {
                "operationId": "base64Post",
                "summary": "Base64 Encode / Decode (POST body)",
                "description": "Encode UTF-8 text to Base64, or decode Base64 (standard or URL-safe) back to text. Binary results come back as hex.",
                "tags": [
                    "Encoders & converters"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "text": {
                                        "type": "string",
                                        "description": "Text to encode, or Base64 to decode."
                                    },
                                    "mode": {
                                        "type": "string",
                                        "enum": [
                                            "encode",
                                            "decode"
                                        ],
                                        "default": "encode",
                                        "description": "encode or decode."
                                    },
                                    "urlsafe": {
                                        "type": "boolean",
                                        "default": false,
                                        "description": "Use the URL-safe alphabet (- and _, no padding)."
                                    }
                                },
                                "required": [
                                    "text"
                                ]
                            }
                        },
                        "application/x-www-form-urlencoded": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "text": {
                                        "type": "string",
                                        "description": "Text to encode, or Base64 to decode."
                                    },
                                    "mode": {
                                        "type": "string",
                                        "enum": [
                                            "encode",
                                            "decode"
                                        ],
                                        "default": "encode",
                                        "description": "encode or decode."
                                    },
                                    "urlsafe": {
                                        "type": "boolean",
                                        "default": false,
                                        "description": "Use the URL-safe alphabet (- and _, no padding)."
                                    }
                                },
                                "required": [
                                    "text"
                                ]
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Result",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Result"
                                }
                            }
                        }
                    },
                    "400": {
                        "description": "Bad input",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "Rate limited; see the Retry-After header",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/url-encode": {
            "get": {
                "operationId": "urlEncode",
                "summary": "URL Encode / Decode",
                "description": "Percent-encode or decode text with exactly the rules of JavaScript's encodeURIComponent/decodeURIComponent (scope=component) or encodeURI/decodeURI (scope=full). Human page: https://digitalgreenhouse.com.au/tools/url-encode",
                "tags": [
                    "Encoders & converters"
                ],
                "parameters": [
                    {
                        "name": "text",
                        "in": "query",
                        "required": true,
                        "description": "Text to encode or decode.",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "mode",
                        "in": "query",
                        "required": false,
                        "description": "encode or decode.",
                        "schema": {
                            "type": "string",
                            "enum": [
                                "encode",
                                "decode"
                            ],
                            "default": "encode"
                        }
                    },
                    {
                        "name": "scope",
                        "in": "query",
                        "required": false,
                        "description": "component = one query value or path segment; full = a whole URL.",
                        "schema": {
                            "type": "string",
                            "enum": [
                                "component",
                                "full"
                            ],
                            "default": "component"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Result",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Result"
                                }
                            }
                        }
                    },
                    "400": {
                        "description": "Bad input",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "Rate limited; see the Retry-After header",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    }
                }
            },
            "post": {
                "operationId": "urlEncodePost",
                "summary": "URL Encode / Decode (POST body)",
                "description": "Percent-encode or decode text with exactly the rules of JavaScript's encodeURIComponent/decodeURIComponent (scope=component) or encodeURI/decodeURI (scope=full).",
                "tags": [
                    "Encoders & converters"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "text": {
                                        "type": "string",
                                        "description": "Text to encode or decode."
                                    },
                                    "mode": {
                                        "type": "string",
                                        "enum": [
                                            "encode",
                                            "decode"
                                        ],
                                        "default": "encode",
                                        "description": "encode or decode."
                                    },
                                    "scope": {
                                        "type": "string",
                                        "enum": [
                                            "component",
                                            "full"
                                        ],
                                        "default": "component",
                                        "description": "component = one query value or path segment; full = a whole URL."
                                    }
                                },
                                "required": [
                                    "text"
                                ]
                            }
                        },
                        "application/x-www-form-urlencoded": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "text": {
                                        "type": "string",
                                        "description": "Text to encode or decode."
                                    },
                                    "mode": {
                                        "type": "string",
                                        "enum": [
                                            "encode",
                                            "decode"
                                        ],
                                        "default": "encode",
                                        "description": "encode or decode."
                                    },
                                    "scope": {
                                        "type": "string",
                                        "enum": [
                                            "component",
                                            "full"
                                        ],
                                        "default": "component",
                                        "description": "component = one query value or path segment; full = a whole URL."
                                    }
                                },
                                "required": [
                                    "text"
                                ]
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Result",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Result"
                                }
                            }
                        }
                    },
                    "400": {
                        "description": "Bad input",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "Rate limited; see the Retry-After header",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/html-entity": {
            "get": {
                "operationId": "htmlEntity",
                "summary": "HTML Entity Encoder",
                "description": "Escape & < > \" ' as HTML entities (optionally every non-ASCII character too), or decode entities back to text. Human page: https://digitalgreenhouse.com.au/tools/html-entity",
                "tags": [
                    "Encoders & converters"
                ],
                "parameters": [
                    {
                        "name": "text",
                        "in": "query",
                        "required": true,
                        "description": "Text to encode, or HTML with entities to decode.",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "mode",
                        "in": "query",
                        "required": false,
                        "description": "encode or decode.",
                        "schema": {
                            "type": "string",
                            "enum": [
                                "encode",
                                "decode"
                            ],
                            "default": "encode"
                        }
                    },
                    {
                        "name": "all",
                        "in": "query",
                        "required": false,
                        "description": "When encoding, also turn non-ASCII characters into numeric entities.",
                        "schema": {
                            "type": "boolean",
                            "default": false
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Result",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Result"
                                }
                            }
                        }
                    },
                    "400": {
                        "description": "Bad input",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "Rate limited; see the Retry-After header",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    }
                }
            },
            "post": {
                "operationId": "htmlEntityPost",
                "summary": "HTML Entity Encoder (POST body)",
                "description": "Escape & < > \" ' as HTML entities (optionally every non-ASCII character too), or decode entities back to text.",
                "tags": [
                    "Encoders & converters"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "text": {
                                        "type": "string",
                                        "description": "Text to encode, or HTML with entities to decode."
                                    },
                                    "mode": {
                                        "type": "string",
                                        "enum": [
                                            "encode",
                                            "decode"
                                        ],
                                        "default": "encode",
                                        "description": "encode or decode."
                                    },
                                    "all": {
                                        "type": "boolean",
                                        "default": false,
                                        "description": "When encoding, also turn non-ASCII characters into numeric entities."
                                    }
                                },
                                "required": [
                                    "text"
                                ]
                            }
                        },
                        "application/x-www-form-urlencoded": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "text": {
                                        "type": "string",
                                        "description": "Text to encode, or HTML with entities to decode."
                                    },
                                    "mode": {
                                        "type": "string",
                                        "enum": [
                                            "encode",
                                            "decode"
                                        ],
                                        "default": "encode",
                                        "description": "encode or decode."
                                    },
                                    "all": {
                                        "type": "boolean",
                                        "default": false,
                                        "description": "When encoding, also turn non-ASCII characters into numeric entities."
                                    }
                                },
                                "required": [
                                    "text"
                                ]
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Result",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Result"
                                }
                            }
                        }
                    },
                    "400": {
                        "description": "Bad input",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "Rate limited; see the Retry-After header",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/morse-code": {
            "get": {
                "operationId": "morseCode",
                "summary": "Morse Code Translator",
                "description": "Translate text to International Morse code (ITU-R M.1677-1) or Morse back to text, with how long it takes to send at a given speed. Morse output separates letters with a space and words with \" / \"; input also accepts | or three spaces between words, and · − for dots and dashes. Prosigns go in angle brackets, e.g. <SOS>. Human page: https://digitalgreenhouse.com.au/tools/morse-code",
                "tags": [
                    "Encoders & converters"
                ],
                "parameters": [
                    {
                        "name": "text",
                        "in": "query",
                        "required": true,
                        "description": "Text to encode, or Morse code to decode.",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "mode",
                        "in": "query",
                        "required": false,
                        "description": "auto decodes when the input is only dots, dashes and separators, and encodes anything else.",
                        "schema": {
                            "type": "string",
                            "enum": [
                                "auto",
                                "encode",
                                "decode"
                            ],
                            "default": "auto"
                        }
                    },
                    {
                        "name": "wpm",
                        "in": "query",
                        "required": false,
                        "description": "Character speed in words per minute (PARIS standard), used for the timing.",
                        "schema": {
                            "type": "integer",
                            "default": 20,
                            "minimum": 5,
                            "maximum": 60
                        }
                    },
                    {
                        "name": "farnsworth",
                        "in": "query",
                        "required": false,
                        "description": "Optional slower overall speed in wpm: letters stay at wpm and the gaps stretch (Farnsworth spacing).",
                        "schema": {
                            "type": "integer",
                            "minimum": 3,
                            "maximum": 60
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Result",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Result"
                                }
                            }
                        }
                    },
                    "400": {
                        "description": "Bad input",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "Rate limited; see the Retry-After header",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    }
                }
            },
            "post": {
                "operationId": "morseCodePost",
                "summary": "Morse Code Translator (POST body)",
                "description": "Translate text to International Morse code (ITU-R M.1677-1) or Morse back to text, with how long it takes to send at a given speed. Morse output separates letters with a space and words with \" / \"; input also accepts | or three spaces between words, and · − for dots and dashes. Prosigns go in angle brackets, e.g. <SOS>.",
                "tags": [
                    "Encoders & converters"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "text": {
                                        "type": "string",
                                        "description": "Text to encode, or Morse code to decode."
                                    },
                                    "mode": {
                                        "type": "string",
                                        "enum": [
                                            "auto",
                                            "encode",
                                            "decode"
                                        ],
                                        "default": "auto",
                                        "description": "auto decodes when the input is only dots, dashes and separators, and encodes anything else."
                                    },
                                    "wpm": {
                                        "type": "integer",
                                        "default": 20,
                                        "minimum": 5,
                                        "maximum": 60,
                                        "description": "Character speed in words per minute (PARIS standard), used for the timing."
                                    },
                                    "farnsworth": {
                                        "type": "integer",
                                        "minimum": 3,
                                        "maximum": 60,
                                        "description": "Optional slower overall speed in wpm: letters stay at wpm and the gaps stretch (Farnsworth spacing)."
                                    }
                                },
                                "required": [
                                    "text"
                                ]
                            }
                        },
                        "application/x-www-form-urlencoded": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "text": {
                                        "type": "string",
                                        "description": "Text to encode, or Morse code to decode."
                                    },
                                    "mode": {
                                        "type": "string",
                                        "enum": [
                                            "auto",
                                            "encode",
                                            "decode"
                                        ],
                                        "default": "auto",
                                        "description": "auto decodes when the input is only dots, dashes and separators, and encodes anything else."
                                    },
                                    "wpm": {
                                        "type": "integer",
                                        "default": 20,
                                        "minimum": 5,
                                        "maximum": 60,
                                        "description": "Character speed in words per minute (PARIS standard), used for the timing."
                                    },
                                    "farnsworth": {
                                        "type": "integer",
                                        "minimum": 3,
                                        "maximum": 60,
                                        "description": "Optional slower overall speed in wpm: letters stay at wpm and the gaps stretch (Farnsworth spacing)."
                                    }
                                },
                                "required": [
                                    "text"
                                ]
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Result",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Result"
                                }
                            }
                        }
                    },
                    "400": {
                        "description": "Bad input",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "Rate limited; see the Retry-After header",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/slugify": {
            "get": {
                "operationId": "slugify",
                "summary": "Slugify (URL Slug)",
                "description": "Turn a title into a clean URL slug: accents stripped, anything that is not a letter or digit becomes the separator. Human page: https://digitalgreenhouse.com.au/tools/slugify",
                "tags": [
                    "Encoders & converters"
                ],
                "parameters": [
                    {
                        "name": "text",
                        "in": "query",
                        "required": true,
                        "description": "The title or text.",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "separator",
                        "in": "query",
                        "required": false,
                        "description": "Hyphen or underscore.",
                        "schema": {
                            "type": "string",
                            "enum": [
                                "-",
                                "_"
                            ],
                            "default": "-"
                        }
                    },
                    {
                        "name": "lowercase",
                        "in": "query",
                        "required": false,
                        "description": "Lower-case the slug.",
                        "schema": {
                            "type": "boolean",
                            "default": true
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Result",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Result"
                                }
                            }
                        }
                    },
                    "400": {
                        "description": "Bad input",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "Rate limited; see the Retry-After header",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    }
                }
            },
            "post": {
                "operationId": "slugifyPost",
                "summary": "Slugify (URL Slug) (POST body)",
                "description": "Turn a title into a clean URL slug: accents stripped, anything that is not a letter or digit becomes the separator.",
                "tags": [
                    "Encoders & converters"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "text": {
                                        "type": "string",
                                        "description": "The title or text."
                                    },
                                    "separator": {
                                        "type": "string",
                                        "enum": [
                                            "-",
                                            "_"
                                        ],
                                        "default": "-",
                                        "description": "Hyphen or underscore."
                                    },
                                    "lowercase": {
                                        "type": "boolean",
                                        "default": true,
                                        "description": "Lower-case the slug."
                                    }
                                },
                                "required": [
                                    "text"
                                ]
                            }
                        },
                        "application/x-www-form-urlencoded": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "text": {
                                        "type": "string",
                                        "description": "The title or text."
                                    },
                                    "separator": {
                                        "type": "string",
                                        "enum": [
                                            "-",
                                            "_"
                                        ],
                                        "default": "-",
                                        "description": "Hyphen or underscore."
                                    },
                                    "lowercase": {
                                        "type": "boolean",
                                        "default": true,
                                        "description": "Lower-case the slug."
                                    }
                                },
                                "required": [
                                    "text"
                                ]
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Result",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Result"
                                }
                            }
                        }
                    },
                    "400": {
                        "description": "Bad input",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "Rate limited; see the Retry-After header",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/text-case-converter": {
            "get": {
                "operationId": "textCaseConverter",
                "summary": "Text Case Converter",
                "description": "Convert text to lowercase, UPPERCASE, Title Case, Sentence case, camelCase, PascalCase, snake_case, kebab-case or CONSTANT_CASE. Splits words on spaces, - _ and camel humps. Human page: https://digitalgreenhouse.com.au/tools/text-case-converter",
                "tags": [
                    "Encoders & converters"
                ],
                "parameters": [
                    {
                        "name": "text",
                        "in": "query",
                        "required": true,
                        "description": "The text.",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "case",
                        "in": "query",
                        "required": false,
                        "description": "One case, or all of them.",
                        "schema": {
                            "type": "string",
                            "enum": [
                                "all",
                                "lower",
                                "upper",
                                "title",
                                "sentence",
                                "camel",
                                "pascal",
                                "snake",
                                "kebab",
                                "constant"
                            ],
                            "default": "all"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Result",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Result"
                                }
                            }
                        }
                    },
                    "400": {
                        "description": "Bad input",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "Rate limited; see the Retry-After header",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    }
                }
            },
            "post": {
                "operationId": "textCaseConverterPost",
                "summary": "Text Case Converter (POST body)",
                "description": "Convert text to lowercase, UPPERCASE, Title Case, Sentence case, camelCase, PascalCase, snake_case, kebab-case or CONSTANT_CASE. Splits words on spaces, - _ and camel humps.",
                "tags": [
                    "Encoders & converters"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "text": {
                                        "type": "string",
                                        "description": "The text."
                                    },
                                    "case": {
                                        "type": "string",
                                        "enum": [
                                            "all",
                                            "lower",
                                            "upper",
                                            "title",
                                            "sentence",
                                            "camel",
                                            "pascal",
                                            "snake",
                                            "kebab",
                                            "constant"
                                        ],
                                        "default": "all",
                                        "description": "One case, or all of them."
                                    }
                                },
                                "required": [
                                    "text"
                                ]
                            }
                        },
                        "application/x-www-form-urlencoded": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "text": {
                                        "type": "string",
                                        "description": "The text."
                                    },
                                    "case": {
                                        "type": "string",
                                        "enum": [
                                            "all",
                                            "lower",
                                            "upper",
                                            "title",
                                            "sentence",
                                            "camel",
                                            "pascal",
                                            "snake",
                                            "kebab",
                                            "constant"
                                        ],
                                        "default": "all",
                                        "description": "One case, or all of them."
                                    }
                                },
                                "required": [
                                    "text"
                                ]
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Result",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Result"
                                }
                            }
                        }
                    },
                    "400": {
                        "description": "Bad input",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "Rate limited; see the Retry-After header",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/json-formatter": {
            "get": {
                "operationId": "jsonFormatter",
                "summary": "JSON Formatter & Validator",
                "description": "Validate JSON and point to the first error by line and column, or pretty-print / minify it. Send large documents as a POST body. Human page: https://digitalgreenhouse.com.au/tools/json-formatter",
                "tags": [
                    "Encoders & converters"
                ],
                "parameters": [
                    {
                        "name": "text",
                        "in": "query",
                        "required": true,
                        "description": "The JSON text.",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "mode",
                        "in": "query",
                        "required": false,
                        "description": "validate only, or also return formatted/minified output.",
                        "schema": {
                            "type": "string",
                            "enum": [
                                "validate",
                                "format",
                                "minify"
                            ],
                            "default": "validate"
                        }
                    },
                    {
                        "name": "indent",
                        "in": "query",
                        "required": false,
                        "description": "Indent for mode=format.",
                        "schema": {
                            "type": "string",
                            "enum": [
                                "2",
                                "4",
                                "tab"
                            ],
                            "default": "2"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Result",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Result"
                                }
                            }
                        }
                    },
                    "400": {
                        "description": "Bad input",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "Rate limited; see the Retry-After header",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    }
                }
            },
            "post": {
                "operationId": "jsonFormatterPost",
                "summary": "JSON Formatter & Validator (POST body)",
                "description": "Validate JSON and point to the first error by line and column, or pretty-print / minify it. Send large documents as a POST body.",
                "tags": [
                    "Encoders & converters"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "text": {
                                        "type": "string",
                                        "description": "The JSON text."
                                    },
                                    "mode": {
                                        "type": "string",
                                        "enum": [
                                            "validate",
                                            "format",
                                            "minify"
                                        ],
                                        "default": "validate",
                                        "description": "validate only, or also return formatted/minified output."
                                    },
                                    "indent": {
                                        "type": "string",
                                        "enum": [
                                            "2",
                                            "4",
                                            "tab"
                                        ],
                                        "default": "2",
                                        "description": "Indent for mode=format."
                                    }
                                },
                                "required": [
                                    "text"
                                ]
                            }
                        },
                        "application/x-www-form-urlencoded": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "text": {
                                        "type": "string",
                                        "description": "The JSON text."
                                    },
                                    "mode": {
                                        "type": "string",
                                        "enum": [
                                            "validate",
                                            "format",
                                            "minify"
                                        ],
                                        "default": "validate",
                                        "description": "validate only, or also return formatted/minified output."
                                    },
                                    "indent": {
                                        "type": "string",
                                        "enum": [
                                            "2",
                                            "4",
                                            "tab"
                                        ],
                                        "default": "2",
                                        "description": "Indent for mode=format."
                                    }
                                },
                                "required": [
                                    "text"
                                ]
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Result",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Result"
                                }
                            }
                        }
                    },
                    "400": {
                        "description": "Bad input",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "Rate limited; see the Retry-After header",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/jwt-decoder": {
            "post": {
                "operationId": "jwtDecoder",
                "summary": "JWT Decoder",
                "description": "Decode a JSON Web Token's header and payload and report expiry (exp), not-before (nbf) and issued-at (iat). The signature is NOT verified. POST only, so tokens never appear in URLs or server logs.",
                "tags": [
                    "Encoders & converters"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "token": {
                                        "type": "string",
                                        "maxLength": 16384,
                                        "description": "The JWT (header.payload.signature)."
                                    }
                                },
                                "required": [
                                    "token"
                                ]
                            }
                        },
                        "application/x-www-form-urlencoded": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "token": {
                                        "type": "string",
                                        "maxLength": 16384,
                                        "description": "The JWT (header.payload.signature)."
                                    }
                                },
                                "required": [
                                    "token"
                                ]
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Result",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Result"
                                }
                            }
                        }
                    },
                    "400": {
                        "description": "Bad input",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "Rate limited; see the Retry-After header",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/hash-generator": {
            "get": {
                "operationId": "hashGenerator",
                "summary": "Hash Generator",
                "description": "MD5, SHA-1, SHA-256, SHA-384 and SHA-512 of text (as UTF-8 bytes) or of hex/Base64 bytes, with an optional check against an expected hash. Use POST for anything sensitive. Human page: https://digitalgreenhouse.com.au/tools/hash-generator",
                "tags": [
                    "Encoders & converters"
                ],
                "parameters": [
                    {
                        "name": "text",
                        "in": "query",
                        "required": true,
                        "description": "The input.",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "algorithm",
                        "in": "query",
                        "required": false,
                        "description": "One algorithm, or all.",
                        "schema": {
                            "type": "string",
                            "enum": [
                                "all",
                                "md5",
                                "sha1",
                                "sha256",
                                "sha384",
                                "sha512"
                            ],
                            "default": "all"
                        }
                    },
                    {
                        "name": "input_encoding",
                        "in": "query",
                        "required": false,
                        "description": "How \"text\" is encoded: text = UTF-8 string; hex or base64 = raw bytes.",
                        "schema": {
                            "type": "string",
                            "enum": [
                                "text",
                                "hex",
                                "base64"
                            ],
                            "default": "text"
                        }
                    },
                    {
                        "name": "expect",
                        "in": "query",
                        "required": false,
                        "description": "Optional expected hash (hex) to compare against.",
                        "schema": {
                            "type": "string",
                            "maxLength": 200
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Result",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Result"
                                }
                            }
                        }
                    },
                    "400": {
                        "description": "Bad input",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "Rate limited; see the Retry-After header",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    }
                }
            },
            "post": {
                "operationId": "hashGeneratorPost",
                "summary": "Hash Generator (POST body)",
                "description": "MD5, SHA-1, SHA-256, SHA-384 and SHA-512 of text (as UTF-8 bytes) or of hex/Base64 bytes, with an optional check against an expected hash. Use POST for anything sensitive.",
                "tags": [
                    "Encoders & converters"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "text": {
                                        "type": "string",
                                        "description": "The input."
                                    },
                                    "algorithm": {
                                        "type": "string",
                                        "enum": [
                                            "all",
                                            "md5",
                                            "sha1",
                                            "sha256",
                                            "sha384",
                                            "sha512"
                                        ],
                                        "default": "all",
                                        "description": "One algorithm, or all."
                                    },
                                    "input_encoding": {
                                        "type": "string",
                                        "enum": [
                                            "text",
                                            "hex",
                                            "base64"
                                        ],
                                        "default": "text",
                                        "description": "How \"text\" is encoded: text = UTF-8 string; hex or base64 = raw bytes."
                                    },
                                    "expect": {
                                        "type": "string",
                                        "maxLength": 200,
                                        "description": "Optional expected hash (hex) to compare against."
                                    }
                                },
                                "required": [
                                    "text"
                                ]
                            }
                        },
                        "application/x-www-form-urlencoded": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "text": {
                                        "type": "string",
                                        "description": "The input."
                                    },
                                    "algorithm": {
                                        "type": "string",
                                        "enum": [
                                            "all",
                                            "md5",
                                            "sha1",
                                            "sha256",
                                            "sha384",
                                            "sha512"
                                        ],
                                        "default": "all",
                                        "description": "One algorithm, or all."
                                    },
                                    "input_encoding": {
                                        "type": "string",
                                        "enum": [
                                            "text",
                                            "hex",
                                            "base64"
                                        ],
                                        "default": "text",
                                        "description": "How \"text\" is encoded: text = UTF-8 string; hex or base64 = raw bytes."
                                    },
                                    "expect": {
                                        "type": "string",
                                        "maxLength": 200,
                                        "description": "Optional expected hash (hex) to compare against."
                                    }
                                },
                                "required": [
                                    "text"
                                ]
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Result",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Result"
                                }
                            }
                        }
                    },
                    "400": {
                        "description": "Bad input",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "Rate limited; see the Retry-After header",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/uuid-generator": {
            "get": {
                "operationId": "uuidGenerator",
                "summary": "UUID / ULID Generator",
                "description": "Generate random UUID v4, time-ordered UUID v7, or ULIDs, up to 100 at a time. Human page: https://digitalgreenhouse.com.au/tools/uuid-generator",
                "tags": [
                    "Encoders & converters"
                ],
                "parameters": [
                    {
                        "name": "version",
                        "in": "query",
                        "required": false,
                        "description": "v4, v7 or ulid.",
                        "schema": {
                            "type": "string",
                            "enum": [
                                "v4",
                                "v7",
                                "ulid"
                            ],
                            "default": "v4"
                        }
                    },
                    {
                        "name": "count",
                        "in": "query",
                        "required": false,
                        "description": "How many.",
                        "schema": {
                            "type": "integer",
                            "default": 1,
                            "minimum": 1,
                            "maximum": 100
                        }
                    },
                    {
                        "name": "uppercase",
                        "in": "query",
                        "required": false,
                        "description": "Upper-case UUIDs (ULIDs are always upper-case).",
                        "schema": {
                            "type": "boolean",
                            "default": false
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Result",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Result"
                                }
                            }
                        }
                    },
                    "400": {
                        "description": "Bad input",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "Rate limited; see the Retry-After header",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    }
                }
            },
            "post": {
                "operationId": "uuidGeneratorPost",
                "summary": "UUID / ULID Generator (POST body)",
                "description": "Generate random UUID v4, time-ordered UUID v7, or ULIDs, up to 100 at a time.",
                "tags": [
                    "Encoders & converters"
                ],
                "requestBody": {
                    "required": false,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "version": {
                                        "type": "string",
                                        "enum": [
                                            "v4",
                                            "v7",
                                            "ulid"
                                        ],
                                        "default": "v4",
                                        "description": "v4, v7 or ulid."
                                    },
                                    "count": {
                                        "type": "integer",
                                        "default": 1,
                                        "minimum": 1,
                                        "maximum": 100,
                                        "description": "How many."
                                    },
                                    "uppercase": {
                                        "type": "boolean",
                                        "default": false,
                                        "description": "Upper-case UUIDs (ULIDs are always upper-case)."
                                    }
                                }
                            }
                        },
                        "application/x-www-form-urlencoded": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "version": {
                                        "type": "string",
                                        "enum": [
                                            "v4",
                                            "v7",
                                            "ulid"
                                        ],
                                        "default": "v4",
                                        "description": "v4, v7 or ulid."
                                    },
                                    "count": {
                                        "type": "integer",
                                        "default": 1,
                                        "minimum": 1,
                                        "maximum": 100,
                                        "description": "How many."
                                    },
                                    "uppercase": {
                                        "type": "boolean",
                                        "default": false,
                                        "description": "Upper-case UUIDs (ULIDs are always upper-case)."
                                    }
                                }
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Result",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Result"
                                }
                            }
                        }
                    },
                    "400": {
                        "description": "Bad input",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "Rate limited; see the Retry-After header",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/word-counter": {
            "get": {
                "operationId": "wordCounter",
                "summary": "Word & Character Counter",
                "description": "Words, characters (with and without spaces), UTF-8 bytes, sentences, paragraphs, and reading/speaking time. Send long text as a POST body. Human page: https://digitalgreenhouse.com.au/tools/word-counter",
                "tags": [
                    "Text & generators"
                ],
                "parameters": [
                    {
                        "name": "text",
                        "in": "query",
                        "required": true,
                        "description": "The text to count.",
                        "schema": {
                            "type": "string"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Result",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Result"
                                }
                            }
                        }
                    },
                    "400": {
                        "description": "Bad input",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "Rate limited; see the Retry-After header",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    }
                }
            },
            "post": {
                "operationId": "wordCounterPost",
                "summary": "Word & Character Counter (POST body)",
                "description": "Words, characters (with and without spaces), UTF-8 bytes, sentences, paragraphs, and reading/speaking time. Send long text as a POST body.",
                "tags": [
                    "Text & generators"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "text": {
                                        "type": "string",
                                        "description": "The text to count."
                                    }
                                },
                                "required": [
                                    "text"
                                ]
                            }
                        },
                        "application/x-www-form-urlencoded": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "text": {
                                        "type": "string",
                                        "description": "The text to count."
                                    }
                                },
                                "required": [
                                    "text"
                                ]
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Result",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Result"
                                }
                            }
                        }
                    },
                    "400": {
                        "description": "Bad input",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "Rate limited; see the Retry-After header",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/color-converter": {
            "get": {
                "operationId": "colorConverter",
                "summary": "Colour Converter",
                "description": "Convert a colour between HEX, RGB and HSL. Human page: https://digitalgreenhouse.com.au/tools/color-converter",
                "tags": [
                    "Design & colour"
                ],
                "parameters": [
                    {
                        "name": "color",
                        "in": "query",
                        "required": true,
                        "description": "HEX (#0E5C3A or 0E5C3A or #abc), rgb(14, 92, 58) or hsl(155, 74%, 21%).",
                        "schema": {
                            "type": "string",
                            "maxLength": 64
                        },
                        "example": "#0E5C3A"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Result",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Result"
                                }
                            }
                        }
                    },
                    "400": {
                        "description": "Bad input",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "Rate limited; see the Retry-After header",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    }
                }
            },
            "post": {
                "operationId": "colorConverterPost",
                "summary": "Colour Converter (POST body)",
                "description": "Convert a colour between HEX, RGB and HSL.",
                "tags": [
                    "Design & colour"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "color": {
                                        "type": "string",
                                        "maxLength": 64,
                                        "description": "HEX (#0E5C3A or 0E5C3A or #abc), rgb(14, 92, 58) or hsl(155, 74%, 21%)."
                                    }
                                },
                                "required": [
                                    "color"
                                ]
                            }
                        },
                        "application/x-www-form-urlencoded": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "color": {
                                        "type": "string",
                                        "maxLength": 64,
                                        "description": "HEX (#0E5C3A or 0E5C3A or #abc), rgb(14, 92, 58) or hsl(155, 74%, 21%)."
                                    }
                                },
                                "required": [
                                    "color"
                                ]
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Result",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Result"
                                }
                            }
                        }
                    },
                    "400": {
                        "description": "Bad input",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "Rate limited; see the Retry-After header",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/contrast-checker": {
            "get": {
                "operationId": "contrastChecker",
                "summary": "WCAG Contrast Checker",
                "description": "Contrast ratio between a text colour and a background colour, with pass/fail for WCAG 2.x AA and AAA (normal text, large text, UI components). Human page: https://digitalgreenhouse.com.au/tools/contrast-checker",
                "tags": [
                    "Design & colour"
                ],
                "parameters": [
                    {
                        "name": "fg",
                        "in": "query",
                        "required": true,
                        "description": "Text (foreground) colour: HEX, rgb() or hsl().",
                        "schema": {
                            "type": "string",
                            "maxLength": 64
                        },
                        "example": "#767676"
                    },
                    {
                        "name": "bg",
                        "in": "query",
                        "required": true,
                        "description": "Background colour: HEX, rgb() or hsl().",
                        "schema": {
                            "type": "string",
                            "maxLength": 64
                        },
                        "example": "#FFFFFF"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Result",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Result"
                                }
                            }
                        }
                    },
                    "400": {
                        "description": "Bad input",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "Rate limited; see the Retry-After header",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    }
                }
            },
            "post": {
                "operationId": "contrastCheckerPost",
                "summary": "WCAG Contrast Checker (POST body)",
                "description": "Contrast ratio between a text colour and a background colour, with pass/fail for WCAG 2.x AA and AAA (normal text, large text, UI components).",
                "tags": [
                    "Design & colour"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "fg": {
                                        "type": "string",
                                        "maxLength": 64,
                                        "description": "Text (foreground) colour: HEX, rgb() or hsl()."
                                    },
                                    "bg": {
                                        "type": "string",
                                        "maxLength": 64,
                                        "description": "Background colour: HEX, rgb() or hsl()."
                                    }
                                },
                                "required": [
                                    "fg",
                                    "bg"
                                ]
                            }
                        },
                        "application/x-www-form-urlencoded": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "fg": {
                                        "type": "string",
                                        "maxLength": 64,
                                        "description": "Text (foreground) colour: HEX, rgb() or hsl()."
                                    },
                                    "bg": {
                                        "type": "string",
                                        "maxLength": 64,
                                        "description": "Background colour: HEX, rgb() or hsl()."
                                    }
                                },
                                "required": [
                                    "fg",
                                    "bg"
                                ]
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Result",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Result"
                                }
                            }
                        }
                    },
                    "400": {
                        "description": "Bad input",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "Rate limited; see the Retry-After header",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    }
                }
            }
        }
    },
    "components": {
        "schemas": {
            "Result": {
                "type": "object",
                "properties": {
                    "ok": {
                        "type": "boolean",
                        "const": true
                    },
                    "tool": {
                        "type": "string"
                    },
                    "input": {
                        "type": "object",
                        "description": "The parameters as understood, after defaults."
                    },
                    "result": {
                        "type": "object",
                        "description": "Tool-specific result fields."
                    },
                    "summary": {
                        "type": "string",
                        "description": "One plain-English sentence describing the result."
                    },
                    "notes": {
                        "type": "array",
                        "items": {
                            "type": "string"
                        }
                    },
                    "page": {
                        "type": "string",
                        "format": "uri",
                        "description": "The human tool page."
                    }
                }
            },
            "Error": {
                "type": "object",
                "properties": {
                    "ok": {
                        "type": "boolean",
                        "const": false
                    },
                    "tool": {
                        "type": "string"
                    },
                    "error": {
                        "type": "object",
                        "properties": {
                            "code": {
                                "type": "string"
                            },
                            "message": {
                                "type": "string"
                            },
                            "param": {
                                "type": [
                                    "string",
                                    "null"
                                ]
                            }
                        }
                    },
                    "usage": {
                        "type": "string"
                    }
                }
            }
        }
    }
}
