{
    "openapi": "3.1.0",
    "info": {
        "title": "Silly Development Panel API",
        "version": "1",
        "summary": "Control your Silly Development servers, files, deploys and databases from code.",
        "description": "The panel API does from code what you can do in the Silly Development panel: start and\nstop servers, send console commands, manage files and backups, deploy from Git, create\nfree servers and databases, and order paid servers.\n\nEvery request needs an API key, sent as a bearer token. Create one in the panel under\nAccount, API keys. A key can be limited to some servers, some permissions, some IP\naddresses and some account scopes, and it can be given an expiry date.\n\nRequests and responses are JSON unless an endpoint says otherwise. Each client may make\n768 requests a minute, and some endpoints have tighter limits, listed on each one.\n",
        "contact": {
            "name": "Silly Development",
            "url": "https://sillydev.co.uk/contact"
        },
        "license": {
            "name": "Proprietary",
            "identifier": "LicenseRef-Proprietary"
        },
        "x-stability": "This is version 1 of the API. Anything we plan to remove or change in a way that breaks existing code is announced on the changelog at least 90 days ahead."
    },
    "servers": [
        {
            "url": "https://sillydev.co.uk/panel/api/client",
            "description": "Silly Development"
        }
    ],
    "security": [
        {
            "apiKey": []
        }
    ],
    "tags": [
        {
            "name": "Servers",
            "description": "List the servers your key can reach, read one server's details, resource use and activity, and delete a server you own."
        },
        {
            "name": "Power and console",
            "description": "Start, stop, restart and kill a server, send console commands, share console output, and get a token for the live console websocket."
        },
        {
            "name": "Startup",
            "description": "The startup command and the startup variables a server runs with."
        },
        {
            "name": "Settings",
            "description": "Rename a server, reinstall it, and change the Docker image it runs on."
        },
        {
            "name": "Files",
            "description": "Browse and change the files of a server. The panel passes each request on to the node\n(Wings) that runs the server, so errors the node reports, such as a missing file\n(404), a file on the egg's denylist (403) or not enough disk space (400), come back\nwith the node's message in `detail`. If the node cannot be reached the panel answers\n504, and a node error answers 500 or 502.\n\nPaths are relative to the server's root directory, which is `/`. A path cannot leave\nit: anything that resolves outside the root is answered as not found.\n\nDownloads and uploads do not go through the panel. You ask the panel for a signed URL\non the node, then download from it or upload to it directly. Each signed URL works\nonce and expires 15 minutes after it is made.\n\nWhile a server is installing, suspended, being transferred, restoring a backup or\nbeing deleted, every endpoint here answers 409.\n"
        },
        {
            "name": "Backups",
            "description": "Make, download, restore, lock and delete backups of a server's files. A server may\nkeep as many backups as its backup limit (`feature_limits.backups` on the server)\nallows; failed backups do not count towards it. A server with a limit of 0 cannot\nmake backups.\n\nA backup is in progress while `completed_at` is null. Once it finishes,\n`is_successful` says whether it worked. Watch the server's websocket or poll\n`getBackup` to see when it is done.\n\nWhile a server is installing, suspended, being transferred, restoring a backup or\nbeing deleted, every endpoint here answers 409.\n"
        },
        {
            "name": "Schedules",
            "description": "Schedules run a list of tasks (console commands, power actions and backups) on a cron timetable. Each schedule's tasks run in order, each one waiting its `time_offset` after the one before."
        },
        {
            "name": "Network",
            "description": "The IP address and port pairs (allocations) assigned to a server. Bots rarely need more than the one they were created with, and adding ports only works where an administrator has switched it on."
        },
        {
            "name": "Subusers",
            "description": "Other accounts given access to a server, each with its own set of permissions. Call `GET /permissions` (`listPermissions`) for every permission there is and what each one allows."
        },
        {
            "name": "Git deploys",
            "description": "Deploy a GitHub or GitLab repository, or any public https Git URL, into a server's files, by hand or on every push. Connecting a GitHub account (installing the Silly Development GitHub App) or a GitLab account can only be done in the panel in a browser, under the server's GitHub tab or your account settings; the API can then use those connections but cannot make them. Only the server's owner can link, deploy or change anything, and only with an API key that is not limited to a set of permissions. Subusers with `git.read` can see what is linked and how deployments went."
        },
        {
            "name": "Account",
            "description": "The account the API key belongs to. A key can only read the account (scope `account.read`); everything that changes it, such as the email address, password, two-factor, API keys and SSH keys, needs a browser session and is not part of the public API."
        },
        {
            "name": "Server creation",
            "description": "Create free servers for the account. Only available while self-service creation is switched on and at least one runtime is configured; otherwise these endpoints return 404."
        },
        {
            "name": "Databases",
            "description": "Free MariaDB and Postgres databases that belong to the account rather than to one of its servers. Only available while the feature is switched on; otherwise every endpoint here returns 404."
        },
        {
            "name": "Billing",
            "description": "Paid servers. Only available while billing is switched on and a plan is on sale (and, while the panel is on test keys or soft-launching, only to administrators); otherwise every endpoint here returns 404. Anything that spends money, refunds it or changes a plan needs the `billing.purchase` scope, which no key has unless its owner turned it on. Managing an existing plan also returns 404 to an account that has never started a checkout. Prices are in pence (the smallest unit of the currency)."
        }
    ],
    "paths": {
        "/": {
            "get": {
                "operationId": "listServers",
                "tags": [
                    "Servers"
                ],
                "summary": "List servers",
                "description": "Lists the servers the key's user owns or is a subuser of, 50 a page by default and at most 100. A key limited to some servers only lists those. The default includes `allocations` and `variables` are always present, and `egg` and `subusers` can be added with `include`. If the account can buy paid servers, `meta.pending_orders` lists paid servers that have been bought but do not exist yet.",
                "parameters": [
                    {
                        "$ref": "#/components/parameters/Page"
                    },
                    {
                        "name": "per_page",
                        "in": "query",
                        "required": false,
                        "description": "How many servers to return on each page. Values above 100 are treated as 100.",
                        "schema": {
                            "type": "integer",
                            "minimum": 1,
                            "maximum": 100,
                            "default": 50
                        }
                    },
                    {
                        "name": "type",
                        "in": "query",
                        "required": false,
                        "description": "Which servers to list. Leave it out for every server you own or are a subuser of; `owner` lists only the servers you own. `admin` (servers you can reach only as an administrator) and `admin-all` (every server) are for administrators: anyone else gets an empty list, and a key limited to some servers or permissions ignores them.",
                        "schema": {
                            "type": "string",
                            "enum": [
                                "owner",
                                "admin",
                                "admin-all"
                            ]
                        }
                    },
                    {
                        "name": "filter[*]",
                        "in": "query",
                        "required": false,
                        "description": "A general search. An IPv4 address, `ip:port` or `:port` matches the server's allocations; anything else matches the start of the UUID, the 8-character identifier, the external ID, or part of the name (case-insensitive).",
                        "schema": {
                            "type": "string"
                        },
                        "example": "discord"
                    },
                    {
                        "name": "filter[uuid]",
                        "in": "query",
                        "required": false,
                        "description": "Servers whose UUID contains this text.",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "filter[name]",
                        "in": "query",
                        "required": false,
                        "description": "Servers whose name contains this text.",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "filter[description]",
                        "in": "query",
                        "required": false,
                        "description": "Servers whose description contains this text.",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "filter[external_id]",
                        "in": "query",
                        "required": false,
                        "description": "Servers whose external ID contains this text.",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "include",
                        "in": "query",
                        "required": false,
                        "description": "Extra relationships to add to each server, comma-separated: `egg` and/or `subusers`. `subusers` comes back as a `null_resource` on servers where you lack `user.read`.",
                        "schema": {
                            "type": "string"
                        },
                        "example": "egg"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "A page of servers.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/ServerList"
                                },
                                "example": {
                                    "object": "list",
                                    "data": [
                                        {
                                            "object": "server",
                                            "attributes": {
                                                "server_owner": true,
                                                "identifier": "1a7ce997",
                                                "__deprecated_uuid_short": "1a7ce997",
                                                "server_identifier": "serv_DJ5MXFRFJ5JFFDSOJZHE5RQCUU",
                                                "internal_id": 4127,
                                                "uuid": "1a7ce997-259b-452e-8b4e-cecc464142ca",
                                                "name": "My Discord bot",
                                                "node": "London 3",
                                                "is_node_under_maintenance": false,
                                                "sftp_details": {
                                                    "ip": "lon3.sillydev.co.uk",
                                                    "port": 2022
                                                },
                                                "description": "",
                                                "limits": {
                                                    "memory": 256,
                                                    "swap": 0,
                                                    "disk": 512,
                                                    "io": 500,
                                                    "cpu": 25,
                                                    "threads": null,
                                                    "oom_disabled": true
                                                },
                                                "invocation": "node /home/container/index.js",
                                                "docker_image": "ghcr.io/pterodactyl/yolks:nodejs_22",
                                                "egg_features": null,
                                                "feature_limits": {
                                                    "allocations": 1,
                                                    "backups": 2
                                                },
                                                "status": null,
                                                "is_paid": false,
                                                "is_suspended": false,
                                                "is_installing": false,
                                                "is_transferring": false,
                                                "skip_scripts": false,
                                                "relationships": {
                                                    "allocations": {
                                                        "object": "list",
                                                        "data": [
                                                            {
                                                                "object": "allocation",
                                                                "attributes": {
                                                                    "id": 9921,
                                                                    "ip": "203.0.113.10",
                                                                    "ip_alias": null,
                                                                    "port": 25565,
                                                                    "notes": null,
                                                                    "is_default": true
                                                                }
                                                            }
                                                        ]
                                                    },
                                                    "variables": {
                                                        "object": "list",
                                                        "data": [
                                                            {
                                                                "object": "egg_variable",
                                                                "attributes": {
                                                                    "name": "Main file",
                                                                    "description": "The file the bot is started from.",
                                                                    "env_variable": "MAIN_FILE",
                                                                    "default_value": "index.js",
                                                                    "server_value": "index.js",
                                                                    "is_editable": true,
                                                                    "rules": "required|string|max:64"
                                                                }
                                                            }
                                                        ]
                                                    }
                                                }
                                            }
                                        }
                                    ],
                                    "meta": {
                                        "pagination": {
                                            "total": 1,
                                            "count": 1,
                                            "per_page": 50,
                                            "current_page": 1,
                                            "total_pages": 1,
                                            "links": []
                                        },
                                        "pending_orders": [
                                            {
                                                "uuid": "6f1d0c2e-8a7b-4c33-9b1e-2f0a5d4c7e91",
                                                "name": "My paid bot",
                                                "runtime": "python",
                                                "status": "provisioning",
                                                "attempts": 1,
                                                "limits": {
                                                    "memory": 1024,
                                                    "disk": 2048,
                                                    "cpu": 100
                                                },
                                                "created_at": "2026-10-10T12:00:00+00:00"
                                            }
                                        ]
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthenticated"
                    },
                    "429": {
                        "$ref": "#/components/responses/TooManyRequests"
                    }
                }
            }
        },
        "/permissions": {
            "get": {
                "operationId": "listPermissions",
                "tags": [
                    "Servers"
                ],
                "summary": "List subuser permissions",
                "description": "Returns every server permission that exists, grouped, with a description of each. Use it to build a permission picker or to check the strings used in `x-permission` and in subuser and API key permission lists; a permission is written `group.key`, e.g. `control.start`.",
                "responses": {
                    "200": {
                        "description": "All server permissions.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/ServerPermissionList"
                                },
                                "example": {
                                    "object": "system_permissions",
                                    "attributes": {
                                        "permissions": {
                                            "websocket": {
                                                "description": "Allows the user to connect to the server websocket, giving them access to view console output and realtime server stats.",
                                                "keys": {
                                                    "connect": "Allows a user to connect to the websocket instance for a server to stream the console."
                                                }
                                            },
                                            "control": {
                                                "description": "Permissions that control a user's ability to control the power state of a server, or send commands.",
                                                "keys": {
                                                    "console": "Allows a user to send commands to the server instance via the console.",
                                                    "start": "Allows a user to start the server if it is stopped.",
                                                    "stop": "Allows a user to stop a server if it is running.",
                                                    "restart": "Allows a user to perform a server restart. This allows them to start the server if it is offline, but not put the server in a completely stopped state."
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthenticated"
                    }
                }
            }
        },
        "/resources": {
            "get": {
                "operationId": "listServerResources",
                "tags": [
                    "Servers"
                ],
                "summary": "Get resource use of several servers",
                "description": "Returns the live resource use of up to 100 servers in one request, keyed by server UUID. A server is silently left out if you could not read it on its own, if it is suspended, installing, being transferred, restoring a backup, being deleted or on a node under maintenance, or if its node did not answer. Answers are cached for up to 20 seconds (3 seconds while a server is booting), so polling faster gains nothing.",
                "parameters": [
                    {
                        "name": "servers",
                        "in": "query",
                        "required": true,
                        "description": "Comma-separated full server UUIDs (not 8-character identifiers). Duplicates are ignored and only the first 100 are used.",
                        "schema": {
                            "type": "string",
                            "maxLength": 3700
                        },
                        "example": "1a7ce997-259b-452e-8b4e-cecc464142ca,6f1d0c2e-8a7b-4c33-9b1e-2f0a5d4c7e91"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "The usage of each server that could be read, keyed by UUID. When none could be read, `data` is an empty object.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "required": [
                                        "object",
                                        "data"
                                    ],
                                    "properties": {
                                        "object": {
                                            "type": "string",
                                            "const": "server_stats_list"
                                        },
                                        "data": {
                                            "type": "object",
                                            "additionalProperties": {
                                                "$ref": "#/components/schemas/ServerResourcesItem"
                                            }
                                        }
                                    }
                                },
                                "example": {
                                    "object": "server_stats_list",
                                    "data": {
                                        "1a7ce997-259b-452e-8b4e-cecc464142ca": {
                                            "object": "stats",
                                            "attributes": {
                                                "current_state": "running",
                                                "is_suspended": false,
                                                "is_booting": false,
                                                "resources": {
                                                    "memory_bytes": 83886080,
                                                    "cpu_absolute": 1.25,
                                                    "disk_bytes": 41943040,
                                                    "network_rx_bytes": 102400,
                                                    "network_tx_bytes": 51200,
                                                    "uptime": 3600000
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthenticated"
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationFailed"
                    },
                    "429": {
                        "$ref": "#/components/responses/TooManyRequests"
                    }
                }
            }
        },
        "/servers/{server}": {
            "parameters": [
                {
                    "$ref": "#/components/parameters/Server"
                }
            ],
            "get": {
                "operationId": "getServer",
                "tags": [
                    "Servers"
                ],
                "summary": "Get a server",
                "description": "Returns one server with its allocations and startup variables. This works whatever state the server is in (installing, suspended, being transferred or being deleted), so it is the endpoint to poll while waiting for a state to change. `meta` says whether you own the server and which permissions you (as limited by your key) have on it; `*` means all of them.",
                "parameters": [
                    {
                        "name": "include",
                        "in": "query",
                        "required": false,
                        "description": "Extra relationships, comma-separated: `egg` and/or `subusers`. `subusers` comes back as a `null_resource` if you lack `user.read`.",
                        "schema": {
                            "type": "string"
                        },
                        "example": "egg,subusers"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "The server.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "allOf": [
                                        {
                                            "$ref": "#/components/schemas/ServerItem"
                                        },
                                        {
                                            "type": "object",
                                            "required": [
                                                "meta"
                                            ],
                                            "properties": {
                                                "meta": {
                                                    "type": "object",
                                                    "required": [
                                                        "is_server_owner",
                                                        "user_permissions"
                                                    ],
                                                    "properties": {
                                                        "is_server_owner": {
                                                            "type": "boolean",
                                                            "description": "Whether the key's user owns this server."
                                                        },
                                                        "user_permissions": {
                                                            "type": "array",
                                                            "description": "The permissions you have on this server. Owners and administrators get `[\"*\"]` (administrators also get `admin.websocket.*` entries), subusers get their list, and a key limited to some permissions only gets those.",
                                                            "items": {
                                                                "type": "string"
                                                            }
                                                        }
                                                    }
                                                }
                                            }
                                        }
                                    ]
                                },
                                "example": {
                                    "object": "server",
                                    "attributes": {
                                        "server_owner": true,
                                        "identifier": "1a7ce997",
                                        "__deprecated_uuid_short": "1a7ce997",
                                        "server_identifier": "serv_DJ5MXFRFJ5JFFDSOJZHE5RQCUU",
                                        "internal_id": 4127,
                                        "uuid": "1a7ce997-259b-452e-8b4e-cecc464142ca",
                                        "name": "My Discord bot",
                                        "node": "London 3",
                                        "is_node_under_maintenance": false,
                                        "sftp_details": {
                                            "ip": "lon3.sillydev.co.uk",
                                            "port": 2022
                                        },
                                        "description": "Moderation bot for my server",
                                        "limits": {
                                            "memory": 256,
                                            "swap": 0,
                                            "disk": 512,
                                            "io": 500,
                                            "cpu": 25,
                                            "threads": null,
                                            "oom_disabled": true
                                        },
                                        "invocation": "python /home/container/bot.py",
                                        "docker_image": "ghcr.io/pterodactyl/yolks:python_3.12",
                                        "egg_features": null,
                                        "feature_limits": {
                                            "allocations": 1,
                                            "backups": 2
                                        },
                                        "status": null,
                                        "is_paid": false,
                                        "is_suspended": false,
                                        "is_installing": false,
                                        "is_transferring": false,
                                        "skip_scripts": false,
                                        "relationships": {
                                            "allocations": {
                                                "object": "list",
                                                "data": [
                                                    {
                                                        "object": "allocation",
                                                        "attributes": {
                                                            "id": 9921,
                                                            "ip": "203.0.113.10",
                                                            "ip_alias": null,
                                                            "port": 25565,
                                                            "notes": null,
                                                            "is_default": true
                                                        }
                                                    }
                                                ]
                                            },
                                            "variables": {
                                                "object": "list",
                                                "data": [
                                                    {
                                                        "object": "egg_variable",
                                                        "attributes": {
                                                            "name": "Bot file",
                                                            "description": "The Python file the bot is started from.",
                                                            "env_variable": "BOT_PY_FILE",
                                                            "default_value": "bot.py",
                                                            "server_value": "bot.py",
                                                            "is_editable": true,
                                                            "rules": "required|string|max:64"
                                                        }
                                                    }
                                                ]
                                            },
                                            "egg": {
                                                "object": "egg",
                                                "attributes": {
                                                    "uuid": "3e9d5a1c-7f42-4b8e-a1d6-0c5b9f2e8d47",
                                                    "name": "Python"
                                                }
                                            }
                                        }
                                    },
                                    "meta": {
                                        "is_server_owner": true,
                                        "user_permissions": [
                                            "*"
                                        ]
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthenticated"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "429": {
                        "$ref": "#/components/responses/TooManyRequests"
                    }
                }
            },
            "delete": {
                "operationId": "deleteServer",
                "tags": [
                    "Servers"
                ],
                "summary": "Delete a server",
                "description": "Permanently deletes the server and its files. Only the server's owner can do this, with a key that is not limited to a set of permissions; subusers cannot, and it cannot be delegated. Deletion is asynchronous: once the node accepts it the server's `status` becomes `deleting` and every other endpoint for it answers 409 until the node has removed it, after which it is gone (GET returns 404). If the node cannot be reached nothing is deleted and the error is returned. A paid server whose subscription is still set to renew is refused with 400: schedule a downgrade first.",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "required": [
                                    "name"
                                ],
                                "properties": {
                                    "name": {
                                        "type": "string",
                                        "description": "The server's current name, as a confirmation. It must match exactly, including case; surrounding spaces are ignored."
                                    }
                                }
                            },
                            "example": {
                                "name": "My Discord bot"
                            }
                        }
                    }
                },
                "responses": {
                    "204": {
                        "$ref": "#/components/responses/NoContent"
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthenticated"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "409": {
                        "$ref": "#/components/responses/Conflict"
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationFailed"
                    },
                    "429": {
                        "$ref": "#/components/responses/TooManyRequests"
                    }
                }
            }
        },
        "/servers/{server}/websocket": {
            "parameters": [
                {
                    "$ref": "#/components/parameters/Server"
                }
            ],
            "get": {
                "operationId": "getWebsocketCredentials",
                "tags": [
                    "Power and console"
                ],
                "summary": "Get console websocket credentials",
                "description": "Returns a short-lived token and the URL of the server's live console websocket, which\nstreams console output, status changes and resource use, and accepts commands and\npower actions. The token lasts 10 minutes and carries your permissions on the server\nat the time it was issued.\n\n**Connecting.** Open a websocket to `data.socket`. The node checks the `Origin`\nheader, so clients outside a browser must send `Origin: https://sillydev.co.uk`.\nEvery message in both directions is a JSON text frame `{\"event\": \"<name>\", \"args\":\n[\"...\"]}`, where `args` is always a list of strings (and may be left out). First send\n`{\"event\": \"auth\", \"args\": [\"<token>\"]}`. The node answers `auth success`, then sends\nthe current `status` (and, if the server is offline, a `stats` message). Nothing else\nis sent or accepted until you have authenticated.\n\n**Main events.** Send `send logs` to get recent console history (only while the\nserver is running; each line arrives as a `console output` event), `send command`\nwith the command as `args[0]` (needs `control.console`, ignored while the server is\noffline), `set state` with `start`, `stop`, `restart` or `kill` as `args[0]` (needs\nthe matching `control.*` permission), and `send stats` for an immediate `stats`\nmessage. You receive `console output` (one line per message), `status` (`offline`,\n`starting`, `running` or `stopping`), `stats` (whose `args[0]` is a JSON string with\n`memory_bytes`, `memory_limit_bytes`, `cpu_absolute`, `network.rx_bytes`,\n`network.tx_bytes`, `uptime` in milliseconds, `state` and `disk_bytes`), and\n`daemon message` (notes from the node, e.g. about installation).\n\n**Keeping the token fresh.** About a minute before the token expires the node sends\n`token expiring`, and `token expired` once it has. Call this endpoint again and send\na new `auth` message on the same connection; there is no need to reconnect. A\nproblem with the token arrives as `jwt error`, other failures as `daemon error`, and\nsending too fast as `throttled` (with the event name as `args[0]`). The node limits\n`auth` and `send logs` to 2 every 5 seconds, `send command` to 10 a second and other\nevents to 4 a second.\n\n**Close codes.** The node closes the connection with code 4409 if the server is\nsuspended (do not reconnect) and 4410 while it is still loading the server after a\nnode restart (wait a few seconds and connect again).\n\nThis endpoint itself is limited to 5 requests a minute per server, shared by everyone\nusing that server.\n",
                "x-permission": "websocket.connect",
                "x-rate-limit": "5 per minute per server (shared by all users of the server)",
                "x-websocket-events": [
                    {
                        "name": "auth",
                        "direction": "send",
                        "description": "Authenticate, or re-authenticate with a fresh token. `args[0]` is the token from this endpoint."
                    },
                    {
                        "name": "send logs",
                        "direction": "send",
                        "description": "Ask for recent console history. Lines arrive as `console output` events. Ignored while the server is not running."
                    },
                    {
                        "name": "send command",
                        "direction": "send",
                        "description": "Type a command into the console. `args[0]` is the command. Needs `control.console`; ignored while the server is offline."
                    },
                    {
                        "name": "set state",
                        "direction": "send",
                        "description": "Send a power action. `args[0]` is `start`, `stop`, `restart` or `kill`. Needs `control.start`, `control.stop` (also for `kill`) or `control.restart`."
                    },
                    {
                        "name": "send stats",
                        "direction": "send",
                        "description": "Ask for a `stats` message straight away."
                    },
                    {
                        "name": "auth success",
                        "direction": "receive",
                        "description": "The token was accepted."
                    },
                    {
                        "name": "console output",
                        "direction": "receive",
                        "description": "One line of console output in `args[0]`."
                    },
                    {
                        "name": "status",
                        "direction": "receive",
                        "description": "The server's power state changed. `args[0]` is `offline`, `starting`, `running` or `stopping`."
                    },
                    {
                        "name": "stats",
                        "direction": "receive",
                        "description": "Resource use. `args[0]` is a JSON string with `memory_bytes`, `memory_limit_bytes`, `cpu_absolute`, `network` (`rx_bytes`, `tx_bytes`), `uptime` (milliseconds), `state` and `disk_bytes`."
                    },
                    {
                        "name": "daemon message",
                        "direction": "receive",
                        "description": "A message from the node rather than the server's own output, such as installation progress."
                    },
                    {
                        "name": "install started",
                        "direction": "receive",
                        "description": "The server's install script has started."
                    },
                    {
                        "name": "install output",
                        "direction": "receive",
                        "description": "One line of install script output. Only sent to administrators."
                    },
                    {
                        "name": "install completed",
                        "direction": "receive",
                        "description": "The server's install script has finished."
                    },
                    {
                        "name": "backup completed",
                        "direction": "receive",
                        "description": "A backup finished. The event name is `backup completed:<backup uuid>` and `args[0]` is a JSON string describing the result. Needs `backup.read`."
                    },
                    {
                        "name": "backup restore completed",
                        "direction": "receive",
                        "description": "Restoring a backup finished."
                    },
                    {
                        "name": "transfer status",
                        "direction": "receive",
                        "description": "The status of a transfer of the server to another node."
                    },
                    {
                        "name": "transfer logs",
                        "direction": "receive",
                        "description": "Transfer log output. Only sent to administrators."
                    },
                    {
                        "name": "token expiring",
                        "direction": "receive",
                        "description": "The token expires within about a minute. Get a new one from this endpoint and send `auth` again."
                    },
                    {
                        "name": "token expired",
                        "direction": "receive",
                        "description": "The token has expired. Get a new one and send `auth` again."
                    },
                    {
                        "name": "jwt error",
                        "direction": "receive",
                        "description": "The token is missing, expired, for another server or otherwise invalid. `args[0]` says why."
                    },
                    {
                        "name": "daemon error",
                        "direction": "receive",
                        "description": "Handling a message failed. `args[0]` is an error message with a reference ID."
                    },
                    {
                        "name": "throttled",
                        "direction": "receive",
                        "description": "Messages of the event named in `args[0]` are being dropped because they were sent too fast."
                    }
                ],
                "responses": {
                    "200": {
                        "description": "A websocket token and address.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/ServerWebsocketCredentials"
                                },
                                "example": {
                                    "data": {
                                        "token": "eyJhbGciOi...",
                                        "socket": "wss://lon3.sillydev.co.uk:8080/api/servers/1a7ce997-259b-452e-8b4e-cecc464142ca/ws"
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthenticated"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "409": {
                        "$ref": "#/components/responses/Conflict"
                    },
                    "429": {
                        "$ref": "#/components/responses/TooManyRequests"
                    }
                }
            }
        },
        "/servers/{server}/resources": {
            "parameters": [
                {
                    "$ref": "#/components/parameters/Server"
                }
            ],
            "get": {
                "operationId": "getServerResources",
                "tags": [
                    "Servers"
                ],
                "summary": "Get a server's resource use",
                "description": "Returns the server's power state and current memory, CPU, disk and network use, as reported by its node. The answer is cached for up to 20 seconds (3 seconds while the server is booting); for a live feed use the websocket's `stats` events instead. Any server permission is enough to read it.",
                "responses": {
                    "200": {
                        "description": "The server's resource use.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/ServerResourcesItem"
                                },
                                "example": {
                                    "object": "stats",
                                    "attributes": {
                                        "current_state": "running",
                                        "is_suspended": false,
                                        "is_booting": false,
                                        "resources": {
                                            "memory_bytes": 83886080,
                                            "cpu_absolute": 1.25,
                                            "disk_bytes": 41943040,
                                            "network_rx_bytes": 102400,
                                            "network_tx_bytes": 51200,
                                            "uptime": 3600000
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthenticated"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "409": {
                        "$ref": "#/components/responses/Conflict"
                    },
                    "429": {
                        "$ref": "#/components/responses/TooManyRequests"
                    }
                }
            }
        },
        "/servers/{server}/activity": {
            "parameters": [
                {
                    "$ref": "#/components/parameters/Server"
                }
            ],
            "get": {
                "operationId": "listServerActivity",
                "tags": [
                    "Servers"
                ],
                "summary": "List a server's activity",
                "description": "Lists what has been done to the server and by whom: power actions, commands, file changes, settings changes and so on, 25 a page by default. Actions taken by administrators are left out. IP addresses are only shown for your own actions.",
                "x-permission": "activity.read",
                "parameters": [
                    {
                        "$ref": "#/components/parameters/Page"
                    },
                    {
                        "name": "per_page",
                        "in": "query",
                        "required": false,
                        "description": "How many entries to return on each page. Values above 100 are treated as 100.",
                        "schema": {
                            "type": "integer",
                            "minimum": 1,
                            "maximum": 100,
                            "default": 25
                        }
                    },
                    {
                        "name": "sort",
                        "in": "query",
                        "required": false,
                        "description": "`-timestamp` for newest first or `timestamp` for oldest first. Without it the order is not guaranteed.",
                        "schema": {
                            "type": "string",
                            "enum": [
                                "timestamp",
                                "-timestamp"
                            ]
                        }
                    },
                    {
                        "name": "filter[event]",
                        "in": "query",
                        "required": false,
                        "description": "Only entries whose event name contains this text, e.g. `server:power`.",
                        "schema": {
                            "type": "string"
                        },
                        "example": "server:power"
                    },
                    {
                        "name": "include",
                        "in": "query",
                        "required": false,
                        "description": "`actor` adds the user who did each thing as `relationships.actor`.",
                        "schema": {
                            "type": "string",
                            "enum": [
                                "actor"
                            ]
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "A page of activity entries.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/ServerActivityList"
                                },
                                "example": {
                                    "object": "list",
                                    "data": [
                                        {
                                            "object": "activity_log",
                                            "attributes": {
                                                "id": "3f786850e387550fdab836ed7e6dc881de23001b",
                                                "batch": null,
                                                "event": "server:power.start",
                                                "is_api": true,
                                                "ip": "198.51.100.7",
                                                "description": null,
                                                "properties": [],
                                                "has_additional_metadata": false,
                                                "timestamp": "2026-10-10T12:00:00+00:00",
                                                "relationships": {
                                                    "actor": {
                                                        "object": "user",
                                                        "attributes": {
                                                            "uuid": "0b9c4e2a-6d1f-4f8a-9c3e-5a7b2d1e8f60",
                                                            "identifier": "user_BFZ4QKTPNVHU7HUYLUOHRH4QMA",
                                                            "username": "you",
                                                            "email": "you@example.com",
                                                            "image": "https://gravatar.com/avatar/00000000000000000000000000000000",
                                                            "2fa_enabled": true,
                                                            "created_at": "2026-01-15T09:30:00+00:00"
                                                        }
                                                    }
                                                }
                                            }
                                        }
                                    ],
                                    "meta": {
                                        "pagination": {
                                            "total": 1,
                                            "count": 1,
                                            "per_page": 25,
                                            "current_page": 1,
                                            "total_pages": 1,
                                            "links": []
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthenticated"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "409": {
                        "$ref": "#/components/responses/Conflict"
                    },
                    "429": {
                        "$ref": "#/components/responses/TooManyRequests"
                    }
                }
            }
        },
        "/servers/{server}/command": {
            "parameters": [
                {
                    "$ref": "#/components/parameters/Server"
                }
            ],
            "post": {
                "operationId": "sendCommand",
                "tags": [
                    "Power and console"
                ],
                "summary": "Send a console command",
                "description": "Types a command into the server's console, as if entered in the panel. The server must be running: if it is not, the request fails with 502. The command's output is not returned; read it from the websocket.",
                "x-permission": "control.console",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "required": [
                                    "command"
                                ],
                                "properties": {
                                    "command": {
                                        "type": "string",
                                        "minLength": 1,
                                        "description": "The command, without a trailing newline."
                                    }
                                }
                            },
                            "example": {
                                "command": "reload"
                            }
                        }
                    }
                },
                "responses": {
                    "204": {
                        "$ref": "#/components/responses/NoContent"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthenticated"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "409": {
                        "$ref": "#/components/responses/Conflict"
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationFailed"
                    },
                    "429": {
                        "$ref": "#/components/responses/TooManyRequests"
                    },
                    "502": {
                        "description": "The server is not running, or its node could not be reached.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                },
                                "example": {
                                    "errors": [
                                        {
                                            "code": "HttpException",
                                            "status": "502",
                                            "detail": "Server must be online in order to send commands."
                                        }
                                    ]
                                }
                            }
                        }
                    }
                }
            }
        },
        "/servers/{server}/logs/share": {
            "parameters": [
                {
                    "$ref": "#/components/parameters/Server"
                }
            ],
            "post": {
                "operationId": "shareLogs",
                "tags": [
                    "Power and console"
                ],
                "summary": "Share console output",
                "description": "Uploads console text you send to mclo.gs, a public paste site, and returns its link. Email addresses, tokens, passwords, credentials in URLs, IP addresses and private keys are replaced with placeholders such as `[token]` first, but check before sharing the link: the paste is public. Text over mclo.gs's limits (25,000 lines or 10 MiB) is cut from the start, keeping the latest output.",
                "x-permission": "websocket.connect",
                "x-rate-limit": "6 per minute per user",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "required": [
                                    "content"
                                ],
                                "properties": {
                                    "content": {
                                        "type": "string",
                                        "maxLength": 2000000,
                                        "description": "The console text to share. The panel does not fetch it from the server; you send it."
                                    }
                                }
                            },
                            "example": {
                                "content": "Logged in as My Discord bot#1234\nError: Missing Access\n    at RequestHandler.execute"
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "The public link to the shared log.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "required": [
                                        "url"
                                    ],
                                    "properties": {
                                        "url": {
                                            "type": "string",
                                            "format": "uri"
                                        }
                                    }
                                },
                                "example": {
                                    "url": "https://mclo.gs/aB3dE5f"
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthenticated"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "409": {
                        "$ref": "#/components/responses/Conflict"
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationFailed"
                    },
                    "429": {
                        "$ref": "#/components/responses/TooManyRequests"
                    },
                    "502": {
                        "description": "mclo.gs could not take the log. Try again in a moment.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                },
                                "example": {
                                    "errors": [
                                        {
                                            "code": "HttpException",
                                            "status": "502",
                                            "detail": "mclo.gs could not take the log right now. Please try again in a moment."
                                        }
                                    ]
                                }
                            }
                        }
                    }
                }
            }
        },
        "/servers/{server}/power": {
            "parameters": [
                {
                    "$ref": "#/components/parameters/Server"
                }
            ],
            "post": {
                "operationId": "sendPowerSignal",
                "tags": [
                    "Power and console"
                ],
                "summary": "Start, stop, restart or kill a server",
                "description": "Sends a power action to the server. The node accepts it straight away and carries it\nout in the background, so a 204 means the action was accepted, not that it has\nfinished: watch `status` on the websocket or poll the resources endpoint.\n\n- `start` starts the server if it is stopped.\n- `stop` stops it gracefully with the egg's stop command, and also cancels a start\n  that has not yet started the container.\n- `restart` stops it gracefully and starts it again (or just starts it if stopped).\n- `kill` stops the container immediately, which can lose unsaved data. It skips the\n  queue below and cancels any start or restart in progress.\n\nA server runs one power action at a time; one sent while another is running waits,\nand only the most recent waiting action is kept. Starts also wait their turn in the\nnode's start queue when many servers are starting at once (paid servers go first),\nand the console says so while they wait. Suspended servers cannot be started.\n",
                "x-permission": [
                    "control.start",
                    "control.stop",
                    "control.restart"
                ],
                "x-permission-note": "`start` needs control.start, `stop` and `kill` need control.stop, `restart` needs control.restart.",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "required": [
                                    "signal"
                                ],
                                "properties": {
                                    "signal": {
                                        "type": "string",
                                        "enum": [
                                            "start",
                                            "stop",
                                            "restart",
                                            "kill"
                                        ]
                                    }
                                }
                            },
                            "example": {
                                "signal": "restart"
                            }
                        }
                    }
                },
                "responses": {
                    "204": {
                        "$ref": "#/components/responses/NoContent"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthenticated"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "409": {
                        "$ref": "#/components/responses/Conflict"
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationFailed"
                    },
                    "429": {
                        "$ref": "#/components/responses/TooManyRequests"
                    }
                }
            }
        },
        "/servers/{server}/settings/rename": {
            "parameters": [
                {
                    "$ref": "#/components/parameters/Server"
                }
            ],
            "post": {
                "operationId": "renameServer",
                "tags": [
                    "Settings"
                ],
                "summary": "Rename a server",
                "description": "Changes the server's name and, optionally, its description. Leave `description` out to keep the current one; send `null` or an empty string to clear it. On a paid server the new name is also shown on invoices.",
                "x-permission": "settings.rename",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "required": [
                                    "name"
                                ],
                                "properties": {
                                    "name": {
                                        "type": "string",
                                        "minLength": 1,
                                        "maxLength": 191
                                    },
                                    "description": {
                                        "type": [
                                            "string",
                                            "null"
                                        ]
                                    }
                                }
                            },
                            "example": {
                                "name": "My Discord bot",
                                "description": "Moderation bot for my server"
                            }
                        }
                    }
                },
                "responses": {
                    "204": {
                        "$ref": "#/components/responses/NoContent"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthenticated"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "409": {
                        "$ref": "#/components/responses/Conflict"
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationFailed"
                    },
                    "429": {
                        "$ref": "#/components/responses/TooManyRequests"
                    }
                }
            }
        },
        "/servers/{server}/settings/reinstall": {
            "parameters": [
                {
                    "$ref": "#/components/parameters/Server"
                }
            ],
            "post": {
                "operationId": "reinstallServer",
                "tags": [
                    "Settings"
                ],
                "summary": "Reinstall a server",
                "description": "Stops the server and runs its install script again. The server's `status` becomes `installing` until the script finishes, and most endpoints answer 409 meanwhile. This is also the one thing you can still do to a server whose install failed (`status` `install_failed`). Servers set to skip install scripts cannot be reinstalled (400) unless their install failed.",
                "x-permission": "settings.reinstall",
                "responses": {
                    "202": {
                        "description": "The reinstall has started. The body is an empty JSON array.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "array",
                                    "maxItems": 0
                                },
                                "example": []
                            }
                        }
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthenticated"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "409": {
                        "$ref": "#/components/responses/Conflict"
                    },
                    "429": {
                        "$ref": "#/components/responses/TooManyRequests"
                    }
                }
            }
        },
        "/servers/{server}/settings/docker-image": {
            "parameters": [
                {
                    "$ref": "#/components/parameters/Server"
                }
            ],
            "put": {
                "operationId": "setDockerImage",
                "tags": [
                    "Settings"
                ],
                "summary": "Change the Docker image",
                "description": "Switches the server to another of the Docker images its egg offers, for example a newer Node.js or Python version. The list of choices is `meta.docker_images` from the startup endpoint. It takes effect the next time the server starts. If an administrator set a custom image, it cannot be changed here (400).",
                "x-permission": "startup.docker-image",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "required": [
                                    "docker_image"
                                ],
                                "properties": {
                                    "docker_image": {
                                        "type": "string",
                                        "maxLength": 191,
                                        "description": "One of the image values (not the display names) in the startup endpoint's `meta.docker_images`."
                                    }
                                }
                            },
                            "example": {
                                "docker_image": "ghcr.io/pterodactyl/yolks:nodejs_22"
                            }
                        }
                    }
                },
                "responses": {
                    "204": {
                        "$ref": "#/components/responses/NoContent"
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthenticated"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "409": {
                        "$ref": "#/components/responses/Conflict"
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationFailed"
                    },
                    "429": {
                        "$ref": "#/components/responses/TooManyRequests"
                    }
                }
            }
        },
        "/servers/{server}/settings/badge": {
            "parameters": [
                {
                    "$ref": "#/components/parameters/Server"
                }
            ],
            "get": {
                "operationId": "getStatusBadge",
                "tags": [
                    "Settings"
                ],
                "summary": "Get the status badge",
                "description": "Whether the server's public status badge is on, and if so its image address and a Markdown snippet for a README. The badge is an image that says `online`, `starting`, `offline` or `unknown`, refreshed at most once a minute, and nothing else about the server. Owner only, with a key that has `settings.rename`; subusers cannot see or change it.",
                "x-permission": "settings.rename",
                "responses": {
                    "200": {
                        "description": "The badge's settings. `url` and `markdown` are null while it is off.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/ServerBadgeItem"
                                },
                                "example": {
                                    "object": "server_badge",
                                    "attributes": {
                                        "enabled": true,
                                        "show_name": false,
                                        "url": "https://sillydev.co.uk/badge/k3Q9vX2mL7pR4tW8zB1nC6dF0gH5jS2aE9uY3iO7.svg",
                                        "link": "https://sillydev.co.uk/?ref=badge",
                                        "markdown": "[![bot status](https://sillydev.co.uk/badge/k3Q9vX2mL7pR4tW8zB1nC6dF0gH5jS2aE9uY3iO7.svg)](https://sillydev.co.uk/?ref=badge)"
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthenticated"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "409": {
                        "$ref": "#/components/responses/Conflict"
                    },
                    "429": {
                        "$ref": "#/components/responses/TooManyRequests"
                    }
                }
            },
            "put": {
                "operationId": "updateStatusBadge",
                "tags": [
                    "Settings"
                ],
                "summary": "Turn on the status badge",
                "description": "Turns the badge on, giving it a new random address (201), or changes whether it shows the server's name (200). Off by default; until it is turned on there is no badge to find. With `show_name` false or left out the badge's label is just \"bot\". Owner only, with a key that has `settings.rename`.",
                "x-permission": "settings.rename",
                "x-rate-limit": "20 per minute",
                "requestBody": {
                    "required": false,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "show_name": {
                                        "type": "boolean",
                                        "description": "Show the server's name on the badge instead of \"bot\". Left out, the current setting is kept (off for a new badge)."
                                    }
                                }
                            },
                            "example": {
                                "show_name": false
                            }
                        }
                    }
                },
                "responses": {
                    "201": {
                        "description": "The badge is now on, at a new address.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/ServerBadgeItem"
                                },
                                "example": {
                                    "object": "server_badge",
                                    "attributes": {
                                        "enabled": true,
                                        "show_name": false,
                                        "url": "https://sillydev.co.uk/badge/k3Q9vX2mL7pR4tW8zB1nC6dF0gH5jS2aE9uY3iO7.svg",
                                        "link": "https://sillydev.co.uk/?ref=badge",
                                        "markdown": "[![bot status](https://sillydev.co.uk/badge/k3Q9vX2mL7pR4tW8zB1nC6dF0gH5jS2aE9uY3iO7.svg)](https://sillydev.co.uk/?ref=badge)"
                                    }
                                }
                            }
                        }
                    },
                    "200": {
                        "description": "The badge was already on; its settings now.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/ServerBadgeItem"
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthenticated"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "409": {
                        "$ref": "#/components/responses/Conflict"
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationFailed"
                    },
                    "429": {
                        "$ref": "#/components/responses/TooManyRequests"
                    }
                }
            },
            "delete": {
                "operationId": "deleteStatusBadge",
                "tags": [
                    "Settings"
                ],
                "summary": "Turn off the status badge",
                "description": "Turns the badge off and forgets its address, which then shows `unknown` with a 404 (copies cached elsewhere can last up to a minute). Turning it on again makes a new address. Owner only, with a key that has `settings.rename`.",
                "x-permission": "settings.rename",
                "responses": {
                    "204": {
                        "$ref": "#/components/responses/NoContent"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthenticated"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "409": {
                        "$ref": "#/components/responses/Conflict"
                    },
                    "429": {
                        "$ref": "#/components/responses/TooManyRequests"
                    }
                }
            }
        },
        "/servers/{server}/settings/badge/regenerate": {
            "parameters": [
                {
                    "$ref": "#/components/parameters/Server"
                }
            ],
            "post": {
                "operationId": "regenerateStatusBadge",
                "tags": [
                    "Settings"
                ],
                "summary": "Replace the status badge's address",
                "description": "Gives the badge a new random address. The old one stops working at once, though copies cached elsewhere can last up to a minute, so update your README. 404 while the badge is off. Owner only, with a key that has `settings.rename`.",
                "x-permission": "settings.rename",
                "x-rate-limit": "10 per minute",
                "responses": {
                    "200": {
                        "description": "The badge, at its new address.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/ServerBadgeItem"
                                },
                                "example": {
                                    "object": "server_badge",
                                    "attributes": {
                                        "enabled": true,
                                        "show_name": false,
                                        "url": "https://sillydev.co.uk/badge/Zt5Yh2Kq8Wm3Np6Rs9Vb1Xc4Df7Gj0Lk2Pa5Qe8U.svg",
                                        "link": "https://sillydev.co.uk/?ref=badge",
                                        "markdown": "[![bot status](https://sillydev.co.uk/badge/Zt5Yh2Kq8Wm3Np6Rs9Vb1Xc4Df7Gj0Lk2Pa5Qe8U.svg)](https://sillydev.co.uk/?ref=badge)"
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthenticated"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "409": {
                        "$ref": "#/components/responses/Conflict"
                    },
                    "429": {
                        "$ref": "#/components/responses/TooManyRequests"
                    }
                }
            }
        },
        "/servers/{server}/startup": {
            "parameters": [
                {
                    "$ref": "#/components/parameters/Server"
                }
            ],
            "get": {
                "operationId": "getStartup",
                "tags": [
                    "Startup"
                ],
                "summary": "Get startup settings",
                "description": "Returns the startup variables you can see, the startup command with their values filled in, and the Docker images you can choose from. If a linked repository's `sillydev.conf` also sets some of these, `meta.sillydev` names them and says whether a change made here is written back to the file or will be undone by the next deploy.",
                "x-permission": "startup.read",
                "responses": {
                    "200": {
                        "description": "The server's startup variables and command.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "allOf": [
                                        {
                                            "$ref": "#/components/schemas/ServerStartupVariableList"
                                        },
                                        {
                                            "type": "object",
                                            "required": [
                                                "meta"
                                            ],
                                            "properties": {
                                                "meta": {
                                                    "type": "object",
                                                    "required": [
                                                        "startup_command",
                                                        "docker_images",
                                                        "raw_startup_command",
                                                        "sillydev"
                                                    ],
                                                    "properties": {
                                                        "startup_command": {
                                                            "type": "string",
                                                            "description": "The startup command with variable values filled in."
                                                        },
                                                        "raw_startup_command": {
                                                            "type": "string",
                                                            "description": "The startup command with `{{VARIABLE}}` placeholders."
                                                        },
                                                        "docker_images": {
                                                            "type": "object",
                                                            "description": "The images you can switch to, as display name to image.",
                                                            "additionalProperties": {
                                                                "type": "string"
                                                            }
                                                        },
                                                        "sillydev": {
                                                            "description": "Set when the linked repository's sillydev.conf also sets some of these settings, otherwise null.",
                                                            "oneOf": [
                                                                {
                                                                    "type": "null"
                                                                },
                                                                {
                                                                    "type": "object",
                                                                    "required": [
                                                                        "repository",
                                                                        "branch",
                                                                        "writes_back",
                                                                        "keys"
                                                                    ],
                                                                    "properties": {
                                                                        "repository": {
                                                                            "type": "string",
                                                                            "description": "The repository, as `owner/name`."
                                                                        },
                                                                        "branch": {
                                                                            "type": "string"
                                                                        },
                                                                        "writes_back": {
                                                                            "type": "boolean",
                                                                            "description": "Whether a change made here is committed to sillydev.conf. If false, the next deploy puts the file's value back."
                                                                        },
                                                                        "keys": {
                                                                            "type": "array",
                                                                            "description": "The variable names the file sets, plus `image` if it sets the Docker image.",
                                                                            "items": {
                                                                                "type": "string"
                                                                            }
                                                                        }
                                                                    }
                                                                }
                                                            ]
                                                        }
                                                    }
                                                }
                                            }
                                        }
                                    ]
                                },
                                "example": {
                                    "object": "list",
                                    "data": [
                                        {
                                            "object": "egg_variable",
                                            "attributes": {
                                                "name": "Main file",
                                                "description": "The file the bot is started from.",
                                                "env_variable": "MAIN_FILE",
                                                "default_value": "index.js",
                                                "server_value": "bot.js",
                                                "is_editable": true,
                                                "rules": "required|string|max:64"
                                            }
                                        }
                                    ],
                                    "meta": {
                                        "startup_command": "node /home/container/bot.js",
                                        "raw_startup_command": "node /home/container/{{MAIN_FILE}}",
                                        "docker_images": {
                                            "Node.js 20": "ghcr.io/pterodactyl/yolks:nodejs_20",
                                            "Node.js 22": "ghcr.io/pterodactyl/yolks:nodejs_22"
                                        },
                                        "sillydev": null
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthenticated"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "409": {
                        "$ref": "#/components/responses/Conflict"
                    },
                    "429": {
                        "$ref": "#/components/responses/TooManyRequests"
                    }
                }
            }
        },
        "/servers/{server}/startup/variable": {
            "parameters": [
                {
                    "$ref": "#/components/parameters/Server"
                }
            ],
            "put": {
                "operationId": "updateStartupVariable",
                "tags": [
                    "Startup"
                ],
                "summary": "Change a startup variable",
                "description": "Sets one startup variable and returns it with the updated startup command. The value is checked against the variable's own `rules`. Variables you cannot see or that are read-only (`is_editable` false) are refused with 400. The change takes effect the next time the server starts, and is written to the linked repository's sillydev.conf too if that file sets this variable and write-back is on.",
                "x-permission": "startup.update",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "required": [
                                    "key",
                                    "value"
                                ],
                                "properties": {
                                    "key": {
                                        "type": "string",
                                        "description": "The variable's `env_variable`, e.g. `MAIN_FILE`."
                                    },
                                    "value": {
                                        "type": [
                                            "string",
                                            "null"
                                        ],
                                        "description": "The new value. It must be present; whether it may be null or empty depends on the variable's rules. Null is stored as an empty string."
                                    }
                                }
                            },
                            "example": {
                                "key": "MAIN_FILE",
                                "value": "bot.js"
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "The updated variable.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "allOf": [
                                        {
                                            "$ref": "#/components/schemas/ServerStartupVariableItem"
                                        },
                                        {
                                            "type": "object",
                                            "required": [
                                                "meta"
                                            ],
                                            "properties": {
                                                "meta": {
                                                    "type": "object",
                                                    "required": [
                                                        "startup_command",
                                                        "raw_startup_command"
                                                    ],
                                                    "properties": {
                                                        "startup_command": {
                                                            "type": "string"
                                                        },
                                                        "raw_startup_command": {
                                                            "type": "string"
                                                        }
                                                    }
                                                }
                                            }
                                        }
                                    ]
                                },
                                "example": {
                                    "object": "egg_variable",
                                    "attributes": {
                                        "name": "Main file",
                                        "description": "The file the bot is started from.",
                                        "env_variable": "MAIN_FILE",
                                        "default_value": "index.js",
                                        "server_value": "bot.js",
                                        "is_editable": true,
                                        "rules": "required|string|max:64"
                                    },
                                    "meta": {
                                        "startup_command": "node /home/container/bot.js",
                                        "raw_startup_command": "node /home/container/{{MAIN_FILE}}"
                                    }
                                }
                            }
                        }
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthenticated"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "409": {
                        "$ref": "#/components/responses/Conflict"
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationFailed"
                    },
                    "429": {
                        "$ref": "#/components/responses/TooManyRequests"
                    }
                }
            }
        },
        "/servers/{server}/files/list": {
            "get": {
                "operationId": "listFiles",
                "tags": [
                    "Files"
                ],
                "summary": "List a directory",
                "description": "Returns the files and folders in one directory of the server, not recursively. The list is not paginated.",
                "x-permission": "file.read",
                "parameters": [
                    {
                        "$ref": "#/components/parameters/Server"
                    },
                    {
                        "name": "directory",
                        "in": "query",
                        "required": false,
                        "description": "The directory to list. Defaults to the root, `/`.",
                        "schema": {
                            "type": "string",
                            "default": "/"
                        },
                        "example": "/src"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "The directory's contents.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/FileObjectList"
                                },
                                "example": {
                                    "object": "list",
                                    "data": [
                                        {
                                            "object": "file_object",
                                            "attributes": {
                                                "name": "src",
                                                "mode": "drwxr-xr-x",
                                                "mode_bits": "755",
                                                "size": 4096,
                                                "is_file": false,
                                                "is_symlink": false,
                                                "mimetype": "inode/directory",
                                                "created_at": "2026-10-01T09:30:00+00:00",
                                                "modified_at": "2026-10-09T18:12:45+00:00"
                                            }
                                        },
                                        {
                                            "object": "file_object",
                                            "attributes": {
                                                "name": "main.py",
                                                "mode": "-rw-r--r--",
                                                "mode_bits": "644",
                                                "size": 2318,
                                                "is_file": true,
                                                "is_symlink": false,
                                                "mimetype": "text/x-python",
                                                "created_at": "2026-10-01T09:30:00+00:00",
                                                "modified_at": "2026-10-10T11:58:02+00:00"
                                            }
                                        }
                                    ]
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthenticated"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "409": {
                        "$ref": "#/components/responses/Conflict"
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationFailed"
                    }
                }
            }
        },
        "/servers/{server}/files/contents": {
            "get": {
                "operationId": "getFileContents",
                "tags": [
                    "Files"
                ],
                "summary": "Read a file",
                "description": "Returns the raw contents of a file as the response body, not JSON. The response is always sent as `text/plain`, whatever the file holds. Files larger than 4 MiB are refused with 400; use `getFileDownloadUrl` for those. The read is recorded in the server's activity log.",
                "x-permission": "file.read-content",
                "parameters": [
                    {
                        "$ref": "#/components/parameters/Server"
                    },
                    {
                        "name": "file",
                        "in": "query",
                        "required": true,
                        "description": "The path of the file to read.",
                        "schema": {
                            "type": "string"
                        },
                        "example": "/main.py"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "The file's contents, exactly as stored.",
                        "content": {
                            "text/plain": {
                                "schema": {
                                    "type": "string"
                                },
                                "example": "import discord\n\nclient = discord.Client(intents=discord.Intents.default())\n"
                            }
                        }
                    },
                    "400": {
                        "description": "The file is larger than 4 MiB, is a directory, or is a named pipe.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                },
                                "example": {
                                    "errors": [
                                        {
                                            "code": "FileSizeTooLargeException",
                                            "status": "400",
                                            "detail": "The file you are attempting to open is too large to view in the file editor."
                                        }
                                    ]
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthenticated"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "409": {
                        "$ref": "#/components/responses/Conflict"
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationFailed"
                    }
                }
            }
        },
        "/servers/{server}/files/download": {
            "get": {
                "operationId": "getFileDownloadUrl",
                "tags": [
                    "Files"
                ],
                "summary": "Get a download link for a file",
                "description": "Returns a signed URL on the server's node from which the file can be downloaded. This\nis step one of two: then send a plain `GET` to the returned URL, with no API key,\nand the node answers with the file as `application/octet-stream` and a\n`Content-Disposition: attachment` header. The URL works once and expires 15 minutes\nafter it is made; ask for a new one for each download.\n\nDirectories cannot be downloaded (the node answers 404); compress them first with\n`compressFiles`. Errors from the node come as `{\"error\": \"...\"}`, not the panel's\nerror format. Asking for the link is recorded in the server's activity log.\n",
                "x-permission": "file.read-content",
                "parameters": [
                    {
                        "$ref": "#/components/parameters/Server"
                    },
                    {
                        "name": "file",
                        "in": "query",
                        "required": true,
                        "description": "The path of the file to download.",
                        "schema": {
                            "type": "string"
                        },
                        "example": "/logs/latest.log"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "A single-use download link, valid for 15 minutes.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/FileSignedUrl"
                                },
                                "example": {
                                    "object": "signed_url",
                                    "attributes": {
                                        "url": "https://node1.sillydev.co.uk:8080/download/file?token=eyJhbGciOi..."
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthenticated"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "409": {
                        "$ref": "#/components/responses/Conflict"
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationFailed"
                    }
                }
            }
        },
        "/servers/{server}/files/rename": {
            "put": {
                "operationId": "renameFiles",
                "tags": [
                    "Files"
                ],
                "summary": "Rename or move files",
                "description": "Renames or moves one or more files or folders. `from` and `to` are relative to `root`, so a `to` in another directory (such as `../old/main.py`) moves the file. The renames run one at a time, in the order given; a `from` that does not exist is skipped without an error, and a `to` that already exists stops the request with 400.",
                "x-permission": "file.update",
                "parameters": [
                    {
                        "$ref": "#/components/parameters/Server"
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "required": [
                                    "root",
                                    "files"
                                ],
                                "properties": {
                                    "root": {
                                        "type": [
                                            "string",
                                            "null"
                                        ],
                                        "description": "The directory the paths in `files` are relative to. Must be sent; null means `/`."
                                    },
                                    "files": {
                                        "type": "array",
                                        "minItems": 1,
                                        "items": {
                                            "type": "object",
                                            "required": [
                                                "from",
                                                "to"
                                            ],
                                            "properties": {
                                                "from": {
                                                    "type": "string",
                                                    "description": "The current name or path."
                                                },
                                                "to": {
                                                    "type": "string",
                                                    "description": "The new name or path."
                                                }
                                            }
                                        }
                                    }
                                }
                            },
                            "example": {
                                "root": "/",
                                "files": [
                                    {
                                        "from": "bot.py",
                                        "to": "main.py"
                                    },
                                    {
                                        "from": "config.json",
                                        "to": "config/config.json"
                                    }
                                ]
                            }
                        }
                    }
                },
                "responses": {
                    "204": {
                        "$ref": "#/components/responses/NoContent"
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthenticated"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "409": {
                        "$ref": "#/components/responses/Conflict"
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationFailed"
                    }
                }
            }
        },
        "/servers/{server}/files/copy": {
            "post": {
                "operationId": "copyFile",
                "tags": [
                    "Files"
                ],
                "summary": "Copy a file",
                "description": "Makes a copy of a file in the same directory and names it for you: `main.py` becomes `main copy.py`, then `main copy 2.py` and so on. Only files can be copied, not directories. The copy counts towards the server's disk limit.",
                "x-permission": "file.create",
                "parameters": [
                    {
                        "$ref": "#/components/parameters/Server"
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "required": [
                                    "location"
                                ],
                                "properties": {
                                    "location": {
                                        "type": "string",
                                        "description": "The path of the file to copy."
                                    }
                                }
                            },
                            "example": {
                                "location": "/main.py"
                            }
                        }
                    }
                },
                "responses": {
                    "204": {
                        "$ref": "#/components/responses/NoContent"
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthenticated"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "409": {
                        "$ref": "#/components/responses/Conflict"
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationFailed"
                    }
                }
            }
        },
        "/servers/{server}/files/write": {
            "post": {
                "operationId": "writeFile",
                "tags": [
                    "Files"
                ],
                "summary": "Write a file",
                "description": "Creates a file, or replaces an existing one, with the request body. The path goes in the `file` query parameter and the body is the file's raw contents, not JSON; send it as `text/plain` (or `application/octet-stream` for binary data). An empty body empties the file. Missing parent directories are created. The write is recorded in the server's activity log.",
                "x-permission": "file.create",
                "parameters": [
                    {
                        "$ref": "#/components/parameters/Server"
                    },
                    {
                        "name": "file",
                        "in": "query",
                        "required": true,
                        "description": "The path of the file to write.",
                        "schema": {
                            "type": "string"
                        },
                        "example": "/config.json"
                    }
                ],
                "requestBody": {
                    "required": false,
                    "description": "The new contents of the file, sent as they are.",
                    "content": {
                        "text/plain": {
                            "schema": {
                                "type": "string"
                            },
                            "example": "{\"prefix\": \"!\", \"status\": \"online\"}\n"
                        },
                        "application/octet-stream": {
                            "schema": {
                                "type": "string",
                                "format": "binary"
                            }
                        }
                    }
                },
                "responses": {
                    "204": {
                        "$ref": "#/components/responses/NoContent"
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthenticated"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "409": {
                        "$ref": "#/components/responses/Conflict"
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationFailed"
                    }
                }
            }
        },
        "/servers/{server}/files/compress": {
            "post": {
                "operationId": "compressFiles",
                "tags": [
                    "Files"
                ],
                "summary": "Compress files into an archive",
                "description": "Puts the given files and folders into a new `.tar.gz` archive in `root`, named `archive-<date and time>.tar.gz`, and returns the archive's details. The request waits until the archive is finished, which can take several minutes for large folders, so allow a long timeout (the panel waits up to 15 minutes). Answers 409 if the server is out of disk space.",
                "x-permission": "file.archive",
                "parameters": [
                    {
                        "$ref": "#/components/parameters/Server"
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "required": [
                                    "files"
                                ],
                                "properties": {
                                    "root": {
                                        "type": [
                                            "string",
                                            "null"
                                        ],
                                        "description": "The directory the names in `files` are relative to, and where the archive is written. Defaults to `/`."
                                    },
                                    "files": {
                                        "type": "array",
                                        "minItems": 1,
                                        "description": "Names of the files and folders to include.",
                                        "items": {
                                            "type": "string"
                                        }
                                    }
                                }
                            },
                            "example": {
                                "root": "/",
                                "files": [
                                    "src",
                                    "main.py",
                                    "requirements.txt"
                                ]
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "The archive that was made.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/FileObject"
                                },
                                "example": {
                                    "object": "file_object",
                                    "attributes": {
                                        "name": "archive-2026-10-10T120000Z.tar.gz",
                                        "mode": "-rw-r--r--",
                                        "mode_bits": "644",
                                        "size": 48213,
                                        "is_file": true,
                                        "is_symlink": false,
                                        "mimetype": "application/tar+gzip",
                                        "created_at": "2026-10-10T12:00:00+00:00",
                                        "modified_at": "2026-10-10T12:00:00+00:00"
                                    }
                                }
                            }
                        }
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthenticated"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "409": {
                        "$ref": "#/components/responses/Conflict"
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationFailed"
                    }
                }
            }
        },
        "/servers/{server}/files/decompress": {
            "post": {
                "operationId": "decompressFile",
                "tags": [
                    "Files"
                ],
                "summary": "Extract an archive",
                "description": "Unpacks an archive (zip, tar, tar.gz and other common formats) into `root`, overwriting files with the same names. The request waits until extraction is finished, so allow a timeout of several minutes. The node first checks that the unpacked files fit in the server's disk limit. Answers 400 for a format it does not understand, or if a file being overwritten is in use; stop the server and try again.",
                "x-permission": "file.create",
                "parameters": [
                    {
                        "$ref": "#/components/parameters/Server"
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "required": [
                                    "file"
                                ],
                                "properties": {
                                    "root": {
                                        "type": [
                                            "string",
                                            "null"
                                        ],
                                        "description": "The directory holding the archive, which is also where it is unpacked. Defaults to `/`."
                                    },
                                    "file": {
                                        "type": "string",
                                        "description": "The archive's name, relative to `root`."
                                    }
                                }
                            },
                            "example": {
                                "root": "/",
                                "file": "bot.zip"
                            }
                        }
                    }
                },
                "responses": {
                    "204": {
                        "$ref": "#/components/responses/NoContent"
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthenticated"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "409": {
                        "$ref": "#/components/responses/Conflict"
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationFailed"
                    }
                }
            }
        },
        "/servers/{server}/files/delete": {
            "post": {
                "operationId": "deleteFiles",
                "tags": [
                    "Files"
                ],
                "summary": "Delete files",
                "description": "Deletes files and folders, including everything inside the folders. This cannot be undone. If one deletion fails the request stops with an error, and some of the other files may already be gone.",
                "x-permission": "file.delete",
                "parameters": [
                    {
                        "$ref": "#/components/parameters/Server"
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "required": [
                                    "root",
                                    "files"
                                ],
                                "properties": {
                                    "root": {
                                        "type": [
                                            "string",
                                            "null"
                                        ],
                                        "description": "The directory the names in `files` are relative to. Must be sent; null means `/`."
                                    },
                                    "files": {
                                        "type": "array",
                                        "minItems": 1,
                                        "description": "Names of the files and folders to delete.",
                                        "items": {
                                            "type": "string"
                                        }
                                    }
                                }
                            },
                            "example": {
                                "root": "/",
                                "files": [
                                    "__pycache__",
                                    "old_bot.py"
                                ]
                            }
                        }
                    }
                },
                "responses": {
                    "204": {
                        "$ref": "#/components/responses/NoContent"
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthenticated"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "409": {
                        "$ref": "#/components/responses/Conflict"
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationFailed"
                    }
                }
            }
        },
        "/servers/{server}/files/create-folder": {
            "post": {
                "operationId": "createFolder",
                "tags": [
                    "Files"
                ],
                "summary": "Create a folder",
                "description": "Creates a folder called `name` inside `root`. `name` may hold slashes, and any missing folders along the way are created too. Creating a folder that already exists is not an error.",
                "x-permission": "file.create",
                "parameters": [
                    {
                        "$ref": "#/components/parameters/Server"
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "required": [
                                    "name"
                                ],
                                "properties": {
                                    "root": {
                                        "type": "string",
                                        "description": "The directory to create the folder in. Defaults to `/`; leave it out rather than sending null."
                                    },
                                    "name": {
                                        "type": "string",
                                        "description": "The new folder's name."
                                    }
                                }
                            },
                            "example": {
                                "root": "/",
                                "name": "cogs"
                            }
                        }
                    }
                },
                "responses": {
                    "204": {
                        "$ref": "#/components/responses/NoContent"
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthenticated"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "409": {
                        "$ref": "#/components/responses/Conflict"
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationFailed"
                    }
                }
            }
        },
        "/servers/{server}/files/chmod": {
            "post": {
                "operationId": "chmodFiles",
                "tags": [
                    "Files"
                ],
                "summary": "Change file permissions",
                "description": "Sets the Unix permissions of one or more files or folders. Send each `mode` as a string of octal digits, such as `\"755\"`; a JSON number is rejected by the node with 400, and so is a string that is not valid octal. Files that do not exist are skipped without an error.",
                "x-permission": "file.update",
                "parameters": [
                    {
                        "$ref": "#/components/parameters/Server"
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "required": [
                                    "root",
                                    "files"
                                ],
                                "properties": {
                                    "root": {
                                        "type": [
                                            "string",
                                            "null"
                                        ],
                                        "description": "The directory the names in `files` are relative to. Must be sent; null means `/`."
                                    },
                                    "files": {
                                        "type": "array",
                                        "minItems": 1,
                                        "items": {
                                            "type": "object",
                                            "required": [
                                                "file",
                                                "mode"
                                            ],
                                            "properties": {
                                                "file": {
                                                    "type": "string",
                                                    "description": "The file or folder name."
                                                },
                                                "mode": {
                                                    "type": "string",
                                                    "pattern": "^[0-7]{3,4}$",
                                                    "description": "The new permissions in octal, as a string."
                                                }
                                            }
                                        }
                                    }
                                }
                            },
                            "example": {
                                "root": "/",
                                "files": [
                                    {
                                        "file": "start.sh",
                                        "mode": "755"
                                    }
                                ]
                            }
                        }
                    }
                },
                "responses": {
                    "204": {
                        "$ref": "#/components/responses/NoContent"
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthenticated"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "409": {
                        "$ref": "#/components/responses/Conflict"
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationFailed"
                    }
                }
            }
        },
        "/servers/{server}/files/pull": {
            "post": {
                "operationId": "pullFile",
                "tags": [
                    "Files"
                ],
                "summary": "Download a file from a URL onto the server",
                "description": "Has the node download a file from a public `http` or `https` URL into the server's\nfiles. By default the download runs in the background and this request returns at\nonce; set `foreground` to wait until the file is saved, so that failures are\nreported to you.\n\nLimits: 5 requests per 10 minutes per server, shared by everyone using it; at most 3\ndownloads running at once per server; the file must fit in the server's disk limit.\nThe URL must answer `200` with a `Content-Length` header. Redirects are not\nfollowed, and URLs that resolve to private or local addresses (such as 127.0.0.0/8,\n10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16 and 169.254.0.0/16) are refused.\n",
                "x-permission": "file.create",
                "x-rate-limit": "5 per 10 minutes per server",
                "parameters": [
                    {
                        "$ref": "#/components/parameters/Server"
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "required": [
                                    "url"
                                ],
                                "properties": {
                                    "url": {
                                        "type": "string",
                                        "format": "uri",
                                        "description": "The URL to download."
                                    },
                                    "directory": {
                                        "type": [
                                            "string",
                                            "null"
                                        ],
                                        "description": "The directory to save the file in. Defaults to `/`."
                                    },
                                    "filename": {
                                        "type": [
                                            "string",
                                            "null"
                                        ],
                                        "description": "The name to save the file as. Defaults to the last part of the URL's path."
                                    },
                                    "use_header": {
                                        "type": "boolean",
                                        "default": false,
                                        "description": "Name the file from the response's `Content-Disposition` header when it has one, in preference to `filename`."
                                    },
                                    "foreground": {
                                        "type": "boolean",
                                        "default": false,
                                        "description": "Wait for the download to finish before answering, and report a failed download as an error."
                                    }
                                }
                            },
                            "example": {
                                "url": "https://example.com/releases/bot-1.4.0.zip",
                                "directory": "/",
                                "filename": "bot.zip",
                                "foreground": true
                            }
                        }
                    }
                },
                "responses": {
                    "204": {
                        "description": "The download has started, or with `foreground` has finished. There is no response body."
                    },
                    "400": {
                        "description": "The server already has 3 downloads running, is out of disk space, or the URL could not be downloaded (with `foreground`). Also returned if remote downloads are switched off on the node.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                },
                                "example": {
                                    "errors": [
                                        {
                                            "code": "DaemonConnectionException",
                                            "status": "400",
                                            "detail": "An error occurred on the remote host: This server has reached its limit of 3 simultaneous remote file downloads at once. Please wait for one to complete before trying again.. (request id: 6f1c2a9e-1d4b-4c55-9a0e-3b7f8e2d1c40)"
                                        }
                                    ]
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthenticated"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "409": {
                        "$ref": "#/components/responses/Conflict"
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationFailed"
                    },
                    "429": {
                        "$ref": "#/components/responses/TooManyRequests"
                    }
                }
            }
        },
        "/servers/{server}/files/upload": {
            "get": {
                "operationId": "getFileUploadUrl",
                "tags": [
                    "Files"
                ],
                "summary": "Get an upload link",
                "description": "Returns a signed URL on the server's node that files can be uploaded to. This is step\none of two: then `POST` to the returned URL, with no API key, a\n`multipart/form-data` body with one or more files in the field named `files`. Add a\n`directory` query parameter to the URL (for example `&directory=/cogs`) to upload\nsomewhere other than `/`. The node answers 200 with an empty body when the upload is\nsaved.\n\nThe URL works once and expires 15 minutes after it is made. Each file may be up to\nthe node's upload limit. Errors from the\nnode come as `{\"error\": \"...\"}`, not the panel's error format. Folders cannot be\nuploaded this way; upload an archive and use `decompressFile`.\n",
                "x-permission": "file.create",
                "parameters": [
                    {
                        "$ref": "#/components/parameters/Server"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "A single-use upload link, valid for 15 minutes.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/FileSignedUrl"
                                },
                                "example": {
                                    "object": "signed_url",
                                    "attributes": {
                                        "url": "https://node1.sillydev.co.uk:8080/upload/file?token=eyJhbGciOi..."
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthenticated"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "409": {
                        "$ref": "#/components/responses/Conflict"
                    }
                }
            }
        },
        "/servers/{server}/files/git": {
            "get": {
                "operationId": "getFileGitNotice",
                "tags": [
                    "Files"
                ],
                "summary": "Check whether files are deployed from Git",
                "description": "Says whether a Git repository is linked to the server, so a file editor can warn that changes in the deploy directory may be overwritten by the next deploy. It only needs `file.read` and so deliberately leaves out the repository, branch and account; read the server's Git settings for those, which needs the Git permissions. This is not a plain JSON envelope: it is a bare object.",
                "x-permission": "file.read",
                "parameters": [
                    {
                        "$ref": "#/components/parameters/Server"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Whether a repository is linked, and if so where it deploys.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/FileGitNotice"
                                },
                                "examples": {
                                    "linked": {
                                        "summary": "A repository is linked",
                                        "value": {
                                            "linked": true,
                                            "provider": "github",
                                            "directory": "/",
                                            "auto_deploy": true
                                        }
                                    },
                                    "notLinked": {
                                        "summary": "No repository is linked",
                                        "value": {
                                            "linked": false
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthenticated"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "409": {
                        "$ref": "#/components/responses/Conflict"
                    }
                }
            }
        },
        "/servers/{server}/backups": {
            "get": {
                "operationId": "listBackups",
                "tags": [
                    "Backups"
                ],
                "summary": "List backups",
                "description": "Returns the server's backups in the order they were made, including ones still in progress and ones that failed. `meta.backup_count` is how many count towards the backup limit, that is every backup that has not failed.",
                "x-permission": "backup.read",
                "parameters": [
                    {
                        "$ref": "#/components/parameters/Server"
                    },
                    {
                        "$ref": "#/components/parameters/Page"
                    },
                    {
                        "name": "per_page",
                        "in": "query",
                        "required": false,
                        "description": "How many backups to return on each page. Values above 50 are treated as 50.",
                        "schema": {
                            "type": "integer",
                            "minimum": 1,
                            "maximum": 50,
                            "default": 20
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "A page of backups.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/BackupList"
                                },
                                "example": {
                                    "object": "list",
                                    "data": [
                                        {
                                            "object": "backup",
                                            "attributes": {
                                                "uuid": "0f2a6c1e-8d3b-4f7a-9c5e-2b1d4e6f8a90",
                                                "is_successful": true,
                                                "is_locked": false,
                                                "name": "Before discord.py upgrade",
                                                "ignored_files": [
                                                    "node_modules",
                                                    "*.log"
                                                ],
                                                "checksum": "sha1:3f786850e387550fdab836ed7e6dc881de23001b",
                                                "bytes": 5242880,
                                                "created_at": "2026-10-10T12:00:00+00:00",
                                                "completed_at": "2026-10-10T12:00:41+00:00"
                                            }
                                        }
                                    ],
                                    "meta": {
                                        "pagination": {
                                            "total": 1,
                                            "count": 1,
                                            "per_page": 20,
                                            "current_page": 1,
                                            "total_pages": 1,
                                            "links": []
                                        },
                                        "backup_count": 1
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthenticated"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "409": {
                        "$ref": "#/components/responses/Conflict"
                    }
                }
            },
            "post": {
                "operationId": "createBackup",
                "tags": [
                    "Backups"
                ],
                "summary": "Start a backup",
                "description": "Starts a backup of the server's files and returns it at once, still in progress\n(`completed_at` is null). The server keeps running while it is backed up.\n\nAnswers 400 when the server has reached its backup limit (delete an old backup\nfirst) and 429 when it has already started 2 backups in the last 10 minutes; deleted\nbackups still count towards that. `is_locked` is only applied if you also have the\n`backup.delete` permission, and is ignored otherwise.\n",
                "x-permission": "backup.create",
                "x-rate-limit": "2 backups per 10 minutes per server",
                "parameters": [
                    {
                        "$ref": "#/components/parameters/Server"
                    }
                ],
                "requestBody": {
                    "required": false,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "name": {
                                        "type": [
                                            "string",
                                            "null"
                                        ],
                                        "maxLength": 191,
                                        "description": "A name for the backup. Defaults to `Backup at <date and time>`."
                                    },
                                    "is_locked": {
                                        "type": [
                                            "boolean",
                                            "null"
                                        ],
                                        "default": false,
                                        "description": "Lock the backup so it cannot be deleted until it is unlocked. Needs the `backup.delete` permission."
                                    },
                                    "ignored": {
                                        "type": [
                                            "string",
                                            "null"
                                        ],
                                        "description": "Files and folders to leave out, one pattern per line in `.gitignore` syntax. At most 32 KiB, 256 patterns and 16 `*` wildcards per pattern. When empty, the node uses the `.backupignore` file in the server's root, if there is one."
                                    }
                                }
                            },
                            "example": {
                                "name": "Before discord.py upgrade",
                                "is_locked": false,
                                "ignored": "node_modules\n*.log"
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "The backup, now in progress.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Backup"
                                },
                                "example": {
                                    "object": "backup",
                                    "attributes": {
                                        "uuid": "0f2a6c1e-8d3b-4f7a-9c5e-2b1d4e6f8a90",
                                        "is_successful": false,
                                        "is_locked": false,
                                        "name": "Before discord.py upgrade",
                                        "ignored_files": [
                                            "node_modules",
                                            "*.log"
                                        ],
                                        "checksum": null,
                                        "bytes": 0,
                                        "created_at": "2026-10-10T12:00:00+00:00",
                                        "completed_at": null
                                    }
                                }
                            }
                        }
                    },
                    "400": {
                        "description": "The server has reached its backup limit, or the node refused the ignore list.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                },
                                "example": {
                                    "errors": [
                                        {
                                            "code": "TooManyBackupsException",
                                            "status": "400",
                                            "detail": "Cannot create a new backup, this server has reached its limit of 3 backups."
                                        }
                                    ]
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthenticated"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "409": {
                        "$ref": "#/components/responses/Conflict"
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationFailed"
                    },
                    "429": {
                        "$ref": "#/components/responses/TooManyRequests"
                    }
                }
            }
        },
        "/servers/{server}/backups/{backup}": {
            "parameters": [
                {
                    "$ref": "#/components/parameters/Server"
                },
                {
                    "name": "backup",
                    "in": "path",
                    "required": true,
                    "description": "The backup's UUID, as `uuid` in the backup's attributes.",
                    "schema": {
                        "type": "string",
                        "format": "uuid"
                    },
                    "example": "0f2a6c1e-8d3b-4f7a-9c5e-2b1d4e6f8a90"
                }
            ],
            "get": {
                "operationId": "getBackup",
                "tags": [
                    "Backups"
                ],
                "summary": "Get a backup",
                "description": "Returns one backup. Poll this to see when a backup in progress finishes: `completed_at` is set and `is_successful` says whether it worked.",
                "x-permission": "backup.read",
                "responses": {
                    "200": {
                        "description": "The backup.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Backup"
                                },
                                "example": {
                                    "object": "backup",
                                    "attributes": {
                                        "uuid": "0f2a6c1e-8d3b-4f7a-9c5e-2b1d4e6f8a90",
                                        "is_successful": true,
                                        "is_locked": true,
                                        "name": "Before discord.py upgrade",
                                        "ignored_files": [
                                            "node_modules",
                                            "*.log"
                                        ],
                                        "checksum": "sha1:3f786850e387550fdab836ed7e6dc881de23001b",
                                        "bytes": 5242880,
                                        "created_at": "2026-10-10T12:00:00+00:00",
                                        "completed_at": "2026-10-10T12:00:41+00:00"
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthenticated"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "409": {
                        "$ref": "#/components/responses/Conflict"
                    }
                }
            },
            "delete": {
                "operationId": "deleteBackup",
                "tags": [
                    "Backups"
                ],
                "summary": "Delete a backup",
                "description": "Deletes a backup and its archive. This cannot be undone. A locked backup that completed successfully cannot be deleted (400) until it is unlocked with `toggleBackupLock`; failed backups can always be deleted.",
                "x-permission": "backup.delete",
                "responses": {
                    "204": {
                        "$ref": "#/components/responses/NoContent"
                    },
                    "400": {
                        "description": "The backup is locked.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                },
                                "example": {
                                    "errors": [
                                        {
                                            "code": "BackupLockedException",
                                            "status": "400",
                                            "detail": "Cannot delete a backup that is marked as locked."
                                        }
                                    ]
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthenticated"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "409": {
                        "$ref": "#/components/responses/Conflict"
                    }
                }
            }
        },
        "/servers/{server}/backups/{backup}/download": {
            "get": {
                "operationId": "getBackupDownloadUrl",
                "tags": [
                    "Backups"
                ],
                "summary": "Get a download link for a backup",
                "description": "Returns a signed URL from which the backup's `.tar.gz` archive can be downloaded.\nThis is step one of two: then send a plain `GET` to the returned URL, with no API\nkey. For backups kept on the node, the URL is on the node, works once and expires\nafter 15 minutes. For backups kept in S3 storage, it is a pre-signed S3 URL that\nexpires after 5 minutes.\n\nOnly ask for the link once the backup has completed successfully. Asking for it is\nrecorded in the server's activity log.\n",
                "x-permission": "backup.download",
                "parameters": [
                    {
                        "$ref": "#/components/parameters/Server"
                    },
                    {
                        "name": "backup",
                        "in": "path",
                        "required": true,
                        "description": "The backup's UUID, as `uuid` in the backup's attributes.",
                        "schema": {
                            "type": "string",
                            "format": "uuid"
                        },
                        "example": "0f2a6c1e-8d3b-4f7a-9c5e-2b1d4e6f8a90"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "A download link for the backup.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/BackupSignedUrl"
                                },
                                "example": {
                                    "object": "signed_url",
                                    "attributes": {
                                        "url": "https://node1.sillydev.co.uk:8080/download/backup?token=eyJhbGciOi..."
                                    }
                                }
                            }
                        }
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthenticated"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "409": {
                        "$ref": "#/components/responses/Conflict"
                    }
                }
            }
        },
        "/servers/{server}/backups/{backup}/lock": {
            "post": {
                "operationId": "toggleBackupLock",
                "tags": [
                    "Backups"
                ],
                "summary": "Lock or unlock a backup",
                "description": "Flips the backup's lock: a locked backup becomes unlocked and an unlocked one becomes locked. A locked backup cannot be deleted. There is no body; read `is_locked` in the response to see the new state.",
                "x-permission": "backup.delete",
                "parameters": [
                    {
                        "$ref": "#/components/parameters/Server"
                    },
                    {
                        "name": "backup",
                        "in": "path",
                        "required": true,
                        "description": "The backup's UUID, as `uuid` in the backup's attributes.",
                        "schema": {
                            "type": "string",
                            "format": "uuid"
                        },
                        "example": "0f2a6c1e-8d3b-4f7a-9c5e-2b1d4e6f8a90"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "The backup with its new lock state.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Backup"
                                },
                                "example": {
                                    "object": "backup",
                                    "attributes": {
                                        "uuid": "0f2a6c1e-8d3b-4f7a-9c5e-2b1d4e6f8a90",
                                        "is_successful": true,
                                        "is_locked": true,
                                        "name": "Before discord.py upgrade",
                                        "ignored_files": [
                                            "node_modules",
                                            "*.log"
                                        ],
                                        "checksum": "sha1:3f786850e387550fdab836ed7e6dc881de23001b",
                                        "bytes": 5242880,
                                        "created_at": "2026-10-10T12:00:00+00:00",
                                        "completed_at": "2026-10-10T12:00:41+00:00"
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthenticated"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "409": {
                        "$ref": "#/components/responses/Conflict"
                    }
                }
            }
        },
        "/servers/{server}/backups/{backup}/restore": {
            "post": {
                "operationId": "restoreBackup",
                "tags": [
                    "Backups"
                ],
                "summary": "Restore a backup",
                "description": "Restores the backup's files over the server's files. The request returns at once and\nthe restore runs on the node: the server is stopped, its files are deleted first if\n`truncate` is true, and the archive is unpacked. Without `truncate`, files that are\nnot in the backup are left as they are and files that are in it are overwritten.\n\nWhile the restore runs, the server's other endpoints answer 409. Only a backup that\ncompleted successfully can be restored (400 otherwise). Limited to 3 restores per 15\nminutes per server, shared by everyone using it.\n",
                "x-permission": "backup.restore",
                "x-rate-limit": "3 per 15 minutes per server",
                "parameters": [
                    {
                        "$ref": "#/components/parameters/Server"
                    },
                    {
                        "name": "backup",
                        "in": "path",
                        "required": true,
                        "description": "The backup's UUID, as `uuid` in the backup's attributes.",
                        "schema": {
                            "type": "string",
                            "format": "uuid"
                        },
                        "example": "0f2a6c1e-8d3b-4f7a-9c5e-2b1d4e6f8a90"
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "required": [
                                    "truncate"
                                ],
                                "properties": {
                                    "truncate": {
                                        "type": "boolean",
                                        "description": "Delete all of the server's files before restoring, so the result matches the backup exactly."
                                    }
                                }
                            },
                            "example": {
                                "truncate": true
                            }
                        }
                    }
                },
                "responses": {
                    "204": {
                        "description": "The restore has started. There is no response body."
                    },
                    "400": {
                        "description": "The backup is still in progress or failed, or the server is not in a state that allows a restore.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                },
                                "example": {
                                    "errors": [
                                        {
                                            "code": "BadRequestHttpException",
                                            "status": "400",
                                            "detail": "This backup cannot be restored at this time: not completed or failed."
                                        }
                                    ]
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthenticated"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "409": {
                        "$ref": "#/components/responses/Conflict"
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationFailed"
                    },
                    "429": {
                        "$ref": "#/components/responses/TooManyRequests"
                    }
                }
            }
        },
        "/servers/{server}/schedules": {
            "parameters": [
                {
                    "$ref": "#/components/parameters/Server"
                }
            ],
            "get": {
                "operationId": "listSchedules",
                "tags": [
                    "Schedules"
                ],
                "summary": "List schedules",
                "description": "Returns every schedule on the server, each with its tasks in `attributes.relationships.tasks`. The list is not paginated.",
                "x-permission": "schedule.read",
                "responses": {
                    "200": {
                        "description": "The server's schedules.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/ScheduleList"
                                },
                                "example": {
                                    "object": "list",
                                    "data": [
                                        {
                                            "object": "server_schedule",
                                            "attributes": {
                                                "id": 12,
                                                "name": "Nightly restart",
                                                "cron": {
                                                    "day_of_week": "*",
                                                    "day_of_month": "*",
                                                    "month": "*",
                                                    "hour": "4",
                                                    "minute": "0"
                                                },
                                                "is_active": true,
                                                "is_processing": false,
                                                "only_when_online": true,
                                                "last_run_at": "2026-10-10T04:00:00+00:00",
                                                "next_run_at": "2026-10-11T04:00:00+00:00",
                                                "created_at": "2026-09-01T12:00:00+00:00",
                                                "updated_at": "2026-10-10T04:00:03+00:00",
                                                "relationships": {
                                                    "tasks": {
                                                        "object": "list",
                                                        "data": [
                                                            {
                                                                "object": "schedule_task",
                                                                "attributes": {
                                                                    "id": 31,
                                                                    "sequence_id": 1,
                                                                    "action": "command",
                                                                    "payload": "say Restarting in 1 minute",
                                                                    "time_offset": 0,
                                                                    "is_queued": false,
                                                                    "continue_on_failure": false,
                                                                    "created_at": "2026-09-01T12:00:00+00:00",
                                                                    "updated_at": "2026-09-01T12:00:00+00:00"
                                                                }
                                                            },
                                                            {
                                                                "object": "schedule_task",
                                                                "attributes": {
                                                                    "id": 32,
                                                                    "sequence_id": 2,
                                                                    "action": "power",
                                                                    "payload": "restart",
                                                                    "time_offset": 60,
                                                                    "is_queued": false,
                                                                    "continue_on_failure": false,
                                                                    "created_at": "2026-09-01T12:00:00+00:00",
                                                                    "updated_at": "2026-09-01T12:00:00+00:00"
                                                                }
                                                            }
                                                        ]
                                                    }
                                                }
                                            }
                                        }
                                    ]
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthenticated"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    }
                }
            },
            "post": {
                "operationId": "createSchedule",
                "tags": [
                    "Schedules"
                ],
                "summary": "Create a schedule",
                "description": "Creates a schedule with no tasks; add them with `createScheduleTask`. The five cron fields are evaluated in the panel's timezone and must together make a valid cron expression. `is_active` and `only_when_online` are false when left out, so send `is_active: true` for the schedule to run. New schedules are limited to 2 a minute per server, shared by everyone managing that server.",
                "x-permission": "schedule.create",
                "x-rate-limit": "2 per minute per server",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/ScheduleRequest"
                            },
                            "example": {
                                "name": "Nightly restart",
                                "minute": "0",
                                "hour": "4",
                                "day_of_month": "*",
                                "month": "*",
                                "day_of_week": "*",
                                "is_active": true,
                                "only_when_online": true
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "The new schedule.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Schedule"
                                },
                                "example": {
                                    "object": "server_schedule",
                                    "attributes": {
                                        "id": 12,
                                        "name": "Nightly restart",
                                        "cron": {
                                            "day_of_week": "*",
                                            "day_of_month": "*",
                                            "month": "*",
                                            "hour": "4",
                                            "minute": "0"
                                        },
                                        "is_active": true,
                                        "is_processing": false,
                                        "only_when_online": true,
                                        "last_run_at": null,
                                        "next_run_at": "2026-10-11T04:00:00+00:00",
                                        "created_at": "2026-10-10T12:00:00+00:00",
                                        "updated_at": "2026-10-10T12:00:00+00:00",
                                        "relationships": {
                                            "tasks": {
                                                "object": "list",
                                                "data": []
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "400": {
                        "description": "The cron fields do not make a valid cron expression.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                },
                                "example": {
                                    "errors": [
                                        {
                                            "code": "DisplayException",
                                            "status": "400",
                                            "detail": "The cron data provided does not evaluate to a valid expression."
                                        }
                                    ]
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthenticated"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationFailed"
                    },
                    "429": {
                        "$ref": "#/components/responses/TooManyRequests"
                    }
                }
            }
        },
        "/servers/{server}/schedules/{schedule}": {
            "parameters": [
                {
                    "$ref": "#/components/parameters/Server"
                },
                {
                    "name": "schedule",
                    "in": "path",
                    "required": true,
                    "description": "The schedule's numeric ID.",
                    "schema": {
                        "type": "integer"
                    },
                    "example": 12
                }
            ],
            "get": {
                "operationId": "getSchedule",
                "tags": [
                    "Schedules"
                ],
                "summary": "Get a schedule",
                "description": "Returns one schedule with its tasks in `attributes.relationships.tasks`.",
                "x-permission": "schedule.read",
                "responses": {
                    "200": {
                        "description": "The schedule.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Schedule"
                                },
                                "example": {
                                    "object": "server_schedule",
                                    "attributes": {
                                        "id": 12,
                                        "name": "Nightly restart",
                                        "cron": {
                                            "day_of_week": "*",
                                            "day_of_month": "*",
                                            "month": "*",
                                            "hour": "4",
                                            "minute": "0"
                                        },
                                        "is_active": true,
                                        "is_processing": false,
                                        "only_when_online": true,
                                        "last_run_at": "2026-10-10T04:00:00+00:00",
                                        "next_run_at": "2026-10-11T04:00:00+00:00",
                                        "created_at": "2026-09-01T12:00:00+00:00",
                                        "updated_at": "2026-10-10T04:00:03+00:00",
                                        "relationships": {
                                            "tasks": {
                                                "object": "list",
                                                "data": [
                                                    {
                                                        "object": "schedule_task",
                                                        "attributes": {
                                                            "id": 32,
                                                            "sequence_id": 1,
                                                            "action": "power",
                                                            "payload": "restart",
                                                            "time_offset": 0,
                                                            "is_queued": false,
                                                            "continue_on_failure": false,
                                                            "created_at": "2026-09-01T12:00:00+00:00",
                                                            "updated_at": "2026-09-01T12:00:00+00:00"
                                                        }
                                                    }
                                                ]
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthenticated"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    }
                }
            },
            "post": {
                "operationId": "updateSchedule",
                "tags": [
                    "Schedules"
                ],
                "summary": "Update a schedule",
                "description": "Replaces the schedule's name, cron fields and switches; send every field, as with `createSchedule`. Leaving out `is_active` or `only_when_online` sets it to false. Turning a schedule on or off also clears a stuck `is_processing` flag. Tasks are not changed.",
                "x-permission": "schedule.update",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/ScheduleRequest"
                            },
                            "example": {
                                "name": "Nightly restart",
                                "minute": "30",
                                "hour": "3",
                                "day_of_month": "*",
                                "month": "*",
                                "day_of_week": "1-5",
                                "is_active": true,
                                "only_when_online": true
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "The updated schedule.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Schedule"
                                },
                                "example": {
                                    "object": "server_schedule",
                                    "attributes": {
                                        "id": 12,
                                        "name": "Nightly restart",
                                        "cron": {
                                            "day_of_week": "1-5",
                                            "day_of_month": "*",
                                            "month": "*",
                                            "hour": "3",
                                            "minute": "30"
                                        },
                                        "is_active": true,
                                        "is_processing": false,
                                        "only_when_online": true,
                                        "last_run_at": "2026-10-10T04:00:00+00:00",
                                        "next_run_at": "2026-10-12T03:30:00+00:00",
                                        "created_at": "2026-09-01T12:00:00+00:00",
                                        "updated_at": "2026-10-10T12:00:00+00:00",
                                        "relationships": {
                                            "tasks": {
                                                "object": "list",
                                                "data": []
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "400": {
                        "description": "The cron fields do not make a valid cron expression.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                },
                                "example": {
                                    "errors": [
                                        {
                                            "code": "DisplayException",
                                            "status": "400",
                                            "detail": "The cron data provided does not evaluate to a valid expression."
                                        }
                                    ]
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthenticated"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationFailed"
                    }
                }
            },
            "delete": {
                "operationId": "deleteSchedule",
                "tags": [
                    "Schedules"
                ],
                "summary": "Delete a schedule",
                "description": "Deletes the schedule and all of its tasks.",
                "x-permission": "schedule.delete",
                "responses": {
                    "204": {
                        "$ref": "#/components/responses/NoContent"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthenticated"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    }
                }
            }
        },
        "/servers/{server}/schedules/{schedule}/execute": {
            "parameters": [
                {
                    "$ref": "#/components/parameters/Server"
                },
                {
                    "name": "schedule",
                    "in": "path",
                    "required": true,
                    "description": "The schedule's numeric ID.",
                    "schema": {
                        "type": "integer"
                    },
                    "example": 12
                }
            ],
            "post": {
                "operationId": "runSchedule",
                "tags": [
                    "Schedules"
                ],
                "summary": "Run a schedule now",
                "description": "Runs the schedule straight away, whether or not it is active and ignoring `only_when_online`. The first task runs during the request, without waiting its `time_offset`; the rest follow in the background as usual. Command tasks are skipped if the server is offline. A schedule with no tasks cannot be run.",
                "x-permission": "schedule.update",
                "responses": {
                    "202": {
                        "description": "The schedule has started. The body is an empty JSON array.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "array",
                                    "maxItems": 0
                                },
                                "example": []
                            }
                        }
                    },
                    "400": {
                        "description": "The schedule has no tasks.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                },
                                "example": {
                                    "errors": [
                                        {
                                            "code": "DisplayException",
                                            "status": "400",
                                            "detail": "Cannot process schedule for task execution: no tasks are registered."
                                        }
                                    ]
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthenticated"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    }
                }
            }
        },
        "/servers/{server}/schedules/{schedule}/tasks": {
            "parameters": [
                {
                    "$ref": "#/components/parameters/Server"
                },
                {
                    "name": "schedule",
                    "in": "path",
                    "required": true,
                    "description": "The schedule's numeric ID.",
                    "schema": {
                        "type": "integer"
                    },
                    "example": 12
                }
            ],
            "post": {
                "operationId": "createScheduleTask",
                "tags": [
                    "Schedules"
                ],
                "summary": "Add a task to a schedule",
                "description": "Adds a task to the schedule, at the end or at `sequence_id` (later tasks move down one). Besides `schedule.update` you need the permission for what the task does: `control.console` for a command, `backup.create` for a backup, and `control.start`, `control.stop` or `control.restart` for a power action (`kill` needs `control.stop`). A schedule may hold at most 10 tasks, and a backup task cannot be added to a server that may not keep backups.",
                "x-permission": [
                    "schedule.update",
                    "control.console",
                    "control.start",
                    "control.stop",
                    "control.restart",
                    "backup.create"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/ScheduleTaskRequest"
                            },
                            "examples": {
                                "command": {
                                    "summary": "Send a console command",
                                    "value": {
                                        "action": "command",
                                        "payload": "say Restarting in 1 minute",
                                        "time_offset": 0
                                    }
                                },
                                "power": {
                                    "summary": "Restart the server a minute later",
                                    "value": {
                                        "action": "power",
                                        "payload": "restart",
                                        "time_offset": 60,
                                        "continue_on_failure": false
                                    }
                                },
                                "backup": {
                                    "summary": "Take a backup, leaving out node_modules and logs",
                                    "value": {
                                        "action": "backup",
                                        "payload": "node_modules\nlogs/*.log",
                                        "time_offset": 0
                                    }
                                }
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "The new task.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/ScheduleTask"
                                },
                                "example": {
                                    "object": "schedule_task",
                                    "attributes": {
                                        "id": 32,
                                        "sequence_id": 2,
                                        "action": "power",
                                        "payload": "restart",
                                        "time_offset": 60,
                                        "is_queued": false,
                                        "continue_on_failure": false,
                                        "created_at": "2026-10-10T12:00:00+00:00",
                                        "updated_at": "2026-10-10T12:00:00+00:00"
                                    }
                                }
                            }
                        }
                    },
                    "400": {
                        "description": "The schedule already has as many tasks as it may.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                },
                                "example": {
                                    "errors": [
                                        {
                                            "code": "ServiceLimitExceededException",
                                            "status": "400",
                                            "detail": "Schedules may not have more than 10 tasks associated with them. Creating this task would put this schedule over the limit."
                                        }
                                    ]
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthenticated"
                    },
                    "403": {
                        "description": "The key lacks `schedule.update` or the permission for the task's action, or this is a backup task and the server's backup limit is 0.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                },
                                "example": {
                                    "errors": [
                                        {
                                            "code": "HttpForbiddenException",
                                            "status": "403",
                                            "detail": "A backup task cannot be created when the server's backup limit is set to 0."
                                        }
                                    ]
                                }
                            }
                        }
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationFailed"
                    }
                }
            }
        },
        "/servers/{server}/schedules/{schedule}/tasks/{task}": {
            "parameters": [
                {
                    "$ref": "#/components/parameters/Server"
                },
                {
                    "name": "schedule",
                    "in": "path",
                    "required": true,
                    "description": "The schedule's numeric ID.",
                    "schema": {
                        "type": "integer"
                    },
                    "example": 12
                },
                {
                    "name": "task",
                    "in": "path",
                    "required": true,
                    "description": "The task's numeric ID, which must belong to the schedule.",
                    "schema": {
                        "type": "integer"
                    },
                    "example": 32
                }
            ],
            "post": {
                "operationId": "updateScheduleTask",
                "tags": [
                    "Schedules"
                ],
                "summary": "Update a task",
                "description": "Replaces the task's action, payload, offset and failure setting; leaving out `continue_on_failure` sets it to false. Send `sequence_id` to move the task, and the tasks in between shift to make room. The same action permissions apply as for `createScheduleTask`.",
                "x-permission": [
                    "schedule.update",
                    "control.console",
                    "control.start",
                    "control.stop",
                    "control.restart",
                    "backup.create"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/ScheduleTaskRequest"
                            },
                            "example": {
                                "action": "command",
                                "payload": "say Restarting in 5 minutes",
                                "time_offset": 0,
                                "sequence_id": 1
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "The updated task.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/ScheduleTask"
                                },
                                "example": {
                                    "object": "schedule_task",
                                    "attributes": {
                                        "id": 31,
                                        "sequence_id": 1,
                                        "action": "command",
                                        "payload": "say Restarting in 5 minutes",
                                        "time_offset": 0,
                                        "is_queued": false,
                                        "continue_on_failure": false,
                                        "created_at": "2026-09-01T12:00:00+00:00",
                                        "updated_at": "2026-10-10T12:00:00+00:00"
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthenticated"
                    },
                    "403": {
                        "description": "The key lacks `schedule.update` or the permission for the task's action, or this is a backup task and the server's backup limit is 0.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationFailed"
                    }
                }
            },
            "delete": {
                "operationId": "deleteScheduleTask",
                "tags": [
                    "Schedules"
                ],
                "summary": "Delete a task",
                "description": "Deletes the task. Tasks after it move up one place.",
                "x-permission": "schedule.update",
                "responses": {
                    "204": {
                        "$ref": "#/components/responses/NoContent"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthenticated"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    }
                }
            }
        },
        "/servers/{server}/network/allocations": {
            "parameters": [
                {
                    "$ref": "#/components/parameters/Server"
                }
            ],
            "get": {
                "operationId": "listAllocations",
                "tags": [
                    "Network"
                ],
                "summary": "List allocations",
                "description": "Returns every IP and port assigned to the server. `is_default` marks the primary one, which the server listens on by default. The list is not paginated.",
                "x-permission": "allocation.read",
                "responses": {
                    "200": {
                        "description": "The server's allocations.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/AllocationList"
                                },
                                "example": {
                                    "object": "list",
                                    "data": [
                                        {
                                            "object": "allocation",
                                            "attributes": {
                                                "id": 501,
                                                "ip": "203.0.113.10",
                                                "ip_alias": "node1.sillydev.co.uk",
                                                "port": 25565,
                                                "notes": null,
                                                "is_default": true
                                            }
                                        },
                                        {
                                            "object": "allocation",
                                            "attributes": {
                                                "id": 502,
                                                "ip": "203.0.113.10",
                                                "ip_alias": "node1.sillydev.co.uk",
                                                "port": 25566,
                                                "notes": "Web dashboard",
                                                "is_default": false
                                            }
                                        }
                                    ]
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthenticated"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    }
                }
            },
            "post": {
                "operationId": "createAllocation",
                "tags": [
                    "Network"
                ],
                "summary": "Add an allocation",
                "description": "Assigns another port on the same IP as the server's primary allocation, picking a free one at random. This only works where an administrator has switched on automatic allocations and given the server an allocation limit; otherwise it fails with a 400. Limited to 2 a minute per server, shared by everyone managing that server.",
                "x-permission": "allocation.create",
                "x-rate-limit": "2 per minute per server",
                "responses": {
                    "200": {
                        "description": "The new allocation.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Allocation"
                                },
                                "example": {
                                    "object": "allocation",
                                    "attributes": {
                                        "id": 502,
                                        "ip": "203.0.113.10",
                                        "ip_alias": "node1.sillydev.co.uk",
                                        "port": 25566,
                                        "notes": null,
                                        "is_default": false
                                    }
                                }
                            }
                        }
                    },
                    "400": {
                        "description": "Automatic allocations are switched off, the server is at its allocation limit (or has none), or there are no free ports left in the range.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                },
                                "example": {
                                    "errors": [
                                        {
                                            "code": "DisplayException",
                                            "status": "400",
                                            "detail": "Cannot assign additional allocations to this server: limit has been reached."
                                        }
                                    ]
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthenticated"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "429": {
                        "$ref": "#/components/responses/TooManyRequests"
                    }
                }
            }
        },
        "/servers/{server}/network/allocations/{allocation}": {
            "parameters": [
                {
                    "$ref": "#/components/parameters/Server"
                },
                {
                    "name": "allocation",
                    "in": "path",
                    "required": true,
                    "description": "The allocation's numeric ID, from `listAllocations`.",
                    "schema": {
                        "type": "integer"
                    },
                    "example": 502
                }
            ],
            "post": {
                "operationId": "updateAllocationNotes",
                "tags": [
                    "Network"
                ],
                "summary": "Set an allocation's notes",
                "description": "Sets the free-text notes shown next to the allocation in the panel. `notes` must be sent; send null to clear them.",
                "x-permission": "allocation.update",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/AllocationNotesRequest"
                            },
                            "example": {
                                "notes": "Web dashboard"
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "The updated allocation.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Allocation"
                                },
                                "example": {
                                    "object": "allocation",
                                    "attributes": {
                                        "id": 502,
                                        "ip": "203.0.113.10",
                                        "ip_alias": "node1.sillydev.co.uk",
                                        "port": 25566,
                                        "notes": "Web dashboard",
                                        "is_default": false
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthenticated"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationFailed"
                    }
                }
            },
            "delete": {
                "operationId": "deleteAllocation",
                "tags": [
                    "Network"
                ],
                "summary": "Remove an allocation",
                "description": "Takes the allocation away from the server and clears its notes. The primary allocation cannot be removed, and nothing can be removed from a server without an allocation limit.",
                "x-permission": "allocation.delete",
                "responses": {
                    "204": {
                        "$ref": "#/components/responses/NoContent"
                    },
                    "400": {
                        "description": "This is the primary allocation, or the server has no allocation limit.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                },
                                "example": {
                                    "errors": [
                                        {
                                            "code": "DisplayException",
                                            "status": "400",
                                            "detail": "You cannot delete the primary allocation for this server."
                                        }
                                    ]
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthenticated"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    }
                }
            }
        },
        "/servers/{server}/network/allocations/{allocation}/primary": {
            "parameters": [
                {
                    "$ref": "#/components/parameters/Server"
                },
                {
                    "name": "allocation",
                    "in": "path",
                    "required": true,
                    "description": "The allocation's numeric ID, from `listAllocations`.",
                    "schema": {
                        "type": "integer"
                    },
                    "example": 502
                }
            ],
            "post": {
                "operationId": "setPrimaryAllocation",
                "tags": [
                    "Network"
                ],
                "summary": "Make an allocation the primary one",
                "description": "Makes this allocation the server's primary (default) one. The server picks up the new primary port the next time it starts.",
                "x-permission": "allocation.update",
                "responses": {
                    "200": {
                        "description": "The allocation, now the primary one.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Allocation"
                                },
                                "example": {
                                    "object": "allocation",
                                    "attributes": {
                                        "id": 502,
                                        "ip": "203.0.113.10",
                                        "ip_alias": "node1.sillydev.co.uk",
                                        "port": 25566,
                                        "notes": "Web dashboard",
                                        "is_default": true
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthenticated"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    }
                }
            }
        },
        "/servers/{server}/users": {
            "parameters": [
                {
                    "$ref": "#/components/parameters/Server"
                }
            ],
            "get": {
                "operationId": "listSubusers",
                "tags": [
                    "Subusers"
                ],
                "summary": "List subusers",
                "description": "Returns every subuser of the server with their permissions. The server's owner is not listed. The list is not paginated.",
                "x-permission": "user.read",
                "responses": {
                    "200": {
                        "description": "The server's subusers.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/SubuserList"
                                },
                                "example": {
                                    "object": "list",
                                    "data": [
                                        {
                                            "object": "server_subuser",
                                            "attributes": {
                                                "uuid": "5f0c2d8e-3b1a-4c7d-9e2f-6a8b0c1d2e3f",
                                                "identifier": "user_l4gc3dr3djgh3hrpnkfqyhjoh4",
                                                "username": "friend",
                                                "email": "friend@example.com",
                                                "image": "https://www.gravatar.com/avatar/0f2c9a7e4b1d8c6a3e5f7b9d1c3e5a7b9d1f3a5c7e9b1d3f5a7c9e1b3d5f7a9c?d=404",
                                                "2fa_enabled": false,
                                                "created_at": "2026-09-15T18:30:00+00:00",
                                                "permissions": [
                                                    "websocket.connect",
                                                    "control.console",
                                                    "control.restart",
                                                    "file.read",
                                                    "file.read-content"
                                                ]
                                            }
                                        }
                                    ]
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthenticated"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    }
                }
            },
            "post": {
                "operationId": "createSubuser",
                "tags": [
                    "Subusers"
                ],
                "summary": "Add a subuser",
                "description": "Gives the account with this email access to the server. If no account has the email, one is created and sent an email to set its password. `websocket.connect` is always added, and unknown permissions are silently dropped. You cannot give permissions you do not have yourself, nor any your API key is not allowed. Limited to 10 every 15 minutes per server, shared by everyone managing that server.",
                "x-permission": "user.create",
                "x-rate-limit": "10 per 15 minutes per server",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/SubuserCreateRequest"
                            },
                            "example": {
                                "email": "friend@example.com",
                                "permissions": [
                                    "control.console",
                                    "control.restart",
                                    "file.read",
                                    "file.read-content"
                                ]
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "The new subuser.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Subuser"
                                },
                                "example": {
                                    "object": "server_subuser",
                                    "attributes": {
                                        "uuid": "5f0c2d8e-3b1a-4c7d-9e2f-6a8b0c1d2e3f",
                                        "identifier": "user_l4gc3dr3djgh3hrpnkfqyhjoh4",
                                        "username": "friend",
                                        "email": "friend@example.com",
                                        "image": "https://www.gravatar.com/avatar/0f2c9a7e4b1d8c6a3e5f7b9d1c3e5a7b9d1f3a5c7e9b1d3f5a7c9e1b3d5f7a9c?d=404",
                                        "2fa_enabled": false,
                                        "created_at": "2026-09-15T18:30:00+00:00",
                                        "permissions": [
                                            "control.console",
                                            "control.restart",
                                            "file.read",
                                            "file.read-content",
                                            "websocket.connect"
                                        ]
                                    }
                                }
                            }
                        }
                    },
                    "400": {
                        "description": "The email belongs to the server's owner or to an existing subuser.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                },
                                "example": {
                                    "errors": [
                                        {
                                            "code": "ServerSubuserExistsException",
                                            "status": "400",
                                            "detail": "A user with that email address is already assigned as a subuser for this server."
                                        }
                                    ]
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthenticated"
                    },
                    "403": {
                        "description": "The key lacks `user.create`, or you tried to give permissions that you or your API key do not have.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                },
                                "example": {
                                    "errors": [
                                        {
                                            "code": "HttpForbiddenException",
                                            "status": "403",
                                            "detail": "Cannot assign permissions to a subuser that your account does not actively possess."
                                        }
                                    ]
                                }
                            }
                        }
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationFailed"
                    },
                    "429": {
                        "$ref": "#/components/responses/TooManyRequests"
                    }
                }
            }
        },
        "/servers/{server}/users/{user}": {
            "parameters": [
                {
                    "$ref": "#/components/parameters/Server"
                },
                {
                    "name": "user",
                    "in": "path",
                    "required": true,
                    "description": "The subuser's account UUID (`attributes.uuid` from `listSubusers`).",
                    "schema": {
                        "type": "string",
                        "format": "uuid"
                    },
                    "example": "5f0c2d8e-3b1a-4c7d-9e2f-6a8b0c1d2e3f"
                }
            ],
            "get": {
                "operationId": "getSubuser",
                "tags": [
                    "Subusers"
                ],
                "summary": "Get a subuser",
                "description": "Returns one subuser of the server. You cannot look yourself up here (403).",
                "x-permission": "user.read",
                "responses": {
                    "200": {
                        "description": "The subuser.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Subuser"
                                },
                                "example": {
                                    "object": "server_subuser",
                                    "attributes": {
                                        "uuid": "5f0c2d8e-3b1a-4c7d-9e2f-6a8b0c1d2e3f",
                                        "identifier": "user_l4gc3dr3djgh3hrpnkfqyhjoh4",
                                        "username": "friend",
                                        "email": "friend@example.com",
                                        "image": "https://www.gravatar.com/avatar/0f2c9a7e4b1d8c6a3e5f7b9d1c3e5a7b9d1f3a5c7e9b1d3f5a7c9e1b3d5f7a9c?d=404",
                                        "2fa_enabled": false,
                                        "created_at": "2026-09-15T18:30:00+00:00",
                                        "permissions": [
                                            "websocket.connect",
                                            "control.console"
                                        ]
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthenticated"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    }
                }
            },
            "post": {
                "operationId": "updateSubuser",
                "tags": [
                    "Subusers"
                ],
                "summary": "Change a subuser's permissions",
                "description": "Replaces the subuser's permissions with the list sent (`websocket.connect` is always kept). If they change, the subuser's open SFTP sessions and console connections are dropped so the new set applies at once (this drops everyone's open console connections to the server, who then reconnect). The same limits on what you can give apply as for `createSubuser`, and you cannot change your own permissions.",
                "x-permission": "user.update",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/SubuserUpdateRequest"
                            },
                            "example": {
                                "permissions": [
                                    "control.console",
                                    "control.start",
                                    "control.stop",
                                    "control.restart"
                                ]
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "The updated subuser.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Subuser"
                                },
                                "example": {
                                    "object": "server_subuser",
                                    "attributes": {
                                        "uuid": "5f0c2d8e-3b1a-4c7d-9e2f-6a8b0c1d2e3f",
                                        "identifier": "user_l4gc3dr3djgh3hrpnkfqyhjoh4",
                                        "username": "friend",
                                        "email": "friend@example.com",
                                        "image": "https://www.gravatar.com/avatar/0f2c9a7e4b1d8c6a3e5f7b9d1c3e5a7b9d1f3a5c7e9b1d3f5a7c9e1b3d5f7a9c?d=404",
                                        "2fa_enabled": false,
                                        "created_at": "2026-09-15T18:30:00+00:00",
                                        "permissions": [
                                            "control.console",
                                            "control.start",
                                            "control.stop",
                                            "control.restart",
                                            "websocket.connect"
                                        ]
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthenticated"
                    },
                    "403": {
                        "description": "The key lacks `user.update`, this is your own account, or you tried to give permissions that you or your API key do not have.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationFailed"
                    }
                }
            },
            "delete": {
                "operationId": "deleteSubuser",
                "tags": [
                    "Subusers"
                ],
                "summary": "Remove a subuser",
                "description": "Takes away the account's access to the server and ends its open SFTP sessions; open console connections to the server are dropped and reconnect. The account itself is not deleted. You cannot remove yourself here.",
                "x-permission": "user.delete",
                "responses": {
                    "204": {
                        "$ref": "#/components/responses/NoContent"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthenticated"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    }
                }
            }
        },
        "/servers/{server}/git": {
            "parameters": [
                {
                    "$ref": "#/components/parameters/Server"
                }
            ],
            "get": {
                "operationId": "getGitDeploys",
                "tags": [
                    "Git deploys"
                ],
                "summary": "Get the linked repository and deployments",
                "description": "Returns the linked repository (or null), the state of its `sillydev.conf`, the last 15 deployments, the deployment rate limit, and, for the owner only, the GitHub App installations and GitLab account they have connected in the panel. `can_manage` says whether this key may link, deploy and change settings: it is true only for the server's owner using a key not limited to a set of permissions.",
                "x-permission": "git.read",
                "responses": {
                    "200": {
                        "description": "The server's Git deploy set-up. This is plain JSON, not a resource envelope.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/GitOverview"
                                },
                                "example": {
                                    "can_manage": true,
                                    "repository": {
                                        "source": "github",
                                        "repository": "you/my-discord-bot",
                                        "url": "https://github.com/you/my-discord-bot",
                                        "branch": "main",
                                        "directory": "/",
                                        "auto_deploy": true,
                                        "restart_on_deploy": true,
                                        "start_if_offline": false,
                                        "apply_config": true,
                                        "sync_startup": true,
                                        "installation": {
                                            "id": 7,
                                            "account": "you",
                                            "type": "User",
                                            "suspended": false
                                        },
                                        "account": "you",
                                        "disconnected": false,
                                        "last_deployed_at": "2026-10-10T11:58:00+00:00"
                                    },
                                    "config": {
                                        "filename": "sillydev.conf",
                                        "version": 1,
                                        "apply": true,
                                        "can_write": true,
                                        "checked_at": "2026-10-10T11:58:20+00:00",
                                        "state": "current",
                                        "missing": [],
                                        "unsupported": [],
                                        "invalid": [],
                                        "version_outdated": false,
                                        "problems": 0,
                                        "differs": []
                                    },
                                    "deployments": [
                                        {
                                            "uuid": "3d6f1a2b-8c4e-4f7a-9b1d-2e3f4a5b6c7d",
                                            "trigger": "push",
                                            "status": "succeeded",
                                            "branch": "main",
                                            "commit": {
                                                "sha": "9fceb02d0ae598e95dc970b74767f19372d61af8",
                                                "message": "Add /ping command",
                                                "author": "You",
                                                "url": "https://github.com/you/my-discord-bot/commit/9fceb02d0ae598e95dc970b74767f19372d61af8"
                                            },
                                            "user": null,
                                            "error": null,
                                            "files": {
                                                "written": 4,
                                                "deleted": 0,
                                                "unchanged": 37,
                                                "kept": 2
                                            },
                                            "power_action": "restart",
                                            "attempts": 0,
                                            "config": {
                                                "applied": [],
                                                "warnings": []
                                            },
                                            "run_after": "2026-10-10T11:58:00+00:00",
                                            "started_at": "2026-10-10T11:58:01+00:00",
                                            "completed_at": "2026-10-10T11:58:20+00:00",
                                            "created_at": "2026-10-10T11:58:00+00:00"
                                        }
                                    ],
                                    "limits": {
                                        "interval": 900,
                                        "paid": false,
                                        "paid_interval": 60,
                                        "next_deploy_at": "2026-10-10T12:13:00+00:00"
                                    },
                                    "github": {
                                        "enabled": true,
                                        "installations": [
                                            {
                                                "id": 7,
                                                "account": "you",
                                                "type": "User",
                                                "suspended": false
                                            }
                                        ]
                                    },
                                    "gitlab": {
                                        "enabled": true,
                                        "url": "https://gitlab.com",
                                        "account": null
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthenticated"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    }
                }
            },
            "put": {
                "operationId": "linkGitRepository",
                "tags": [
                    "Git deploys"
                ],
                "summary": "Link a repository or change its settings",
                "description": "Links a repository to the server, or changes the linked one; every setting is replaced, so send them all. For `github` and `gitlab` the repository must be reachable through a GitHub App installation or GitLab account you have already connected in the panel in a browser (see `listGitRepositories`); for `url`, any public https clone URL works but `auto_deploy` is always off. Linking a repository, or changing the repository or branch, writes `sillydev.conf` to it (unless `write_config` is false) and queues a first deployment; `notices` says what happened. Owner only.",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/GitLinkRequest"
                            },
                            "examples": {
                                "github": {
                                    "summary": "A GitHub repository through a connected installation",
                                    "value": {
                                        "source": "github",
                                        "installation": 7,
                                        "repository": "you/my-discord-bot",
                                        "branch": "main",
                                        "directory": "/",
                                        "auto_deploy": true,
                                        "restart_on_deploy": true,
                                        "start_if_offline": false,
                                        "apply_config": true,
                                        "sync_startup": true,
                                        "write_config": true
                                    }
                                },
                                "url": {
                                    "summary": "A public repository by URL",
                                    "value": {
                                        "source": "url",
                                        "repository": "https://github.com/you/my-discord-bot.git",
                                        "branch": "main",
                                        "directory": "bot",
                                        "restart_on_deploy": true
                                    }
                                }
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "The linked repository and what was done.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/GitLinkResult"
                                },
                                "example": {
                                    "source": "github",
                                    "repository": "you/my-discord-bot",
                                    "url": "https://github.com/you/my-discord-bot",
                                    "branch": "main",
                                    "directory": "/",
                                    "auto_deploy": true,
                                    "restart_on_deploy": true,
                                    "start_if_offline": false,
                                    "apply_config": true,
                                    "sync_startup": true,
                                    "installation": {
                                        "id": 7,
                                        "account": "you",
                                        "type": "User",
                                        "suspended": false
                                    },
                                    "account": "you",
                                    "disconnected": false,
                                    "last_deployed_at": null,
                                    "notices": [
                                        "Added sillydev.conf to main.",
                                        "A first deployment has been queued."
                                    ]
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthenticated"
                    },
                    "403": {
                        "description": "You are not the server's owner, or the key is limited to a set of permissions.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "422": {
                        "description": "A field is invalid, or the repository could not be reached: no matching connected GitHub installation or GitLab account, the app or account cannot see the repository, GitHub or GitLab could not be reached, or GitHub is not set up on this panel.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                },
                                "example": {
                                    "errors": [
                                        {
                                            "code": "UnprocessableEntityHttpException",
                                            "status": "422",
                                            "detail": "The GitHub App cannot access you/my-discord-bot. Add it to the app's installation on you first."
                                        }
                                    ]
                                }
                            }
                        }
                    }
                }
            },
            "delete": {
                "operationId": "unlinkGitRepository",
                "tags": [
                    "Git deploys"
                ],
                "summary": "Unlink the repository",
                "description": "Unlinks the repository and cancels any waiting deployment. Files already deployed stay on the server. By default the panel first removes `sillydev.conf` from the repository where it can write to it; send `delete_config=false` to leave it. Answers 200 with no notices if nothing was linked. Owner only.",
                "parameters": [
                    {
                        "name": "delete_config",
                        "in": "query",
                        "required": false,
                        "description": "Whether to remove `sillydev.conf` from the repository first. May also be sent in a JSON body.",
                        "schema": {
                            "type": "boolean",
                            "default": true
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Unlinked.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/GitNotices"
                                },
                                "example": {
                                    "notices": [
                                        "Removed sillydev.conf from main."
                                    ]
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthenticated"
                    },
                    "403": {
                        "description": "You are not the server's owner, or the key is limited to a set of permissions.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    }
                }
            }
        },
        "/servers/{server}/git/repositories": {
            "parameters": [
                {
                    "$ref": "#/components/parameters/Server"
                }
            ],
            "get": {
                "operationId": "listGitRepositories",
                "tags": [
                    "Git deploys"
                ],
                "summary": "List repositories you can link",
                "description": "Lists the repositories your connected GitHub App installations can reach, or with `provider=gitlab` the GitLab projects your connected account can push to (Developer role or above). The list is empty until you connect GitHub or GitLab in the panel in a browser; that cannot be done through the API. Accounts that could not be loaded are reported in `errors` while the rest are still listed. Owner only.",
                "x-rate-limit": "30 per minute",
                "parameters": [
                    {
                        "name": "provider",
                        "in": "query",
                        "required": false,
                        "description": "`gitlab` for GitLab projects; anything else, or nothing, for GitHub.",
                        "schema": {
                            "type": "string",
                            "enum": [
                                "github",
                                "gitlab"
                            ],
                            "default": "github"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "The repositories, sorted by name for GitHub.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/GitRepositoryChoiceList"
                                },
                                "example": {
                                    "data": [
                                        {
                                            "id": 812345678,
                                            "full_name": "you/my-discord-bot",
                                            "private": true,
                                            "default_branch": "main",
                                            "installation": 7,
                                            "account": "you"
                                        }
                                    ],
                                    "errors": []
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthenticated"
                    },
                    "403": {
                        "description": "You are not the server's owner, or the key is limited to a set of permissions.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "429": {
                        "$ref": "#/components/responses/TooManyRequests"
                    }
                }
            }
        },
        "/servers/{server}/git/deploy": {
            "parameters": [
                {
                    "$ref": "#/components/parameters/Server"
                }
            ],
            "post": {
                "operationId": "deployGitRepository",
                "tags": [
                    "Git deploys"
                ],
                "summary": "Deploy now",
                "description": "Queues a deployment of the linked branch. It is never refused for coming too soon: each server starts at most one deployment every 15 minutes (1 minute on a paid plan), and a request inside that window waits until `run_after`. Only one deployment waits at a time, so this replaces any already waiting (marked `superseded`). Owner only.",
                "x-rate-limit": "10 per minute",
                "responses": {
                    "202": {
                        "description": "The queued deployment.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/GitDeployment"
                                },
                                "example": {
                                    "uuid": "3d6f1a2b-8c4e-4f7a-9b1d-2e3f4a5b6c7d",
                                    "trigger": "manual",
                                    "status": "queued",
                                    "branch": "main",
                                    "commit": {
                                        "sha": null,
                                        "message": null,
                                        "author": null,
                                        "url": null
                                    },
                                    "user": "you",
                                    "error": null,
                                    "files": null,
                                    "power_action": null,
                                    "attempts": 0,
                                    "config": null,
                                    "run_after": "2026-10-10T12:13:00+00:00",
                                    "started_at": null,
                                    "completed_at": null,
                                    "created_at": "2026-10-10T12:00:00+00:00"
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthenticated"
                    },
                    "403": {
                        "description": "You are not the server's owner, or the key is limited to a set of permissions.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "404": {
                        "description": "No repository is linked to this server.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                },
                                "example": {
                                    "errors": [
                                        {
                                            "code": "NotFoundHttpException",
                                            "status": "404",
                                            "detail": "Link a repository to this server first."
                                        }
                                    ]
                                }
                            }
                        }
                    },
                    "409": {
                        "$ref": "#/components/responses/Conflict"
                    },
                    "429": {
                        "$ref": "#/components/responses/TooManyRequests"
                    }
                }
            }
        },
        "/servers/{server}/git/deployments/{deployment}/cancel": {
            "parameters": [
                {
                    "$ref": "#/components/parameters/Server"
                },
                {
                    "name": "deployment",
                    "in": "path",
                    "required": true,
                    "description": "The deployment's UUID, from `deployments[].uuid`.",
                    "schema": {
                        "type": "string",
                        "format": "uuid"
                    },
                    "example": "3d6f1a2b-8c4e-4f7a-9b1d-2e3f4a5b6c7d"
                }
            ],
            "post": {
                "operationId": "cancelGitDeployment",
                "tags": [
                    "Git deploys"
                ],
                "summary": "Cancel a deployment",
                "description": "Cancels a waiting deployment at once, or asks the node to stop a running one, which then finishes as `failed`. A deployment that has already finished is left alone and this still answers 204. Owner only.",
                "responses": {
                    "204": {
                        "$ref": "#/components/responses/NoContent"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthenticated"
                    },
                    "403": {
                        "description": "You are not the server's owner, or the key is limited to a set of permissions.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    }
                }
            }
        },
        "/servers/{server}/git/config": {
            "parameters": [
                {
                    "$ref": "#/components/parameters/Server"
                }
            ],
            "get": {
                "operationId": "getGitConfigTemplate",
                "tags": [
                    "Git deploys"
                ],
                "summary": "Get the sillydev.conf for this server",
                "description": "Returns the `sillydev.conf` the panel would write for this server now, listing every setting the server lets you change and keeping the values from the repository's current file. Use it to copy the file into a repository linked by URL, which the panel cannot write to. Works with no repository linked. Owner only.",
                "responses": {
                    "200": {
                        "description": "The file.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/GitConfigFile"
                                },
                                "example": {
                                    "filename": "sillydev.conf",
                                    "contents": "; sillydev.conf\n; Hosted on Silly Development: https://sillydev.co.uk\n;\n; Silly Development applies these settings to this server every time this\n; repository is deployed: change a value, push, and the next deployment uses it.\n; Comment a setting out (put ; in front of it) to leave it to the panel instead.\n;\n; Only the settings this server lets you change are listed. Never put a secret\n; (a token or password) here: anyone who can see the repository can read it.\n; Secrets belong in the Startup tab on the panel.\n\n[sillydev]\nversion = 1\n\n[docker]\n; One of: \"Python 3.12\", \"Python 3.13\"\nimage = \"Python 3.12\"\n\n[variables]\n\n; Main file: the file to run when the server starts.\nMAIN_FILE = \"bot.py\"\n"
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthenticated"
                    },
                    "403": {
                        "description": "You are not the server's owner, or the key is limited to a set of permissions.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    }
                }
            },
            "post": {
                "operationId": "syncGitConfig",
                "tags": [
                    "Git deploys"
                ],
                "summary": "Write sillydev.conf to the repository",
                "description": "Commits `sillydev.conf` to the linked branch, or brings the existing file up to date with the settings the server supports now. Only works for repositories linked through GitHub or GitLab. Owner only.",
                "x-rate-limit": "10 per minute",
                "responses": {
                    "200": {
                        "description": "What was done.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "required": [
                                        "result"
                                    ],
                                    "properties": {
                                        "result": {
                                            "type": "string",
                                            "enum": [
                                                "created",
                                                "updated",
                                                "unchanged"
                                            ]
                                        }
                                    }
                                },
                                "example": {
                                    "result": "updated"
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthenticated"
                    },
                    "403": {
                        "description": "You are not the server's owner, or the key is limited to a set of permissions.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "404": {
                        "description": "No repository is linked to this server.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "422": {
                        "description": "The repository is linked by URL, so the panel cannot write to it, or GitHub or GitLab refused the commit.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                },
                                "example": {
                                    "errors": [
                                        {
                                            "code": "UnprocessableEntityHttpException",
                                            "status": "422",
                                            "detail": "The panel can only write sillydev.conf to a repository linked through GitHub or GitLab. Copy the file into the repository yourself instead."
                                        }
                                    ]
                                }
                            }
                        }
                    },
                    "429": {
                        "$ref": "#/components/responses/TooManyRequests"
                    }
                }
            }
        },
        "/servers/{server}/git/config/editor": {
            "parameters": [
                {
                    "$ref": "#/components/parameters/Server"
                }
            ],
            "get": {
                "operationId": "getGitConfigEditor",
                "tags": [
                    "Git deploys"
                ],
                "summary": "Get the sillydev.conf editor state",
                "description": "Built for the panel's `sillydev.conf` editor, but usable from code. Returns every setting the file can hold with the value in the repository next to the value on the server, plus the raw file and its `sha` to send back when saving. The file is read live from GitHub or GitLab; for a repository linked by URL it is the copy the last deployment found. Owner only.",
                "x-rate-limit": "30 per minute",
                "responses": {
                    "200": {
                        "description": "The editor state.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/GitConfigEditorState"
                                },
                                "example": {
                                    "filename": "sillydev.conf",
                                    "can_write": true,
                                    "exists": true,
                                    "sha": "3b18e512dba79e4c8300dd08aeb37f8e728b8dad",
                                    "raw": "[sillydev]\nversion = 1\n\n[variables]\nMAIN_FILE = \"bot.py\"\n",
                                    "apply": true,
                                    "sync": true,
                                    "variables": [
                                        {
                                            "key": "MAIN_FILE",
                                            "name": "Main file",
                                            "description": "The file to run when the server starts.",
                                            "rules": "required|string|max:64",
                                            "secret": false,
                                            "state": "set",
                                            "file_value": "bot.py",
                                            "server_value": "main.py",
                                            "differs": true,
                                            "error": null
                                        },
                                        {
                                            "key": "BOT_TOKEN",
                                            "name": "Bot token",
                                            "description": "Your Discord bot token.",
                                            "rules": "nullable|string",
                                            "secret": true,
                                            "state": "absent",
                                            "file_value": null,
                                            "server_value": "",
                                            "differs": false,
                                            "error": null
                                        }
                                    ],
                                    "image": {
                                        "options": [
                                            {
                                                "name": "Python 3.12",
                                                "image": "ghcr.io/sillydev/yolks:python_3.12"
                                            },
                                            {
                                                "name": "Python 3.13",
                                                "image": "ghcr.io/sillydev/yolks:python_3.13"
                                            }
                                        ],
                                        "state": "absent",
                                        "file_value": null,
                                        "server_value": "Python 3.12",
                                        "differs": false,
                                        "error": null
                                    },
                                    "unsupported": [],
                                    "problems": []
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthenticated"
                    },
                    "403": {
                        "description": "You are not the server's owner, or the key is limited to a set of permissions.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "404": {
                        "description": "No repository is linked to this server.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "422": {
                        "description": "GitHub or GitLab could not be reached, or refused to return the file.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "429": {
                        "$ref": "#/components/responses/TooManyRequests"
                    }
                }
            },
            "put": {
                "operationId": "saveGitConfigEditor",
                "tags": [
                    "Git deploys"
                ],
                "summary": "Save sillydev.conf from the editor",
                "description": "Saves the editor, either as a form (`mode: form`, changing only the settings sent and keeping the rest of the file) or as raw text (`mode: raw`). For a repository linked through GitHub or GitLab the file is committed and, if `apply` is on, applied to the server; send the `sha` you loaded, and a 409 means it changed since. For a repository linked by URL nothing is committed and the file comes back to copy in yourself. The panel refuses to write a new secret-looking variable into the file. Owner only.",
                "x-rate-limit": "20 per minute",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/GitConfigEditorSaveRequest"
                            },
                            "examples": {
                                "form": {
                                    "summary": "Change one variable and leave the image to the panel",
                                    "value": {
                                        "mode": "form",
                                        "sha": "3b18e512dba79e4c8300dd08aeb37f8e728b8dad",
                                        "variables": {
                                            "MAIN_FILE": {
                                                "mode": "set",
                                                "value": "main.py"
                                            }
                                        },
                                        "image": {
                                            "mode": "left",
                                            "value": null
                                        }
                                    }
                                },
                                "raw": {
                                    "summary": "Replace the whole file",
                                    "value": {
                                        "mode": "raw",
                                        "sha": "3b18e512dba79e4c8300dd08aeb37f8e728b8dad",
                                        "raw": "[sillydev]\nversion = 1\n\n[variables]\nMAIN_FILE = \"main.py\"\n"
                                    }
                                }
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "What was saved.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/GitConfigEditorSaveResult"
                                },
                                "example": {
                                    "contents": "[sillydev]\nversion = 1\n\n[variables]\nMAIN_FILE = \"main.py\"\n",
                                    "committed": true,
                                    "applied": [
                                        "MAIN_FILE"
                                    ],
                                    "warnings": []
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthenticated"
                    },
                    "403": {
                        "description": "You are not the server's owner, or the key is limited to a set of permissions.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "404": {
                        "description": "No repository is linked to this server.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "409": {
                        "description": "The file changed in the repository since `sha` was loaded. Load the editor again and redo the change.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                },
                                "example": {
                                    "errors": [
                                        {
                                            "code": "ConflictHttpException",
                                            "status": "409",
                                            "detail": "sillydev.conf has changed in the repository since you opened it. Reload the editor to see the new version, then make your change again."
                                        }
                                    ]
                                }
                            }
                        }
                    },
                    "422": {
                        "description": "A field is invalid (for example an unknown variable, a value breaking the variable's rules, or a raw file that does not parse), or GitHub or GitLab could not be reached.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "429": {
                        "$ref": "#/components/responses/TooManyRequests"
                    }
                }
            }
        },
        "/account": {
            "get": {
                "operationId": "getAccount",
                "tags": [
                    "Account"
                ],
                "summary": "Get the account",
                "description": "Returns the account the API key belongs to. Works even when two-factor authentication is required but not yet set up.",
                "x-scope": "account.read",
                "responses": {
                    "200": {
                        "description": "The account.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/AccountItem"
                                },
                                "example": {
                                    "object": "user",
                                    "attributes": {
                                        "id": 42,
                                        "admin": false,
                                        "username": "discordbotdev",
                                        "email": "you@example.com",
                                        "first_name": "Alex",
                                        "last_name": "Smith",
                                        "language": "en"
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthenticated"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    }
                }
            }
        },
        "/account/activity": {
            "get": {
                "operationId": "listAccountActivity",
                "tags": [
                    "Account"
                ],
                "summary": "List the account's activity log",
                "description": "Returns the account's activity log, newest first when sorted by `-timestamp`, 25 entries per page by default and at most 100. Actions an administrator took on the account are not shown, except ones the requesting administrator took themselves.",
                "x-scope": "account.read",
                "parameters": [
                    {
                        "$ref": "#/components/parameters/Page"
                    },
                    {
                        "$ref": "#/components/parameters/PerPage"
                    },
                    {
                        "name": "filter[event]",
                        "in": "query",
                        "required": false,
                        "description": "Only entries whose event name contains this text, e.g. `server:power` or `user:api-key`.",
                        "schema": {
                            "type": "string"
                        },
                        "example": "user:database"
                    },
                    {
                        "name": "sort",
                        "in": "query",
                        "required": false,
                        "description": "Sort by time, `timestamp` for oldest first or `-timestamp` for newest first.",
                        "schema": {
                            "type": "string",
                            "enum": [
                                "timestamp",
                                "-timestamp"
                            ]
                        },
                        "example": "-timestamp"
                    },
                    {
                        "name": "include",
                        "in": "query",
                        "required": false,
                        "description": "Set to `actor` to add the user who performed each action as `attributes.relationships.actor`.",
                        "schema": {
                            "type": "string",
                            "enum": [
                                "actor"
                            ]
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "A page of activity log entries.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/AccountActivityList"
                                },
                                "example": {
                                    "object": "list",
                                    "data": [
                                        {
                                            "object": "activity_log",
                                            "attributes": {
                                                "id": "3f786850e387550fdab836ed7e6dc881de23001b",
                                                "batch": null,
                                                "event": "user:database.create",
                                                "is_api": true,
                                                "ip": "203.0.113.10",
                                                "description": null,
                                                "properties": {
                                                    "label": "Discord bot",
                                                    "version": "MariaDB 11.4"
                                                },
                                                "has_additional_metadata": false,
                                                "timestamp": "2026-10-10T12:00:00+00:00"
                                            }
                                        }
                                    ],
                                    "meta": {
                                        "pagination": {
                                            "total": 1,
                                            "count": 1,
                                            "per_page": 25,
                                            "current_page": 1,
                                            "total_pages": 1,
                                            "links": []
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthenticated"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    }
                }
            }
        },
        "/server-creation": {
            "get": {
                "operationId": "getServerCreationOptions",
                "tags": [
                    "Server creation"
                ],
                "summary": "Get free server allowance and runtimes",
                "description": "Returns how many free servers the account may own, how many it owns now, whether it can create another, and the runtimes on offer. Every account may own 2 free servers. Only servers the account owns and that have no live paid plan count towards it: paid servers and servers you reach as a subuser do not. Returns 404 while creating servers is switched off.",
                "x-scope": "servers.create",
                "x-limits": {
                    "max_free_servers": {
                        "value": 2
                    }
                },
                "responses": {
                    "200": {
                        "description": "The allowance and the runtimes on offer.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/ServerCreationOptions"
                                },
                                "example": {
                                    "object": "server_creation",
                                    "attributes": {
                                        "limit": 1,
                                        "servers_owned": 0,
                                        "can_create": true,
                                        "runtimes": [
                                            {
                                                "key": "nodejs",
                                                "label": "Node.js"
                                            },
                                            {
                                                "key": "python",
                                                "label": "Python"
                                            },
                                            {
                                                "key": "bun",
                                                "label": "Bun"
                                            }
                                        ]
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthenticated"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    }
                }
            },
            "post": {
                "operationId": "createServer",
                "tags": [
                    "Server creation"
                ],
                "summary": "Create a free server",
                "description": "Creates a free server owned by the account and places it on whichever node has room. Every free server is the same size (256 MiB of memory, 512 MiB of disk, 25% of one CPU core and one port), its image and startup command come from the runtime, and it is not started after installing because it has no code yet.\n\nAn account may own 2 free servers; paid servers and servers you reach as a subuser do not count. Creating one more is refused with 409, as is a second request while the first is still being set up. Returns 503 when no node has room, and 404 while creating servers is switched off.",
                "x-scope": "servers.create",
                "x-rate-limit": "5 per minute",
                "x-limits": {
                    "max_free_servers": {
                        "value": 2
                    },
                    "memory_mib": {
                        "value": 256
                    },
                    "disk_mib": {
                        "value": 512
                    },
                    "cpu_percent": {
                        "value": 25
                    },
                    "allocations": {
                        "value": 1
                    },
                    "backups": {
                        "value": 0
                    }
                },
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/ServerCreationRequest"
                            },
                            "example": {
                                "name": "My Discord bot",
                                "description": "Posts the daily quiz.",
                                "runtime": "nodejs"
                            }
                        }
                    }
                },
                "responses": {
                    "201": {
                        "description": "The new server. It is still installing; poll the server until its `status` is no longer `installing` before uploading code or starting it.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/ServerItem"
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthenticated"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "409": {
                        "description": "The account is at its free server limit (\"You already have a server. Delete it before creating another one.\" at a limit of 1), or a server is already being created for it.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                },
                                "example": {
                                    "errors": [
                                        {
                                            "code": "ConflictHttpException",
                                            "status": "409",
                                            "detail": "You already have a server. Delete it before creating another one."
                                        }
                                    ]
                                }
                            }
                        }
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationFailed"
                    },
                    "429": {
                        "$ref": "#/components/responses/TooManyRequests"
                    },
                    "503": {
                        "description": "No node has room for the server right now, or the runtime is misconfigured. Try again later.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                },
                                "example": {
                                    "errors": [
                                        {
                                            "code": "ServiceUnavailableHttpException",
                                            "status": "503",
                                            "detail": "There is no capacity available to create a server right now. Please try again later."
                                        }
                                    ]
                                }
                            }
                        }
                    }
                }
            }
        },
        "/databases": {
            "get": {
                "operationId": "listDatabases",
                "tags": [
                    "Databases"
                ],
                "summary": "List the account's databases",
                "description": "Returns, in one response, the account's databases with their connection details (passwords included), how many it may have, and the versions it can create or move to. An account may have 2 databases in total, of any engine or version, each with a hard disk quota of 50 MiB. Engines are `mariadb` and `postgres`; which versions exist changes over time, so read them from `versions`. Returns 404 while databases are switched off.",
                "x-scope": "databases.read",
                "x-limits": {
                    "max_databases": {
                        "value": 2
                    },
                    "quota_mib": {
                        "value": 50
                    },
                    "max_connections": {
                        "value": 5
                    },
                    "max_queries_per_hour": {
                        "value": 36000
                    },
                    "max_updates_per_hour": {
                        "value": 7200
                    },
                    "max_statement_seconds": {
                        "value": 30
                    }
                },
                "responses": {
                    "200": {
                        "description": "The databases, the allowance and the versions on offer.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/DatabaseOverview"
                                },
                                "example": {
                                    "object": "user_database_list",
                                    "attributes": {
                                        "limit": 2,
                                        "owned": 1,
                                        "can_create": true,
                                        "quota_bytes": 52428800,
                                        "versions": [
                                            {
                                                "id": 3,
                                                "engine": "mariadb",
                                                "name": "MariaDB 11.4",
                                                "server_version": "11.4.3",
                                                "label": "recommended",
                                                "status": "active",
                                                "legacy_ends_at": null,
                                                "host": "db.sillydev.co.uk",
                                                "port": 3306
                                            },
                                            {
                                                "id": 5,
                                                "engine": "postgres",
                                                "name": "Postgres 17",
                                                "server_version": "17.2",
                                                "label": "recommended",
                                                "status": "active",
                                                "legacy_ends_at": null,
                                                "host": "db.sillydev.co.uk",
                                                "port": 5432
                                            }
                                        ],
                                        "databases": [
                                            {
                                                "object": "user_database",
                                                "attributes": {
                                                    "id": 12,
                                                    "label": "Discord bot",
                                                    "engine": "mariadb",
                                                    "name": "discord_bot_k3j9x0",
                                                    "username": "u42_p0zt7c1m",
                                                    "password": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
                                                    "host": "db.sillydev.co.uk",
                                                    "port": 3306,
                                                    "version": {
                                                        "id": 3,
                                                        "engine": "mariadb",
                                                        "name": "MariaDB 11.4",
                                                        "server_version": "11.4.3",
                                                        "label": "recommended",
                                                        "status": "active",
                                                        "legacy_ends_at": null,
                                                        "host": "db.sillydev.co.uk",
                                                        "port": 3306
                                                    },
                                                    "status": "ready",
                                                    "moving_to": null,
                                                    "last_move_error": null,
                                                    "previous_version": null,
                                                    "previous_expires_at": null,
                                                    "moved_at": null,
                                                    "can_undo_move": false,
                                                    "size_bytes": 1310720,
                                                    "quota_bytes": 52428800,
                                                    "size_checked_at": "2026-10-10T12:00:00+00:00",
                                                    "created_at": "2026-10-01T09:30:00+00:00"
                                                }
                                            }
                                        ]
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthenticated"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    }
                }
            },
            "post": {
                "operationId": "createDatabase",
                "tags": [
                    "Databases"
                ],
                "summary": "Create a database",
                "description": "Creates a database on an active version and returns it with its connection details. The database name is made from the label plus a random suffix, and the username and a 32-character password are generated. Refused with 409 when the account already has 2 databases or another creation is still running. Returns 404 while databases are switched off.",
                "x-scope": "databases.write",
                "x-rate-limit": "5 per minute",
                "x-limits": {
                    "max_databases": {
                        "value": 2
                    },
                    "quota_mib": {
                        "value": 50
                    }
                },
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/DatabaseCreateRequest"
                            },
                            "example": {
                                "label": "Discord bot",
                                "version_id": 3
                            }
                        }
                    }
                },
                "responses": {
                    "201": {
                        "description": "The new database.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/DatabaseItem"
                                },
                                "example": {
                                    "object": "user_database",
                                    "attributes": {
                                        "id": 12,
                                        "label": "Discord bot",
                                        "engine": "mariadb",
                                        "name": "discord_bot_k3j9x0",
                                        "username": "u42_p0zt7c1m",
                                        "password": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
                                        "host": "db.sillydev.co.uk",
                                        "port": 3306,
                                        "version": {
                                            "id": 3,
                                            "engine": "mariadb",
                                            "name": "MariaDB 11.4",
                                            "server_version": "11.4.3",
                                            "label": "recommended",
                                            "status": "active",
                                            "legacy_ends_at": null,
                                            "host": "db.sillydev.co.uk",
                                            "port": 3306
                                        },
                                        "status": "ready",
                                        "moving_to": null,
                                        "last_move_error": null,
                                        "previous_version": null,
                                        "previous_expires_at": null,
                                        "moved_at": null,
                                        "can_undo_move": false,
                                        "size_bytes": 0,
                                        "quota_bytes": 52428800,
                                        "size_checked_at": "2026-10-10T12:00:00+00:00",
                                        "created_at": "2026-10-10T12:00:00+00:00"
                                    }
                                }
                            }
                        }
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthenticated"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "409": {
                        "description": "The account is at its database limit, or a database is already being created for it.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                },
                                "example": {
                                    "errors": [
                                        {
                                            "code": "ConflictHttpException",
                                            "status": "409",
                                            "detail": "You can have up to 2 databases. Delete one to make another."
                                        }
                                    ]
                                }
                            }
                        }
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationFailed"
                    },
                    "429": {
                        "$ref": "#/components/responses/TooManyRequests"
                    },
                    "502": {
                        "description": "The database server could not be reached or refused the request. Try again in a few minutes.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                },
                                "example": {
                                    "errors": [
                                        {
                                            "code": "TalonsException",
                                            "status": "502",
                                            "detail": "The database server could not be reached. Please try again in a few minutes."
                                        }
                                    ]
                                }
                            }
                        }
                    }
                }
            }
        },
        "/databases/{database}/rotate-password": {
            "parameters": [
                {
                    "name": "database",
                    "in": "path",
                    "required": true,
                    "description": "The database's numeric `id`.",
                    "schema": {
                        "type": "integer"
                    },
                    "example": 12
                }
            ],
            "post": {
                "operationId": "rotateDatabasePassword",
                "tags": [
                    "Databases"
                ],
                "summary": "Rotate a database's password",
                "description": "Gives the database a new random 32-character password and returns the database with it. The old password stops working at once. If a copy is being kept from a recent move it gets the new password too. Refused with 409 while the database is being moved.",
                "x-scope": "databases.write",
                "x-rate-limit": "10 per minute",
                "responses": {
                    "200": {
                        "description": "The database with its new password.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/DatabaseItem"
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthenticated"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "409": {
                        "$ref": "#/components/responses/Conflict"
                    },
                    "429": {
                        "$ref": "#/components/responses/TooManyRequests"
                    },
                    "502": {
                        "description": "The database server could not be reached or refused the request. Try again in a few minutes.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                },
                                "example": {
                                    "errors": [
                                        {
                                            "code": "TalonsException",
                                            "status": "502",
                                            "detail": "The database server could not be reached. Please try again in a few minutes."
                                        }
                                    ]
                                }
                            }
                        }
                    }
                }
            }
        },
        "/databases/{database}/move": {
            "parameters": [
                {
                    "name": "database",
                    "in": "path",
                    "required": true,
                    "description": "The database's numeric `id`.",
                    "schema": {
                        "type": "integer"
                    },
                    "example": 12
                }
            ],
            "post": {
                "operationId": "moveDatabase",
                "tags": [
                    "Databases"
                ],
                "summary": "Move a database to another version",
                "description": "Queues a move of the database to another active version of the same engine on the same database server, and returns at once with `status` set to `moving`. Poll the database list until `status` is `ready` again: on success `version` is the new one and the old copy is kept, locked, for 7 days so the move can be undone; on failure the database stays where it was and `last_move_error` says why. Refused with 409 while a move is running or while a copy from the last move is still kept (undo or keep it first), and with 422 for the same version, another engine, another database server or a version that is not active.",
                "x-scope": "databases.write",
                "x-rate-limit": "5 per minute",
                "x-limits": {
                    "undo_days": {
                        "value": 7
                    }
                },
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/DatabaseMoveRequest"
                            },
                            "example": {
                                "version_id": 4
                            }
                        }
                    }
                },
                "responses": {
                    "202": {
                        "description": "The move is queued; the database is returned with `status` `moving` and `moving_to` set.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/DatabaseItem"
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthenticated"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "409": {
                        "$ref": "#/components/responses/Conflict"
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationFailed"
                    },
                    "429": {
                        "$ref": "#/components/responses/TooManyRequests"
                    }
                }
            }
        },
        "/databases/{database}/undo-move": {
            "parameters": [
                {
                    "name": "database",
                    "in": "path",
                    "required": true,
                    "description": "The database's numeric `id`.",
                    "schema": {
                        "type": "integer"
                    },
                    "example": 12
                }
            ],
            "post": {
                "operationId": "undoDatabaseMove",
                "tags": [
                    "Databases"
                ],
                "summary": "Undo a database move",
                "description": "Switches the database back to the copy kept from its last move and deletes the moved copy. Anything written since the move is lost. Only possible while `can_undo_move` is true, and refused with 409 when the old version has reached its end date.",
                "x-scope": "databases.write",
                "responses": {
                    "200": {
                        "description": "The database, back on its previous version.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/DatabaseItem"
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthenticated"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "409": {
                        "$ref": "#/components/responses/Conflict"
                    },
                    "502": {
                        "description": "The database server could not be reached or refused the request. Try again in a few minutes.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                },
                                "example": {
                                    "errors": [
                                        {
                                            "code": "TalonsException",
                                            "status": "502",
                                            "detail": "The database server could not be reached. Please try again in a few minutes."
                                        }
                                    ]
                                }
                            }
                        }
                    }
                }
            }
        },
        "/databases/{database}/keep-move": {
            "parameters": [
                {
                    "name": "database",
                    "in": "path",
                    "required": true,
                    "description": "The database's numeric `id`.",
                    "schema": {
                        "type": "integer"
                    },
                    "example": 12
                }
            ],
            "post": {
                "operationId": "keepDatabaseMove",
                "tags": [
                    "Databases"
                ],
                "summary": "Keep a database move",
                "description": "Deletes the copy kept from the database's last move, ending the undo window early so the database can be moved again. Does nothing harmful if there is no kept copy. Refused with 409 while the database is being moved.",
                "x-scope": "databases.write",
                "responses": {
                    "200": {
                        "description": "The database, with `previous_version` cleared.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/DatabaseItem"
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthenticated"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "409": {
                        "$ref": "#/components/responses/Conflict"
                    },
                    "502": {
                        "description": "The database server could not be reached or refused the request. Try again in a few minutes.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                },
                                "example": {
                                    "errors": [
                                        {
                                            "code": "TalonsException",
                                            "status": "502",
                                            "detail": "The database server could not be reached. Please try again in a few minutes."
                                        }
                                    ]
                                }
                            }
                        }
                    }
                }
            }
        },
        "/databases/{database}": {
            "parameters": [
                {
                    "name": "database",
                    "in": "path",
                    "required": true,
                    "description": "The database's numeric `id`.",
                    "schema": {
                        "type": "integer"
                    },
                    "example": 12
                }
            ],
            "delete": {
                "operationId": "deleteDatabase",
                "tags": [
                    "Databases"
                ],
                "summary": "Delete a database",
                "description": "Permanently deletes the database and its data, along with any copy kept from a move. It is only removed from the account once the database server has dropped it. Refused with 409 while the database is being moved.",
                "x-scope": "databases.write",
                "responses": {
                    "204": {
                        "$ref": "#/components/responses/NoContent"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthenticated"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "409": {
                        "$ref": "#/components/responses/Conflict"
                    },
                    "502": {
                        "description": "The database server could not be reached or refused the request. Try again in a few minutes.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                },
                                "example": {
                                    "errors": [
                                        {
                                            "code": "TalonsException",
                                            "status": "502",
                                            "detail": "The database server could not be reached. Please try again in a few minutes."
                                        }
                                    ]
                                }
                            }
                        }
                    }
                }
            }
        },
        "/billing": {
            "get": {
                "operationId": "getBilling",
                "tags": [
                    "Billing"
                ],
                "summary": "Get billing status",
                "description": "Returns the plan on sale, the account's paid servers with their plan state and refund quote, paid servers that lapsed and can be restored by subscribing again, and the saved card (brand and last four digits only). Works for accounts that have never bought anything. Use it to follow an upgrade or a new paid server: once the order is fulfilled the server appears in `subscriptions`. Orders that are paid for but still being built are listed in `meta.pending_orders` of the server list (`GET /`). Has its own, larger rate limit than the rest of the API.",
                "x-scope": "billing.read",
                "x-rate-limit": "2400 per minute",
                "x-limits": {
                    "price_pence": {
                        "value": 75
                    },
                    "plan_multiplier": {
                        "value": 2
                    }
                },
                "responses": {
                    "200": {
                        "description": "The account's billing status.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/BillingOverview"
                                },
                                "example": {
                                    "object": "billing",
                                    "attributes": {
                                        "is_customer": true,
                                        "sandbox": false,
                                        "restricted": false,
                                        "plan": {
                                            "key": "standard",
                                            "name": "Standard",
                                            "price_pence": 75,
                                            "currency": "gbp",
                                            "limits": {
                                                "memory": 512,
                                                "disk": 1024,
                                                "cpu": 50
                                            }
                                        },
                                        "subscriptions": [
                                            {
                                                "server_uuid": "1a7ce997-259b-452e-8b4e-cecc464142ca",
                                                "server_name": "My Discord bot",
                                                "status": "active",
                                                "plan": {
                                                    "key": "standard",
                                                    "name": "Standard"
                                                },
                                                "cancel_at_period_end": false,
                                                "current_period_end": "2026-11-01T12:00:00+00:00",
                                                "payment_issue": null,
                                                "immediate_downgrade": {
                                                    "available": true,
                                                    "reason": null,
                                                    "refund_pence": 22,
                                                    "fee_pence": 25,
                                                    "available_at": null
                                                }
                                            }
                                        ],
                                        "restorable": [],
                                        "saved_card": {
                                            "brand": "visa",
                                            "last4": "4242",
                                            "exp_month": 12,
                                            "exp_year": 2028
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthenticated"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    }
                }
            }
        },
        "/billing/checkout": {
            "post": {
                "operationId": "createCheckout",
                "tags": [
                    "Billing"
                ],
                "summary": "Order a paid server or upgrade a free one",
                "description": "Starts an order for a new paid server (send `name` and `runtime`) or for upgrading an existing free server the account owns (send `server_uuid`). With `use_saved_card` true and a card on file, the order goes straight to being built and the returned `url` is just the billing page; otherwise `url` is a Stripe Checkout page that a person must open in a browser to enter a card, and nothing happens until they do.\n\nNeeds the `billing.purchase` scope, which no key has unless its owner turns it on. Each key may start 2 orders in any rolling 24 hours, abandoned ones included (an administrator can change this for an account, and 0 means the account's keys cannot order at all, which answers 403). The account owner is emailed about every order a key starts.\n\nSend an `Idempotency-Key` header to make retries safe: repeating a key the account already used returns that order instead of starting another. Unpaid orders are cancelled after 7 days.",
                "x-scope": "billing.purchase",
                "x-rate-limit": "20 per minute",
                "x-limits": {
                    "api_key_daily_orders": {
                        "value": 2,
                        "per_account_override": true
                    },
                    "order_expiry_days": {
                        "value": 7
                    },
                    "checkout_per_minute": {
                        "value": 20
                    }
                },
                "parameters": [
                    {
                        "name": "Idempotency-Key",
                        "in": "header",
                        "required": false,
                        "description": "1 to 255 characters, unique per order you mean to place. A repeat returns the original order (same `order_uuid`, `url` pointing at the billing page) without buying again, even if the first request is still running.",
                        "schema": {
                            "type": "string",
                            "minLength": 1,
                            "maxLength": 255
                        },
                        "example": "3f0b6c1e-order-my-discord-bot"
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/BillingCheckoutRequest"
                            },
                            "examples": {
                                "newServer": {
                                    "summary": "A new paid server, paid with the saved card",
                                    "value": {
                                        "name": "My Discord bot",
                                        "description": "Posts the daily quiz.",
                                        "runtime": "nodejs",
                                        "use_saved_card": true
                                    }
                                },
                                "upgrade": {
                                    "summary": "Upgrade an existing free server through Stripe Checkout",
                                    "value": {
                                        "server_uuid": "1a7ce997-259b-452e-8b4e-cecc464142ca"
                                    }
                                }
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "The order. Follow it with `GET /` (`meta.pending_orders`, while it is `provisioning` or `pending_deployment`) and `GET /billing` (`subscriptions`, once the server is on the plan).",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/BillingCheckout"
                                },
                                "examples": {
                                    "savedCard": {
                                        "summary": "Paid with the saved card, or a replayed Idempotency-Key",
                                        "value": {
                                            "object": "billing_checkout",
                                            "attributes": {
                                                "url": "https://sillydev.co.uk/panel/account/billing?order=5d2f8a3c-6b1e-4c7a-9f0d-2e8b7a6c5d4f",
                                                "order_uuid": "5d2f8a3c-6b1e-4c7a-9f0d-2e8b7a6c5d4f"
                                            }
                                        }
                                    },
                                    "stripeCheckout": {
                                        "summary": "A person must open the Stripe Checkout page",
                                        "value": {
                                            "object": "billing_checkout",
                                            "attributes": {
                                                "url": "https://checkout.stripe.com/c/pay/cs_live_xxxxxxxxxxxxxxxx",
                                                "order_uuid": "5d2f8a3c-6b1e-4c7a-9f0d-2e8b7a6c5d4f"
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "400": {
                        "description": "The Idempotency-Key header is empty or too long, the runtime is not available, the server is already on a paid plan or is suspended, no saved card was found, or another plan's payment needs attention before the saved card can be used again.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                },
                                "example": {
                                    "errors": [
                                        {
                                            "code": "BadRequestHttpException",
                                            "status": "400",
                                            "detail": "We could not find a saved card on your account. Please enter your card details to continue."
                                        }
                                    ]
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthenticated"
                    },
                    "403": {
                        "description": "The key lacks the `billing.purchase` scope, or the account's keys may not order (daily limit 0).",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                },
                                "example": {
                                    "errors": [
                                        {
                                            "code": "AccessDeniedHttpException",
                                            "status": "403",
                                            "detail": "API keys on this account cannot order servers. Order from the panel instead."
                                        }
                                    ]
                                }
                            }
                        }
                    },
                    "404": {
                        "description": "Billing is switched off, or `server_uuid` is not a server the account owns.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationFailed"
                    },
                    "429": {
                        "description": "The key has used its daily order limit, or the per-minute rate limit was hit.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                },
                                "example": {
                                    "errors": [
                                        {
                                            "code": "TooManyRequestsHttpException",
                                            "status": "429",
                                            "detail": "This API key has started 2 orders in the last 24 hours, which is its limit."
                                        }
                                    ]
                                }
                            }
                        }
                    }
                }
            }
        },
        "/billing/orders/{orderUuid}": {
            "parameters": [
                {
                    "name": "orderUuid",
                    "in": "path",
                    "required": true,
                    "description": "The order's UUID, as returned by `createCheckout`.",
                    "schema": {
                        "type": "string",
                        "format": "uuid"
                    },
                    "example": "5d2f8a3c-6b1e-4c7a-9f0d-2e8b7a6c5d4f"
                }
            ],
            "delete": {
                "operationId": "cancelOrder",
                "tags": [
                    "Billing"
                ],
                "summary": "Cancel an order",
                "description": "Cancels an order that has not been fulfilled: one still awaiting payment, being built (`provisioning`) or waiting for room (`pending_deployment`). Nothing is charged, because a plan only starts once its server exists. Returns 400 for an order that is already fulfilled, cancelled or failed.",
                "x-scope": "billing.purchase",
                "responses": {
                    "200": {
                        "description": "The cancelled order.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/BillingOrderItem"
                                },
                                "example": {
                                    "object": "server_order",
                                    "attributes": {
                                        "uuid": "5d2f8a3c-6b1e-4c7a-9f0d-2e8b7a6c5d4f",
                                        "status": "cancelled"
                                    }
                                }
                            }
                        }
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthenticated"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    }
                }
            }
        },
        "/billing/subscriptions/{serverUuid}/cancel": {
            "parameters": [
                {
                    "name": "serverUuid",
                    "in": "path",
                    "required": true,
                    "description": "The full UUID of a server the account owns (not the 8-character identifier).",
                    "schema": {
                        "type": "string",
                        "format": "uuid"
                    },
                    "example": "1a7ce997-259b-452e-8b4e-cecc464142ca"
                }
            ],
            "post": {
                "operationId": "cancelSubscription",
                "tags": [
                    "Billing"
                ],
                "summary": "Downgrade a server at the end of its billing period",
                "description": "Schedules the server's paid plan to end at `current_period_end`; the server keeps its paid size until then and nothing is refunded. Reversible with `resumeSubscription` until that date. The owner is emailed. Returns 404 when the server is not the account's or has no live plan.",
                "x-scope": "billing.purchase",
                "responses": {
                    "200": {
                        "description": "The plan's new state.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/BillingSubscriptionItem"
                                },
                                "example": {
                                    "object": "server_subscription",
                                    "attributes": {
                                        "status": "active",
                                        "cancel_at_period_end": true,
                                        "current_period_end": "2026-11-01T12:00:00+00:00",
                                        "payment_issue": null,
                                        "immediate_downgrade": {
                                            "available": true,
                                            "reason": null,
                                            "refund_pence": 22,
                                            "fee_pence": 25,
                                            "available_at": null
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthenticated"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    }
                }
            }
        },
        "/billing/subscriptions/{serverUuid}/resume": {
            "parameters": [
                {
                    "name": "serverUuid",
                    "in": "path",
                    "required": true,
                    "description": "The full UUID of a server the account owns (not the 8-character identifier).",
                    "schema": {
                        "type": "string",
                        "format": "uuid"
                    },
                    "example": "1a7ce997-259b-452e-8b4e-cecc464142ca"
                }
            ],
            "post": {
                "operationId": "resumeSubscription",
                "tags": [
                    "Billing"
                ],
                "summary": "Keep a server's plan after scheduling a downgrade",
                "description": "Undoes `cancelSubscription`, so the plan renews as normal at `current_period_end`. No charge. Returns 404 when the server is not the account's or has no live plan.",
                "x-scope": "billing.purchase",
                "responses": {
                    "200": {
                        "description": "The plan's new state.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/BillingSubscriptionItem"
                                },
                                "example": {
                                    "object": "server_subscription",
                                    "attributes": {
                                        "status": "active",
                                        "cancel_at_period_end": false,
                                        "current_period_end": "2026-11-01T12:00:00+00:00",
                                        "payment_issue": null,
                                        "immediate_downgrade": {
                                            "available": true,
                                            "reason": null,
                                            "refund_pence": 22,
                                            "fee_pence": 25,
                                            "available_at": null
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthenticated"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    }
                }
            }
        },
        "/billing/subscriptions/{serverUuid}/cancel-immediately": {
            "parameters": [
                {
                    "name": "serverUuid",
                    "in": "path",
                    "required": true,
                    "description": "The full UUID of a server the account owns (not the 8-character identifier).",
                    "schema": {
                        "type": "string",
                        "format": "uuid"
                    },
                    "example": "1a7ce997-259b-452e-8b4e-cecc464142ca"
                }
            ],
            "post": {
                "operationId": "cancelSubscriptionImmediately",
                "tags": [
                    "Billing"
                ],
                "summary": "Downgrade a server now with a pro-rata refund",
                "description": "Ends the server's paid plan now and refunds the unused part of the current month, less a processing fee of 25p. The server then becomes a free server if the account has a free slot, and is suspended otherwise. Check `immediate_downgrade` in `GET /billing` first. Refused with 400 when the period renews in under 12 days, when the account already had one of these refunds in the last 30 days (`available_at` says when the next is allowed), or when the refund would be under 5p. If nothing was paid for the current period the plan still ends, without a refund. The owner is emailed about the refund.",
                "x-scope": "billing.purchase",
                "x-rate-limit": "10 per hour",
                "x-limits": {
                    "refunds_per_window": {
                        "value": 1
                    },
                    "refund_quota_days": {
                        "value": 30
                    },
                    "refund_fee_pence": {
                        "value": 25
                    },
                    "refund_minimum_pence": {
                        "value": 5
                    },
                    "blackout_days": {
                        "value": 12
                    },
                    "requests_per_hour": {
                        "value": 10
                    }
                },
                "responses": {
                    "200": {
                        "description": "The ended plan.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/BillingSubscriptionItem"
                                },
                                "example": {
                                    "object": "server_subscription",
                                    "attributes": {
                                        "status": "ended",
                                        "cancel_at_period_end": false,
                                        "current_period_end": "2026-11-01T12:00:00+00:00",
                                        "payment_issue": null,
                                        "immediate_downgrade": {
                                            "available": false,
                                            "reason": "no_payment",
                                            "refund_pence": 0,
                                            "fee_pence": 0,
                                            "available_at": null
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "400": {
                        "description": "An immediate downgrade is not allowed right now; the message says why and what to do instead.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                },
                                "example": {
                                    "errors": [
                                        {
                                            "code": "BadRequestHttpException",
                                            "status": "400",
                                            "detail": "You have already used an immediate downgrade recently. You can use another from Sun, Nov 1, 2026, or schedule a downgrade for your next billing date instead."
                                        }
                                    ]
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthenticated"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "429": {
                        "$ref": "#/components/responses/TooManyRequests"
                    }
                }
            }
        }
    },
    "components": {
        "securitySchemes": {
            "apiKey": {
                "type": "http",
                "scheme": "bearer",
                "description": "An account API key from the panel (Account, API keys), sent as\n`Authorization: Bearer sdevc_...`. Keys made before October 2026 start with `ptlc_`\nand keep working.\n"
            }
        },
        "parameters": {
            "Server": {
                "name": "server",
                "in": "path",
                "required": true,
                "description": "The server's 8-character identifier, as shown in the panel, or its full UUID.",
                "schema": {
                    "type": "string"
                },
                "example": "1a7ce997"
            },
            "Page": {
                "name": "page",
                "in": "query",
                "required": false,
                "description": "The page of results to return, starting at 1.",
                "schema": {
                    "type": "integer",
                    "minimum": 1,
                    "default": 1
                }
            },
            "PerPage": {
                "name": "per_page",
                "in": "query",
                "required": false,
                "description": "How many results to return on each page.",
                "schema": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 100
                }
            }
        },
        "responses": {
            "NoContent": {
                "description": "Done. There is no response body."
            },
            "BadRequest": {
                "description": "The request could not be carried out as sent. `detail` says why.",
                "content": {
                    "application/json": {
                        "schema": {
                            "$ref": "#/components/schemas/Error"
                        },
                        "example": {
                            "errors": [
                                {
                                    "code": "BadRequestHttpException",
                                    "status": "400",
                                    "detail": "The request could not be carried out."
                                }
                            ]
                        }
                    }
                }
            },
            "Unauthenticated": {
                "description": "No API key was sent, or it is wrong, expired or deleted.",
                "content": {
                    "application/json": {
                        "schema": {
                            "$ref": "#/components/schemas/Error"
                        },
                        "example": {
                            "errors": [
                                {
                                    "code": "AuthenticationException",
                                    "status": "401",
                                    "detail": "Unauthenticated."
                                }
                            ]
                        }
                    }
                }
            },
            "Forbidden": {
                "description": "The key is valid but may not do this: it lacks the permission or account scope, it is limited to other servers or IP addresses, or the account may not do it at all.",
                "content": {
                    "application/json": {
                        "schema": {
                            "$ref": "#/components/schemas/Error"
                        },
                        "example": {
                            "errors": [
                                {
                                    "code": "AccessDeniedHttpException",
                                    "status": "403",
                                    "detail": "This action is unauthorized."
                                }
                            ]
                        }
                    }
                }
            },
            "NotFound": {
                "description": "There is no such resource, or the key cannot see it. Features that are switched off answer 404 too.",
                "content": {
                    "application/json": {
                        "schema": {
                            "$ref": "#/components/schemas/Error"
                        },
                        "example": {
                            "errors": [
                                {
                                    "code": "NotFoundHttpException",
                                    "status": "404",
                                    "detail": "The requested resource could not be found on the server."
                                }
                            ]
                        }
                    }
                }
            },
            "Conflict": {
                "description": "The resource is busy or in a state that does not allow this right now.",
                "content": {
                    "application/json": {
                        "schema": {
                            "$ref": "#/components/schemas/Error"
                        },
                        "example": {
                            "errors": [
                                {
                                    "code": "ConflictHttpException",
                                    "status": "409",
                                    "detail": "This server is not in a state that allows this action."
                                }
                            ]
                        }
                    }
                }
            },
            "ValidationFailed": {
                "description": "Some fields were missing or invalid. There is one error per problem, and `meta.source_field` names the field.",
                "content": {
                    "application/json": {
                        "schema": {
                            "$ref": "#/components/schemas/Error"
                        },
                        "example": {
                            "errors": [
                                {
                                    "code": "ValidationException",
                                    "status": "422",
                                    "detail": "The name field is required.",
                                    "meta": {
                                        "source_field": "name",
                                        "rule": "required"
                                    }
                                }
                            ]
                        }
                    }
                }
            },
            "TooManyRequests": {
                "description": "Too many requests. Wait for the number of seconds in the `Retry-After` header, then try again.",
                "headers": {
                    "Retry-After": {
                        "description": "Seconds to wait before trying again.",
                        "schema": {
                            "type": "integer"
                        }
                    }
                },
                "content": {
                    "application/json": {
                        "schema": {
                            "$ref": "#/components/schemas/Error"
                        },
                        "example": {
                            "errors": [
                                {
                                    "code": "TooManyRequestsHttpException",
                                    "status": "429",
                                    "detail": "Too Many Attempts."
                                }
                            ]
                        }
                    }
                }
            }
        },
        "schemas": {
            "Error": {
                "type": "object",
                "required": [
                    "errors"
                ],
                "properties": {
                    "errors": {
                        "type": "array",
                        "items": {
                            "type": "object",
                            "required": [
                                "code",
                                "status",
                                "detail"
                            ],
                            "properties": {
                                "code": {
                                    "type": "string",
                                    "description": "The kind of error, e.g. `ValidationException`."
                                },
                                "status": {
                                    "type": "string",
                                    "description": "The HTTP status, as a string."
                                },
                                "detail": {
                                    "type": "string",
                                    "description": "A message you can show to a person."
                                },
                                "meta": {
                                    "type": "object",
                                    "properties": {
                                        "source_field": {
                                            "type": "string",
                                            "description": "For validation errors, the field at fault."
                                        },
                                        "rule": {
                                            "type": "string",
                                            "description": "For validation errors, the rule that failed."
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            },
            "Pagination": {
                "type": "object",
                "required": [
                    "pagination"
                ],
                "properties": {
                    "pagination": {
                        "type": "object",
                        "properties": {
                            "total": {
                                "type": "integer"
                            },
                            "count": {
                                "type": "integer"
                            },
                            "per_page": {
                                "type": "integer"
                            },
                            "current_page": {
                                "type": "integer"
                            },
                            "total_pages": {
                                "type": "integer"
                            },
                            "links": {
                                "type": "object",
                                "properties": {
                                    "previous": {
                                        "type": "string",
                                        "format": "uri"
                                    },
                                    "next": {
                                        "type": "string",
                                        "format": "uri"
                                    }
                                }
                            }
                        }
                    }
                }
            },
            "Server": {
                "type": "object",
                "description": "A server, as the key's user sees it.",
                "required": [
                    "server_owner",
                    "identifier",
                    "__deprecated_uuid_short",
                    "server_identifier",
                    "internal_id",
                    "uuid",
                    "name",
                    "node",
                    "is_node_under_maintenance",
                    "sftp_details",
                    "description",
                    "limits",
                    "invocation",
                    "docker_image",
                    "egg_features",
                    "feature_limits",
                    "status",
                    "is_paid",
                    "is_suspended",
                    "is_installing",
                    "is_transferring",
                    "skip_scripts"
                ],
                "properties": {
                    "server_owner": {
                        "type": "boolean",
                        "description": "Whether the key's user owns this server (rather than being a subuser or administrator)."
                    },
                    "identifier": {
                        "type": "string",
                        "description": "The 8-character identifier used in panel URLs and accepted by the `{server}` path parameter.",
                        "example": "1a7ce997"
                    },
                    "__deprecated_uuid_short": {
                        "type": "string",
                        "deprecated": true,
                        "description": "The same as `identifier`."
                    },
                    "server_identifier": {
                        "type": "string",
                        "description": "A prefixed internal identifier (`serv_...`). Not accepted in paths; use `identifier` or `uuid`.",
                        "example": "serv_DJ5MXFRFJ5JFFDSOJZHE5RQCUU"
                    },
                    "internal_id": {
                        "type": "integer",
                        "description": "The server's numeric database ID."
                    },
                    "uuid": {
                        "type": "string",
                        "format": "uuid"
                    },
                    "name": {
                        "type": "string"
                    },
                    "node": {
                        "type": "string",
                        "description": "The name of the node the server runs on."
                    },
                    "is_node_under_maintenance": {
                        "type": "boolean",
                        "description": "While true, most endpoints for the server answer 409."
                    },
                    "sftp_details": {
                        "type": "object",
                        "required": [
                            "ip",
                            "port"
                        ],
                        "properties": {
                            "ip": {
                                "type": "string",
                                "description": "The SFTP host name."
                            },
                            "port": {
                                "type": "integer"
                            }
                        }
                    },
                    "description": {
                        "type": [
                            "string",
                            "null"
                        ]
                    },
                    "limits": {
                        "type": "object",
                        "required": [
                            "memory",
                            "swap",
                            "disk",
                            "io",
                            "cpu",
                            "threads",
                            "oom_disabled"
                        ],
                        "properties": {
                            "memory": {
                                "type": "integer",
                                "description": "Memory limit in MiB. 0 means unlimited."
                            },
                            "swap": {
                                "type": "integer",
                                "description": "Swap in MiB. 0 means none and -1 unlimited."
                            },
                            "disk": {
                                "type": "integer",
                                "description": "Disk limit in MiB. 0 means unlimited."
                            },
                            "io": {
                                "type": "integer",
                                "description": "Block IO weight, 10 to 1000."
                            },
                            "cpu": {
                                "type": "integer",
                                "description": "CPU limit as a percentage of one core (100 is one core). 0 means unlimited."
                            },
                            "threads": {
                                "type": [
                                    "string",
                                    "null"
                                ],
                                "description": "The CPU cores the server is pinned to, e.g. `0-1,3`, or null for any."
                            },
                            "oom_disabled": {
                                "type": "boolean",
                                "description": "Whether the out-of-memory killer is disabled for the server."
                            }
                        }
                    },
                    "invocation": {
                        "type": "string",
                        "description": "The startup command with variables filled in. Without `startup.read` the variable values are hidden."
                    },
                    "docker_image": {
                        "type": "string"
                    },
                    "egg_features": {
                        "type": [
                            "array",
                            "null"
                        ],
                        "description": "Panel features the server's egg turns on.",
                        "items": {
                            "type": "string"
                        }
                    },
                    "feature_limits": {
                        "type": "object",
                        "required": [
                            "allocations",
                            "backups"
                        ],
                        "properties": {
                            "allocations": {
                                "type": "integer",
                                "description": "The most allocations (ports) the server may have."
                            },
                            "backups": {
                                "type": "integer",
                                "description": "The most backups the server may keep."
                            }
                        }
                    },
                    "status": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "description": "What the server is doing, or null when it is installed and available.\n- `installing`: the install script is running.\n- `install_failed` / `reinstall_failed`: the install script failed. A server whose first install failed can still be reinstalled.\n- `suspended`: suspended by an administrator.\n- `billing_suspended`: paused because its subscription is unpaid.\n- `restoring_backup`: a backup is being restored.\n- `deleting`: deletion has been accepted and the node is removing it.\n",
                        "enum": [
                            null,
                            "installing",
                            "install_failed",
                            "reinstall_failed",
                            "suspended",
                            "billing_suspended",
                            "restoring_backup",
                            "deleting"
                        ]
                    },
                    "is_paid": {
                        "type": "boolean",
                        "description": "Whether someone is currently paying for the server."
                    },
                    "is_suspended": {
                        "type": "boolean",
                        "deprecated": true,
                        "description": "True when `status` is `suspended` or `billing_suspended`. Use `status`."
                    },
                    "is_installing": {
                        "type": "boolean",
                        "deprecated": true,
                        "description": "True when `status` is `installing` or `install_failed`. Use `status`."
                    },
                    "is_transferring": {
                        "type": "boolean",
                        "description": "Whether the server is being moved to another node. Most endpoints answer 409 while it is."
                    },
                    "skip_scripts": {
                        "type": "boolean",
                        "description": "Whether the egg's install script is skipped for this server."
                    },
                    "relationships": {
                        "type": "object",
                        "properties": {
                            "allocations": {
                                "description": "The server's allocations. Always included. Without `allocation.read` only the primary allocation is listed, with `notes` null.",
                                "type": "object",
                                "required": [
                                    "object",
                                    "data"
                                ],
                                "properties": {
                                    "object": {
                                        "type": "string",
                                        "const": "list"
                                    },
                                    "data": {
                                        "type": "array",
                                        "items": {
                                            "type": "object",
                                            "required": [
                                                "object",
                                                "attributes"
                                            ],
                                            "properties": {
                                                "object": {
                                                    "type": "string",
                                                    "const": "allocation"
                                                },
                                                "attributes": {
                                                    "$ref": "#/components/schemas/ServerAllocation"
                                                }
                                            }
                                        }
                                    }
                                }
                            },
                            "variables": {
                                "description": "The startup variables you can see. Always included; a `null_resource` without `startup.read`.",
                                "oneOf": [
                                    {
                                        "$ref": "#/components/schemas/ServerStartupVariableList"
                                    },
                                    {
                                        "$ref": "#/components/schemas/ServerNullResource"
                                    }
                                ]
                            },
                            "egg": {
                                "description": "The egg (runtime template) the server uses. Only with `include=egg`.",
                                "type": "object",
                                "required": [
                                    "object",
                                    "attributes"
                                ],
                                "properties": {
                                    "object": {
                                        "type": "string",
                                        "const": "egg"
                                    },
                                    "attributes": {
                                        "type": "object",
                                        "required": [
                                            "uuid",
                                            "name"
                                        ],
                                        "properties": {
                                            "uuid": {
                                                "type": "string",
                                                "format": "uuid"
                                            },
                                            "name": {
                                                "type": "string"
                                            }
                                        }
                                    }
                                }
                            },
                            "subusers": {
                                "description": "The server's subusers. Only with `include=subusers`; a `null_resource` without `user.read`.",
                                "oneOf": [
                                    {
                                        "type": "object",
                                        "required": [
                                            "object",
                                            "data"
                                        ],
                                        "properties": {
                                            "object": {
                                                "type": "string",
                                                "const": "list"
                                            },
                                            "data": {
                                                "type": "array",
                                                "items": {
                                                    "type": "object",
                                                    "required": [
                                                        "object",
                                                        "attributes"
                                                    ],
                                                    "properties": {
                                                        "object": {
                                                            "type": "string",
                                                            "const": "server_subuser"
                                                        },
                                                        "attributes": {
                                                            "$ref": "#/components/schemas/ServerSubuser"
                                                        }
                                                    }
                                                }
                                            }
                                        }
                                    },
                                    {
                                        "$ref": "#/components/schemas/ServerNullResource"
                                    }
                                ]
                            }
                        }
                    }
                }
            },
            "ServerItem": {
                "type": "object",
                "required": [
                    "object",
                    "attributes"
                ],
                "properties": {
                    "object": {
                        "type": "string",
                        "const": "server"
                    },
                    "attributes": {
                        "$ref": "#/components/schemas/Server"
                    }
                }
            },
            "ServerList": {
                "type": "object",
                "required": [
                    "object",
                    "data",
                    "meta"
                ],
                "properties": {
                    "object": {
                        "type": "string",
                        "const": "list"
                    },
                    "data": {
                        "type": "array",
                        "items": {
                            "$ref": "#/components/schemas/ServerItem"
                        }
                    },
                    "meta": {
                        "allOf": [
                            {
                                "$ref": "#/components/schemas/Pagination"
                            },
                            {
                                "type": "object",
                                "properties": {
                                    "pending_orders": {
                                        "type": "array",
                                        "description": "Paid servers you have bought that do not exist yet. Only present when the account can buy paid servers.",
                                        "items": {
                                            "$ref": "#/components/schemas/ServerPendingOrder"
                                        }
                                    }
                                }
                            }
                        ]
                    }
                }
            },
            "ServerPendingOrder": {
                "type": "object",
                "required": [
                    "uuid",
                    "name",
                    "runtime",
                    "status",
                    "attempts",
                    "limits",
                    "created_at"
                ],
                "properties": {
                    "uuid": {
                        "type": "string",
                        "format": "uuid",
                        "description": "The order's UUID (not a server UUID)."
                    },
                    "name": {
                        "type": "string"
                    },
                    "runtime": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "description": "The runtime chosen, e.g. `nodejs`, `python` or `bun`."
                    },
                    "status": {
                        "type": "string",
                        "enum": [
                            "provisioning",
                            "pending_deployment"
                        ],
                        "description": "`provisioning` while the server is being created, `pending_deployment` while it waits for room on a node."
                    },
                    "attempts": {
                        "type": "integer",
                        "description": "How many times creating the server has been tried."
                    },
                    "limits": {
                        "type": "object",
                        "description": "The paid plan's limits.",
                        "required": [
                            "memory",
                            "disk",
                            "cpu"
                        ],
                        "properties": {
                            "memory": {
                                "type": "integer",
                                "description": "MiB."
                            },
                            "disk": {
                                "type": "integer",
                                "description": "MiB."
                            },
                            "cpu": {
                                "type": "integer",
                                "description": "Percent of one core."
                            }
                        }
                    },
                    "created_at": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "format": "date-time"
                    }
                }
            },
            "ServerAllocation": {
                "type": "object",
                "description": "An IP address and port assigned to a server.",
                "required": [
                    "id",
                    "ip",
                    "ip_alias",
                    "port",
                    "notes",
                    "is_default"
                ],
                "properties": {
                    "id": {
                        "type": "integer"
                    },
                    "ip": {
                        "type": "string"
                    },
                    "ip_alias": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "description": "A host name to show instead of the IP, if one is set."
                    },
                    "port": {
                        "type": "integer"
                    },
                    "notes": {
                        "type": [
                            "string",
                            "null"
                        ]
                    },
                    "is_default": {
                        "type": "boolean",
                        "description": "Whether this is the server's primary allocation."
                    }
                }
            },
            "ServerSubuser": {
                "type": "object",
                "description": "A user with access to a server they do not own.",
                "required": [
                    "uuid",
                    "identifier",
                    "username",
                    "email",
                    "image",
                    "2fa_enabled",
                    "created_at",
                    "permissions"
                ],
                "properties": {
                    "uuid": {
                        "type": "string",
                        "format": "uuid"
                    },
                    "identifier": {
                        "type": "string",
                        "description": "A prefixed user identifier (`user_...`)."
                    },
                    "username": {
                        "type": "string"
                    },
                    "email": {
                        "type": "string",
                        "format": "email"
                    },
                    "image": {
                        "type": "string",
                        "format": "uri",
                        "description": "Avatar URL."
                    },
                    "2fa_enabled": {
                        "type": "boolean"
                    },
                    "created_at": {
                        "type": "string",
                        "format": "date-time"
                    },
                    "permissions": {
                        "type": "array",
                        "description": "The subuser's permissions on the server.",
                        "items": {
                            "type": "string"
                        }
                    }
                }
            },
            "ServerNullResource": {
                "type": "object",
                "description": "Stands in for a relationship you are not allowed to see.",
                "required": [
                    "object",
                    "attributes"
                ],
                "properties": {
                    "object": {
                        "type": "string",
                        "const": "null_resource"
                    },
                    "attributes": {
                        "type": "null"
                    }
                }
            },
            "ServerPermissionList": {
                "type": "object",
                "required": [
                    "object",
                    "attributes"
                ],
                "properties": {
                    "object": {
                        "type": "string",
                        "const": "system_permissions"
                    },
                    "attributes": {
                        "type": "object",
                        "required": [
                            "permissions"
                        ],
                        "properties": {
                            "permissions": {
                                "type": "object",
                                "description": "Permission groups by name (e.g. `control`, `file`).",
                                "additionalProperties": {
                                    "type": "object",
                                    "required": [
                                        "description",
                                        "keys"
                                    ],
                                    "properties": {
                                        "description": {
                                            "type": "string"
                                        },
                                        "keys": {
                                            "type": "object",
                                            "description": "Each permission in the group (written `group.key`) and what it allows.",
                                            "additionalProperties": {
                                                "type": "string"
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            },
            "ServerResources": {
                "type": "object",
                "required": [
                    "current_state",
                    "is_suspended",
                    "is_booting",
                    "resources"
                ],
                "properties": {
                    "current_state": {
                        "type": "string",
                        "enum": [
                            "offline",
                            "starting",
                            "running",
                            "stopping"
                        ]
                    },
                    "is_suspended": {
                        "type": "boolean"
                    },
                    "is_booting": {
                        "type": "boolean",
                        "description": "True while the node is still loading the server after a restart."
                    },
                    "resources": {
                        "type": "object",
                        "required": [
                            "memory_bytes",
                            "cpu_absolute",
                            "disk_bytes",
                            "network_rx_bytes",
                            "network_tx_bytes",
                            "uptime"
                        ],
                        "properties": {
                            "memory_bytes": {
                                "type": "integer"
                            },
                            "cpu_absolute": {
                                "type": "number",
                                "description": "CPU use as a percentage of one core, e.g. 150 is one and a half cores."
                            },
                            "disk_bytes": {
                                "type": "integer"
                            },
                            "network_rx_bytes": {
                                "type": "integer",
                                "description": "Bytes received since the server started."
                            },
                            "network_tx_bytes": {
                                "type": "integer",
                                "description": "Bytes sent since the server started."
                            },
                            "uptime": {
                                "type": "integer",
                                "description": "Milliseconds since the server started. 0 when offline."
                            }
                        }
                    }
                }
            },
            "ServerResourcesItem": {
                "type": "object",
                "required": [
                    "object",
                    "attributes"
                ],
                "properties": {
                    "object": {
                        "type": "string",
                        "const": "stats"
                    },
                    "attributes": {
                        "$ref": "#/components/schemas/ServerResources"
                    }
                }
            },
            "ServerWebsocketCredentials": {
                "type": "object",
                "required": [
                    "data"
                ],
                "properties": {
                    "data": {
                        "type": "object",
                        "required": [
                            "token",
                            "socket"
                        ],
                        "properties": {
                            "token": {
                                "type": "string",
                                "description": "A signed token valid for 10 minutes. Send it in the `auth` event."
                            },
                            "socket": {
                                "type": "string",
                                "format": "uri",
                                "description": "The websocket URL (`wss://`) on the server's node."
                            }
                        }
                    }
                }
            },
            "ServerStartupVariable": {
                "type": "object",
                "description": "A startup variable of the server's egg.",
                "required": [
                    "name",
                    "description",
                    "env_variable",
                    "default_value",
                    "server_value",
                    "is_editable",
                    "rules"
                ],
                "properties": {
                    "name": {
                        "type": "string"
                    },
                    "description": {
                        "type": [
                            "string",
                            "null"
                        ]
                    },
                    "env_variable": {
                        "type": "string",
                        "description": "The environment variable name, used as `key` when changing it."
                    },
                    "default_value": {
                        "type": [
                            "string",
                            "null"
                        ]
                    },
                    "server_value": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "description": "This server's value."
                    },
                    "is_editable": {
                        "type": "boolean",
                        "description": "Whether you may change it."
                    },
                    "rules": {
                        "type": "string",
                        "description": "Laravel validation rules the value must satisfy, e.g. `required|string|max:64`."
                    }
                }
            },
            "ServerStartupVariableItem": {
                "type": "object",
                "required": [
                    "object",
                    "attributes"
                ],
                "properties": {
                    "object": {
                        "type": "string",
                        "const": "egg_variable"
                    },
                    "attributes": {
                        "$ref": "#/components/schemas/ServerStartupVariable"
                    }
                }
            },
            "ServerStartupVariableList": {
                "type": "object",
                "required": [
                    "object",
                    "data"
                ],
                "properties": {
                    "object": {
                        "type": "string",
                        "const": "list"
                    },
                    "data": {
                        "type": "array",
                        "items": {
                            "$ref": "#/components/schemas/ServerStartupVariableItem"
                        }
                    }
                }
            },
            "ActivityLogEntry": {
                "type": "object",
                "description": "One thing that was done, by whom and when.",
                "required": [
                    "id",
                    "batch",
                    "event",
                    "is_api",
                    "ip",
                    "description",
                    "properties",
                    "has_additional_metadata",
                    "timestamp"
                ],
                "properties": {
                    "id": {
                        "type": "string",
                        "description": "A stable unique key for the entry (a hash, not a database ID)."
                    },
                    "batch": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "format": "uuid",
                        "description": "Shared by entries logged together as part of one action."
                    },
                    "event": {
                        "type": "string",
                        "description": "The event name, e.g. `server:power.start` or `server:file.write`."
                    },
                    "is_api": {
                        "type": "boolean",
                        "description": "Whether it was done with an API key."
                    },
                    "ip": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "description": "The IP address it came from. Only shown for your own actions (or to administrators)."
                    },
                    "description": {
                        "type": [
                            "string",
                            "null"
                        ]
                    },
                    "properties": {
                        "type": "object",
                        "description": "Details of the event, which vary by event. List values also get a `<key>_count` entry (or `count`, if there is only one list). An `ip` property is `[hidden]` unless it was your action.",
                        "additionalProperties": true
                    },
                    "has_additional_metadata": {
                        "type": "boolean",
                        "description": "Whether `properties` holds anything beyond what the event's description already says."
                    },
                    "timestamp": {
                        "type": "string",
                        "format": "date-time"
                    },
                    "relationships": {
                        "type": "object",
                        "properties": {
                            "actor": {
                                "description": "Who did it. Only with `include=actor`; a `null_resource` if it was not a user (e.g. the system or a schedule).",
                                "oneOf": [
                                    {
                                        "type": "object",
                                        "required": [
                                            "object",
                                            "attributes"
                                        ],
                                        "properties": {
                                            "object": {
                                                "type": "string",
                                                "const": "user"
                                            },
                                            "attributes": {
                                                "type": "object",
                                                "required": [
                                                    "uuid",
                                                    "identifier",
                                                    "username",
                                                    "email",
                                                    "image",
                                                    "2fa_enabled",
                                                    "created_at"
                                                ],
                                                "properties": {
                                                    "uuid": {
                                                        "type": "string",
                                                        "format": "uuid"
                                                    },
                                                    "identifier": {
                                                        "type": "string"
                                                    },
                                                    "username": {
                                                        "type": "string"
                                                    },
                                                    "email": {
                                                        "type": "string",
                                                        "format": "email"
                                                    },
                                                    "image": {
                                                        "type": "string",
                                                        "format": "uri"
                                                    },
                                                    "2fa_enabled": {
                                                        "type": "boolean"
                                                    },
                                                    "created_at": {
                                                        "type": "string",
                                                        "format": "date-time"
                                                    }
                                                }
                                            }
                                        }
                                    },
                                    {
                                        "$ref": "#/components/schemas/ServerNullResource"
                                    }
                                ]
                            }
                        }
                    }
                }
            },
            "ServerActivity": {
                "type": "object",
                "required": [
                    "object",
                    "attributes"
                ],
                "properties": {
                    "object": {
                        "type": "string",
                        "const": "activity_log"
                    },
                    "attributes": {
                        "$ref": "#/components/schemas/ActivityLogEntry"
                    }
                }
            },
            "ServerActivityList": {
                "type": "object",
                "required": [
                    "object",
                    "data",
                    "meta"
                ],
                "properties": {
                    "object": {
                        "type": "string",
                        "const": "list"
                    },
                    "data": {
                        "type": "array",
                        "items": {
                            "$ref": "#/components/schemas/ServerActivity"
                        }
                    },
                    "meta": {
                        "$ref": "#/components/schemas/Pagination"
                    }
                }
            },
            "FileObjectAttributes": {
                "type": "object",
                "required": [
                    "name",
                    "mode",
                    "mode_bits",
                    "size",
                    "is_file",
                    "is_symlink",
                    "mimetype",
                    "created_at",
                    "modified_at"
                ],
                "properties": {
                    "name": {
                        "type": "string",
                        "description": "The file or folder name, without its directory."
                    },
                    "mode": {
                        "type": "string",
                        "description": "The permissions as `ls -l` shows them, e.g. `-rw-r--r--`."
                    },
                    "mode_bits": {
                        "type": "string",
                        "description": "The permission bits in octal, e.g. `644`."
                    },
                    "size": {
                        "type": "integer",
                        "description": "Size in bytes. For a folder this is the size of the folder entry, not its contents."
                    },
                    "is_file": {
                        "type": "boolean",
                        "description": "False for folders."
                    },
                    "is_symlink": {
                        "type": "boolean"
                    },
                    "mimetype": {
                        "type": "string",
                        "description": "The detected MIME type; `inode/directory` for folders."
                    },
                    "created_at": {
                        "type": "string",
                        "format": "date-time"
                    },
                    "modified_at": {
                        "type": "string",
                        "format": "date-time"
                    }
                }
            },
            "FileObject": {
                "type": "object",
                "required": [
                    "object",
                    "attributes"
                ],
                "properties": {
                    "object": {
                        "type": "string",
                        "const": "file_object"
                    },
                    "attributes": {
                        "$ref": "#/components/schemas/FileObjectAttributes"
                    }
                }
            },
            "FileObjectList": {
                "type": "object",
                "required": [
                    "object",
                    "data"
                ],
                "properties": {
                    "object": {
                        "type": "string",
                        "const": "list"
                    },
                    "data": {
                        "type": "array",
                        "items": {
                            "$ref": "#/components/schemas/FileObject"
                        }
                    }
                }
            },
            "FileSignedUrl": {
                "type": "object",
                "required": [
                    "object",
                    "attributes"
                ],
                "properties": {
                    "object": {
                        "type": "string",
                        "const": "signed_url"
                    },
                    "attributes": {
                        "type": "object",
                        "required": [
                            "url"
                        ],
                        "properties": {
                            "url": {
                                "type": "string",
                                "format": "uri",
                                "description": "The single-use URL on the server's node, valid for 15 minutes."
                            }
                        }
                    }
                }
            },
            "FileGitNotice": {
                "type": "object",
                "required": [
                    "linked"
                ],
                "properties": {
                    "linked": {
                        "type": "boolean",
                        "description": "Whether a Git repository is linked to the server."
                    },
                    "provider": {
                        "type": "string",
                        "enum": [
                            "github",
                            "gitlab",
                            "url"
                        ],
                        "description": "Where the repository is hosted; `url` is any other Git URL. Only when linked."
                    },
                    "directory": {
                        "type": "string",
                        "description": "The folder the repository deploys into, e.g. `/` or `/bot`. Only when linked."
                    },
                    "auto_deploy": {
                        "type": "boolean",
                        "description": "Whether pushes deploy automatically. Only when linked."
                    }
                }
            },
            "BackupAttributes": {
                "type": "object",
                "required": [
                    "uuid",
                    "is_successful",
                    "is_locked",
                    "name",
                    "ignored_files",
                    "checksum",
                    "bytes",
                    "created_at",
                    "completed_at"
                ],
                "properties": {
                    "uuid": {
                        "type": "string",
                        "format": "uuid",
                        "description": "The backup's ID, used in the URLs of the other backup endpoints."
                    },
                    "is_successful": {
                        "type": "boolean",
                        "description": "True once the backup has finished successfully. False while it is in progress (`completed_at` is null) and when it failed."
                    },
                    "is_locked": {
                        "type": "boolean",
                        "description": "A locked backup cannot be deleted."
                    },
                    "name": {
                        "type": "string"
                    },
                    "ignored_files": {
                        "type": "array",
                        "description": "The ignore patterns given when the backup was made, one per item.",
                        "items": {
                            "type": "string"
                        }
                    },
                    "checksum": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "description": "The archive's checksum as `<algorithm>:<hex>`, e.g. `sha1:...`. Null until it succeeds."
                    },
                    "bytes": {
                        "type": "integer",
                        "description": "The archive's size in bytes. 0 until it completes."
                    },
                    "created_at": {
                        "type": "string",
                        "format": "date-time"
                    },
                    "completed_at": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "format": "date-time",
                        "description": "When the backup finished, successfully or not. Null while in progress."
                    }
                }
            },
            "Backup": {
                "type": "object",
                "required": [
                    "object",
                    "attributes"
                ],
                "properties": {
                    "object": {
                        "type": "string",
                        "const": "backup"
                    },
                    "attributes": {
                        "$ref": "#/components/schemas/BackupAttributes"
                    }
                }
            },
            "BackupList": {
                "type": "object",
                "required": [
                    "object",
                    "data",
                    "meta"
                ],
                "properties": {
                    "object": {
                        "type": "string",
                        "const": "list"
                    },
                    "data": {
                        "type": "array",
                        "items": {
                            "$ref": "#/components/schemas/Backup"
                        }
                    },
                    "meta": {
                        "allOf": [
                            {
                                "$ref": "#/components/schemas/Pagination"
                            },
                            {
                                "type": "object",
                                "required": [
                                    "backup_count"
                                ],
                                "properties": {
                                    "backup_count": {
                                        "type": "integer",
                                        "description": "How many of the server's backups count towards its limit: those in progress or successful, on every page."
                                    }
                                }
                            }
                        ]
                    }
                }
            },
            "BackupSignedUrl": {
                "type": "object",
                "required": [
                    "object",
                    "attributes"
                ],
                "properties": {
                    "object": {
                        "type": "string",
                        "const": "signed_url"
                    },
                    "attributes": {
                        "type": "object",
                        "required": [
                            "url"
                        ],
                        "properties": {
                            "url": {
                                "type": "string",
                                "format": "uri",
                                "description": "Where to download the archive: a single-use URL on the node valid for 15 minutes, or a pre-signed S3 URL valid for 5 minutes."
                            }
                        }
                    }
                }
            },
            "ScheduleCron": {
                "type": "object",
                "description": "The five fields of a standard cron expression, in the panel's timezone.",
                "required": [
                    "day_of_week",
                    "day_of_month",
                    "month",
                    "hour",
                    "minute"
                ],
                "properties": {
                    "day_of_week": {
                        "type": "string",
                        "example": "*"
                    },
                    "day_of_month": {
                        "type": "string",
                        "example": "*"
                    },
                    "month": {
                        "type": "string",
                        "example": "*"
                    },
                    "hour": {
                        "type": "string",
                        "example": "4"
                    },
                    "minute": {
                        "type": "string",
                        "example": "0"
                    }
                }
            },
            "ScheduleAttributes": {
                "type": "object",
                "required": [
                    "id",
                    "name",
                    "cron",
                    "is_active",
                    "is_processing",
                    "only_when_online",
                    "last_run_at",
                    "next_run_at",
                    "created_at",
                    "updated_at"
                ],
                "properties": {
                    "id": {
                        "type": "integer"
                    },
                    "name": {
                        "type": "string"
                    },
                    "cron": {
                        "$ref": "#/components/schemas/ScheduleCron"
                    },
                    "is_active": {
                        "type": "boolean",
                        "description": "Whether the schedule runs on its timetable."
                    },
                    "is_processing": {
                        "type": "boolean",
                        "description": "True while the schedule's tasks are being worked through."
                    },
                    "only_when_online": {
                        "type": "boolean",
                        "description": "When true, a timed run is skipped if the server is offline or stopping. Manual runs ignore this."
                    },
                    "last_run_at": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "format": "date-time"
                    },
                    "next_run_at": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "format": "date-time"
                    },
                    "created_at": {
                        "type": "string",
                        "format": "date-time"
                    },
                    "updated_at": {
                        "type": "string",
                        "format": "date-time"
                    },
                    "relationships": {
                        "type": "object",
                        "properties": {
                            "tasks": {
                                "$ref": "#/components/schemas/ScheduleTaskList"
                            }
                        }
                    }
                }
            },
            "Schedule": {
                "type": "object",
                "required": [
                    "object",
                    "attributes"
                ],
                "properties": {
                    "object": {
                        "type": "string",
                        "const": "server_schedule"
                    },
                    "attributes": {
                        "$ref": "#/components/schemas/ScheduleAttributes"
                    }
                }
            },
            "ScheduleList": {
                "type": "object",
                "required": [
                    "object",
                    "data"
                ],
                "properties": {
                    "object": {
                        "type": "string",
                        "const": "list"
                    },
                    "data": {
                        "type": "array",
                        "items": {
                            "$ref": "#/components/schemas/Schedule"
                        }
                    }
                }
            },
            "ScheduleRequest": {
                "type": "object",
                "required": [
                    "name",
                    "minute",
                    "hour",
                    "day_of_month",
                    "month",
                    "day_of_week"
                ],
                "properties": {
                    "name": {
                        "type": "string",
                        "maxLength": 191
                    },
                    "minute": {
                        "type": "string",
                        "description": "Cron minute field, such as `0`, `*/5` or `0,30`."
                    },
                    "hour": {
                        "type": "string",
                        "description": "Cron hour field."
                    },
                    "day_of_month": {
                        "type": "string",
                        "description": "Cron day-of-month field."
                    },
                    "month": {
                        "type": "string",
                        "description": "Cron month field. Always send it, `*` for every month."
                    },
                    "day_of_week": {
                        "type": "string",
                        "description": "Cron day-of-week field, `0` or `7` being Sunday."
                    },
                    "is_active": {
                        "type": "boolean",
                        "default": false,
                        "description": "Whether the schedule runs on its timetable. False when left out."
                    },
                    "only_when_online": {
                        "type": "boolean",
                        "default": false,
                        "description": "Skip timed runs while the server is offline or stopping. False when left out."
                    }
                }
            },
            "ScheduleTaskAttributes": {
                "type": "object",
                "required": [
                    "id",
                    "sequence_id",
                    "action",
                    "payload",
                    "time_offset",
                    "is_queued",
                    "continue_on_failure",
                    "created_at",
                    "updated_at"
                ],
                "properties": {
                    "id": {
                        "type": "integer"
                    },
                    "sequence_id": {
                        "type": "integer",
                        "minimum": 1,
                        "description": "The task's place in the schedule, starting at 1."
                    },
                    "action": {
                        "type": "string",
                        "enum": [
                            "command",
                            "power",
                            "backup"
                        ]
                    },
                    "payload": {
                        "type": "string",
                        "description": "For `command`, the console command. For `power`, one of `start`, `stop`, `restart` or `kill`. For `backup`, files to leave out of the backup, one pattern per line, or an empty string."
                    },
                    "time_offset": {
                        "type": "integer",
                        "minimum": 0,
                        "maximum": 900,
                        "description": "Seconds to wait after the previous task (or after the schedule starts) before running."
                    },
                    "is_queued": {
                        "type": "boolean",
                        "description": "True while the task is waiting to run."
                    },
                    "continue_on_failure": {
                        "type": "boolean",
                        "description": "When true, the schedule carries on with the next task if this one fails because the node could not be reached or refused it. Otherwise the schedule stops there."
                    },
                    "created_at": {
                        "type": "string",
                        "format": "date-time"
                    },
                    "updated_at": {
                        "type": "string",
                        "format": "date-time"
                    }
                }
            },
            "ScheduleTask": {
                "type": "object",
                "required": [
                    "object",
                    "attributes"
                ],
                "properties": {
                    "object": {
                        "type": "string",
                        "const": "schedule_task"
                    },
                    "attributes": {
                        "$ref": "#/components/schemas/ScheduleTaskAttributes"
                    }
                }
            },
            "ScheduleTaskList": {
                "type": "object",
                "required": [
                    "object",
                    "data"
                ],
                "properties": {
                    "object": {
                        "type": "string",
                        "const": "list"
                    },
                    "data": {
                        "type": "array",
                        "items": {
                            "$ref": "#/components/schemas/ScheduleTask"
                        }
                    }
                }
            },
            "ScheduleTaskRequest": {
                "type": "object",
                "required": [
                    "action",
                    "time_offset"
                ],
                "properties": {
                    "action": {
                        "type": "string",
                        "enum": [
                            "command",
                            "power",
                            "backup"
                        ]
                    },
                    "payload": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "description": "Required unless `action` is `backup`. For `command`, the console command; for `power`, one of `start`, `stop`, `restart` or `kill`; for `backup`, optional patterns of files to leave out, one per line."
                    },
                    "time_offset": {
                        "type": "integer",
                        "minimum": 0,
                        "maximum": 900,
                        "description": "Seconds to wait after the previous task before running this one."
                    },
                    "sequence_id": {
                        "type": "integer",
                        "minimum": 1,
                        "description": "Where to put the task. Left out, a new task goes at the end and an existing one stays where it is."
                    },
                    "continue_on_failure": {
                        "type": "boolean",
                        "default": false,
                        "description": "Carry on with the next task if this one fails to reach the server. False when left out."
                    }
                }
            },
            "AllocationAttributes": {
                "type": "object",
                "required": [
                    "id",
                    "ip",
                    "ip_alias",
                    "port",
                    "notes",
                    "is_default"
                ],
                "properties": {
                    "id": {
                        "type": "integer"
                    },
                    "ip": {
                        "type": "string",
                        "description": "The IP address the port is on."
                    },
                    "ip_alias": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "description": "A hostname to show instead of the IP, if one is set."
                    },
                    "port": {
                        "type": "integer"
                    },
                    "notes": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "maxLength": 256
                    },
                    "is_default": {
                        "type": "boolean",
                        "description": "Whether this is the server's primary allocation."
                    }
                }
            },
            "Allocation": {
                "type": "object",
                "required": [
                    "object",
                    "attributes"
                ],
                "properties": {
                    "object": {
                        "type": "string",
                        "const": "allocation"
                    },
                    "attributes": {
                        "$ref": "#/components/schemas/AllocationAttributes"
                    }
                }
            },
            "AllocationList": {
                "type": "object",
                "required": [
                    "object",
                    "data"
                ],
                "properties": {
                    "object": {
                        "type": "string",
                        "const": "list"
                    },
                    "data": {
                        "type": "array",
                        "items": {
                            "$ref": "#/components/schemas/Allocation"
                        }
                    }
                }
            },
            "AllocationNotesRequest": {
                "type": "object",
                "required": [
                    "notes"
                ],
                "properties": {
                    "notes": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "maxLength": 256
                    }
                }
            },
            "SubuserAttributes": {
                "type": "object",
                "required": [
                    "uuid",
                    "identifier",
                    "username",
                    "email",
                    "image",
                    "2fa_enabled",
                    "created_at",
                    "permissions"
                ],
                "properties": {
                    "uuid": {
                        "type": "string",
                        "format": "uuid",
                        "description": "The account's UUID, used as `{user}` in the subuser paths."
                    },
                    "identifier": {
                        "type": "string",
                        "description": "The account's public identifier.",
                        "example": "user_l4gc3dr3djgh3hrpnkfqyhjoh4"
                    },
                    "username": {
                        "type": "string"
                    },
                    "email": {
                        "type": "string",
                        "format": "email"
                    },
                    "image": {
                        "type": "string",
                        "format": "uri",
                        "description": "Gravatar URL for the email address; it answers 404 if there is no Gravatar."
                    },
                    "2fa_enabled": {
                        "type": "boolean"
                    },
                    "created_at": {
                        "type": "string",
                        "format": "date-time",
                        "description": "When the account was created."
                    },
                    "permissions": {
                        "type": "array",
                        "description": "The subuser's permissions on this server. See `listPermissions` for every one.",
                        "items": {
                            "type": "string"
                        },
                        "example": [
                            "websocket.connect",
                            "control.console"
                        ]
                    }
                }
            },
            "Subuser": {
                "type": "object",
                "required": [
                    "object",
                    "attributes"
                ],
                "properties": {
                    "object": {
                        "type": "string",
                        "const": "server_subuser"
                    },
                    "attributes": {
                        "$ref": "#/components/schemas/SubuserAttributes"
                    }
                }
            },
            "SubuserList": {
                "type": "object",
                "required": [
                    "object",
                    "data"
                ],
                "properties": {
                    "object": {
                        "type": "string",
                        "const": "list"
                    },
                    "data": {
                        "type": "array",
                        "items": {
                            "$ref": "#/components/schemas/Subuser"
                        }
                    }
                }
            },
            "SubuserCreateRequest": {
                "type": "object",
                "required": [
                    "email",
                    "permissions"
                ],
                "properties": {
                    "email": {
                        "type": "string",
                        "format": "email",
                        "maxLength": 191
                    },
                    "permissions": {
                        "type": "array",
                        "description": "Permission strings such as `control.console` or `file.read`. Unknown ones are dropped and `websocket.connect` is always added. See `listPermissions`.",
                        "items": {
                            "type": "string"
                        }
                    }
                }
            },
            "SubuserUpdateRequest": {
                "type": "object",
                "required": [
                    "permissions"
                ],
                "properties": {
                    "permissions": {
                        "type": "array",
                        "description": "The full new set of permissions. See `listPermissions`.",
                        "items": {
                            "type": "string"
                        }
                    }
                }
            },
            "GitInstallation": {
                "type": "object",
                "description": "A GitHub App installation you connected in the panel.",
                "required": [
                    "id",
                    "account",
                    "type",
                    "suspended"
                ],
                "properties": {
                    "id": {
                        "type": "integer",
                        "description": "The panel's ID for the installation, sent as `installation` when linking. Not GitHub's own ID."
                    },
                    "account": {
                        "type": "string",
                        "description": "The GitHub user or organisation it is installed on."
                    },
                    "type": {
                        "type": "string",
                        "description": "`User` or `Organization`."
                    },
                    "suspended": {
                        "type": "boolean"
                    }
                }
            },
            "GitRepository": {
                "type": "object",
                "required": [
                    "source",
                    "repository",
                    "url",
                    "branch",
                    "directory",
                    "auto_deploy",
                    "restart_on_deploy",
                    "start_if_offline",
                    "apply_config",
                    "sync_startup",
                    "installation",
                    "account",
                    "disconnected",
                    "last_deployed_at"
                ],
                "properties": {
                    "source": {
                        "type": "string",
                        "enum": [
                            "github",
                            "gitlab",
                            "url"
                        ]
                    },
                    "repository": {
                        "type": "string",
                        "description": "`owner/name` for GitHub, `group/name` for GitLab, or the https clone URL."
                    },
                    "url": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "description": "The repository's web page."
                    },
                    "branch": {
                        "type": "string"
                    },
                    "directory": {
                        "type": "string",
                        "description": "The folder on the server the repository is deployed into, `/` for the root."
                    },
                    "auto_deploy": {
                        "type": "boolean",
                        "description": "Deploy on every push to the branch. Always false for `url`."
                    },
                    "restart_on_deploy": {
                        "type": "boolean",
                        "description": "Restart the server after deploying if it is running."
                    },
                    "start_if_offline": {
                        "type": "boolean",
                        "description": "Start the server after deploying if it is offline."
                    },
                    "apply_config": {
                        "type": "boolean",
                        "description": "Apply the repository's `sillydev.conf` to the server on each deployment."
                    },
                    "sync_startup": {
                        "type": "boolean",
                        "description": "Write changes made in the panel's Startup tab back to `sillydev.conf` when the file sets that setting and the panel can write to the repository."
                    },
                    "installation": {
                        "oneOf": [
                            {
                                "$ref": "#/components/schemas/GitInstallation"
                            },
                            {
                                "type": "null"
                            }
                        ]
                    },
                    "account": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "description": "The GitHub or GitLab account the repository is linked through."
                    },
                    "disconnected": {
                        "type": "boolean",
                        "description": "True when the GitHub installation or GitLab account it was linked through has been removed. Reconnect in the panel and link it again."
                    },
                    "last_deployed_at": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "format": "date-time",
                        "description": "When the last deployment started."
                    }
                }
            },
            "GitConfigStatus": {
                "type": "object",
                "description": "How the repository's `sillydev.conf`, as the last deployment found it, compares with what the server supports. Only setting names, never values.",
                "required": [
                    "filename",
                    "version",
                    "apply",
                    "can_write",
                    "checked_at",
                    "state"
                ],
                "properties": {
                    "filename": {
                        "type": "string",
                        "const": "sillydev.conf"
                    },
                    "version": {
                        "type": "integer",
                        "description": "The current file format version."
                    },
                    "apply": {
                        "type": "boolean"
                    },
                    "can_write": {
                        "type": "boolean",
                        "description": "Whether the panel can commit to the repository (linked through GitHub or GitLab)."
                    },
                    "checked_at": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "format": "date-time"
                    },
                    "state": {
                        "type": "string",
                        "enum": [
                            "unknown",
                            "absent",
                            "current",
                            "outdated"
                        ],
                        "description": "`unknown` until a deployment has looked; `absent` if the repository has no file."
                    },
                    "missing": {
                        "type": "array",
                        "items": {
                            "type": "string"
                        },
                        "description": "Settings the server supports that the file does not mention."
                    },
                    "unsupported": {
                        "type": "array",
                        "items": {
                            "type": "string"
                        },
                        "description": "Settings in the file the server does not support."
                    },
                    "invalid": {
                        "type": "array",
                        "items": {
                            "type": "string"
                        },
                        "description": "Settings whose value in the file is not allowed."
                    },
                    "version_outdated": {
                        "type": "boolean"
                    },
                    "problems": {
                        "type": "integer",
                        "description": "How many lines of the file could not be read."
                    },
                    "differs": {
                        "type": "array",
                        "items": {
                            "type": "string"
                        },
                        "description": "Settings set differently in the file than on the server."
                    }
                }
            },
            "GitDeployment": {
                "type": "object",
                "required": [
                    "uuid",
                    "trigger",
                    "status",
                    "branch",
                    "commit",
                    "user",
                    "error",
                    "files",
                    "power_action",
                    "attempts",
                    "config",
                    "run_after",
                    "started_at",
                    "completed_at",
                    "created_at"
                ],
                "properties": {
                    "uuid": {
                        "type": "string",
                        "format": "uuid"
                    },
                    "trigger": {
                        "type": "string",
                        "enum": [
                            "manual",
                            "push"
                        ]
                    },
                    "status": {
                        "type": "string",
                        "enum": [
                            "queued",
                            "running",
                            "succeeded",
                            "failed",
                            "superseded",
                            "cancelled"
                        ],
                        "description": "`superseded` means a newer deployment replaced it while it waited."
                    },
                    "branch": {
                        "type": "string"
                    },
                    "commit": {
                        "type": "object",
                        "required": [
                            "sha",
                            "message",
                            "author",
                            "url"
                        ],
                        "description": "Filled in once known; a manual deployment learns its commit when it runs.",
                        "properties": {
                            "sha": {
                                "type": [
                                    "string",
                                    "null"
                                ]
                            },
                            "message": {
                                "type": [
                                    "string",
                                    "null"
                                ]
                            },
                            "author": {
                                "type": [
                                    "string",
                                    "null"
                                ]
                            },
                            "url": {
                                "type": [
                                    "string",
                                    "null"
                                ]
                            }
                        }
                    },
                    "user": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "description": "Username of whoever started it by hand; null for a push."
                    },
                    "error": {
                        "type": [
                            "string",
                            "null"
                        ]
                    },
                    "files": {
                        "description": "File counts once the deployment has finished.",
                        "oneOf": [
                            {
                                "type": "object",
                                "required": [
                                    "written",
                                    "deleted",
                                    "unchanged",
                                    "kept"
                                ],
                                "properties": {
                                    "written": {
                                        "type": "integer"
                                    },
                                    "deleted": {
                                        "type": "integer"
                                    },
                                    "unchanged": {
                                        "type": "integer"
                                    },
                                    "kept": {
                                        "type": "integer"
                                    }
                                }
                            },
                            {
                                "type": "null"
                            }
                        ]
                    },
                    "power_action": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "enum": [
                            "start",
                            "restart",
                            null
                        ],
                        "description": "What was done to the server afterwards, if anything."
                    },
                    "attempts": {
                        "type": "integer",
                        "description": "How many earlier tries failed for a passing reason. A deployment is tried up to 3 times."
                    },
                    "config": {
                        "description": "What was applied from `sillydev.conf`, if anything.",
                        "oneOf": [
                            {
                                "type": "object",
                                "required": [
                                    "applied",
                                    "warnings"
                                ],
                                "properties": {
                                    "applied": {
                                        "type": "array",
                                        "items": {
                                            "type": "string"
                                        }
                                    },
                                    "warnings": {
                                        "type": "array",
                                        "items": {
                                            "type": "string"
                                        }
                                    }
                                }
                            },
                            {
                                "type": "null"
                            }
                        ]
                    },
                    "run_after": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "format": "date-time",
                        "description": "The earliest the deployment may start under the rate limit."
                    },
                    "started_at": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "format": "date-time"
                    },
                    "completed_at": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "format": "date-time"
                    },
                    "created_at": {
                        "type": "string",
                        "format": "date-time"
                    }
                }
            },
            "GitOverview": {
                "type": "object",
                "required": [
                    "can_manage",
                    "repository",
                    "config",
                    "deployments",
                    "limits",
                    "github",
                    "gitlab"
                ],
                "properties": {
                    "can_manage": {
                        "type": "boolean",
                        "description": "Whether this key may link, deploy and change settings (the owner, with an unrestricted key)."
                    },
                    "repository": {
                        "oneOf": [
                            {
                                "$ref": "#/components/schemas/GitRepository"
                            },
                            {
                                "type": "null"
                            }
                        ]
                    },
                    "config": {
                        "oneOf": [
                            {
                                "$ref": "#/components/schemas/GitConfigStatus"
                            },
                            {
                                "type": "null"
                            }
                        ]
                    },
                    "deployments": {
                        "type": "array",
                        "description": "The last 15 deployments, newest first.",
                        "items": {
                            "$ref": "#/components/schemas/GitDeployment"
                        }
                    },
                    "limits": {
                        "type": "object",
                        "required": [
                            "interval",
                            "paid",
                            "paid_interval",
                            "next_deploy_at"
                        ],
                        "properties": {
                            "interval": {
                                "type": "integer",
                                "description": "Minimum seconds between two deployments of this server (900 free, 60 paid by default)."
                            },
                            "paid": {
                                "type": "boolean",
                                "description": "Whether the server is on a live paid plan."
                            },
                            "paid_interval": {
                                "type": [
                                    "integer",
                                    "null"
                                ],
                                "description": "The interval a paid plan would give, shown for free servers when plans can be bought."
                            },
                            "next_deploy_at": {
                                "type": [
                                    "string",
                                    "null"
                                ],
                                "format": "date-time"
                            }
                        }
                    },
                    "github": {
                        "type": "object",
                        "required": [
                            "enabled",
                            "installations"
                        ],
                        "properties": {
                            "enabled": {
                                "type": "boolean",
                                "description": "Whether GitHub deploys are available on this panel."
                            },
                            "installations": {
                                "type": "array",
                                "description": "Your connected GitHub App installations. Empty unless you can manage the server.",
                                "items": {
                                    "$ref": "#/components/schemas/GitInstallation"
                                }
                            }
                        }
                    },
                    "gitlab": {
                        "type": "object",
                        "required": [
                            "enabled",
                            "url",
                            "account"
                        ],
                        "properties": {
                            "enabled": {
                                "type": "boolean"
                            },
                            "url": {
                                "type": "string",
                                "description": "The GitLab instance the panel uses."
                            },
                            "account": {
                                "description": "Your connected GitLab account. Null unless you can manage the server and have connected one.",
                                "oneOf": [
                                    {
                                        "type": "object",
                                        "required": [
                                            "id",
                                            "username"
                                        ],
                                        "properties": {
                                            "id": {
                                                "type": "integer"
                                            },
                                            "username": {
                                                "type": "string"
                                            }
                                        }
                                    },
                                    {
                                        "type": "null"
                                    }
                                ]
                            }
                        }
                    }
                }
            },
            "GitLinkRequest": {
                "type": "object",
                "required": [
                    "source",
                    "repository",
                    "branch"
                ],
                "properties": {
                    "source": {
                        "type": "string",
                        "enum": [
                            "github",
                            "gitlab",
                            "url"
                        ]
                    },
                    "installation": {
                        "type": [
                            "integer",
                            "null"
                        ],
                        "description": "Required for `github`: the `id` of one of your connected installations (from `getGitDeploys` or `listGitRepositories`)."
                    },
                    "repository": {
                        "type": "string",
                        "maxLength": 191,
                        "description": "`owner/name` for GitHub, `group/subgroup/name` for GitLab, or for `url` an https clone URL with no credentials or query string, such as `https://github.com/you/my-discord-bot.git`."
                    },
                    "branch": {
                        "type": "string",
                        "maxLength": 191,
                        "description": "The branch to deploy. No leading `-`, no `..`, `//` or trailing `/`, no spaces."
                    },
                    "directory": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "maxLength": 191,
                        "description": "Folder on the server to deploy into, relative to its root. Cannot contain `..`. Defaults to the root."
                    },
                    "auto_deploy": {
                        "type": "boolean",
                        "default": false,
                        "description": "Deploy on every push to the branch. Ignored for `url`."
                    },
                    "restart_on_deploy": {
                        "type": "boolean",
                        "default": false
                    },
                    "start_if_offline": {
                        "type": "boolean",
                        "default": false
                    },
                    "apply_config": {
                        "type": "boolean",
                        "default": true
                    },
                    "sync_startup": {
                        "type": "boolean",
                        "default": true
                    },
                    "write_config": {
                        "type": "boolean",
                        "default": true,
                        "description": "When linking or retargeting, add or update `sillydev.conf` in the repository where the panel can write to it."
                    }
                }
            },
            "GitNotices": {
                "type": "object",
                "required": [
                    "notices"
                ],
                "properties": {
                    "notices": {
                        "type": "array",
                        "description": "Plain-English notes on what was done, for showing to a person.",
                        "items": {
                            "type": "string"
                        }
                    }
                }
            },
            "GitLinkResult": {
                "allOf": [
                    {
                        "$ref": "#/components/schemas/GitRepository"
                    },
                    {
                        "$ref": "#/components/schemas/GitNotices"
                    }
                ]
            },
            "GitRepositoryChoice": {
                "type": "object",
                "required": [
                    "id",
                    "full_name",
                    "private",
                    "default_branch",
                    "installation",
                    "account"
                ],
                "properties": {
                    "id": {
                        "type": "integer",
                        "description": "GitHub's or GitLab's own ID for the repository."
                    },
                    "full_name": {
                        "type": "string",
                        "description": "Send this as `repository` when linking."
                    },
                    "private": {
                        "type": "boolean"
                    },
                    "default_branch": {
                        "type": "string"
                    },
                    "installation": {
                        "type": [
                            "integer",
                            "null"
                        ],
                        "description": "For GitHub, the installation to send as `installation` when linking. Null for GitLab."
                    },
                    "account": {
                        "type": "string"
                    }
                }
            },
            "GitRepositoryChoiceList": {
                "type": "object",
                "required": [
                    "data",
                    "errors"
                ],
                "properties": {
                    "data": {
                        "type": "array",
                        "items": {
                            "$ref": "#/components/schemas/GitRepositoryChoice"
                        }
                    },
                    "errors": {
                        "type": "array",
                        "description": "Accounts whose repositories could not be loaded.",
                        "items": {
                            "type": "string"
                        }
                    }
                }
            },
            "GitConfigFile": {
                "type": "object",
                "required": [
                    "filename",
                    "contents"
                ],
                "properties": {
                    "filename": {
                        "type": "string",
                        "const": "sillydev.conf"
                    },
                    "contents": {
                        "type": "string"
                    }
                }
            },
            "GitConfigEditorState": {
                "type": "object",
                "required": [
                    "filename",
                    "can_write",
                    "exists",
                    "sha",
                    "raw",
                    "apply",
                    "sync",
                    "variables",
                    "image",
                    "unsupported",
                    "problems"
                ],
                "properties": {
                    "filename": {
                        "type": "string",
                        "const": "sillydev.conf"
                    },
                    "can_write": {
                        "type": "boolean",
                        "description": "Whether saving will commit to the repository. False for repositories linked by URL."
                    },
                    "exists": {
                        "type": "boolean",
                        "description": "Whether the repository has the file."
                    },
                    "sha": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "description": "The version of the file loaded; send it back when saving. Null if there is none or the panel cannot read the repository."
                    },
                    "raw": {
                        "type": "string",
                        "description": "The file's text, or a freshly generated one if there is none."
                    },
                    "apply": {
                        "type": "boolean"
                    },
                    "sync": {
                        "type": "boolean"
                    },
                    "variables": {
                        "type": "array",
                        "items": {
                            "$ref": "#/components/schemas/GitConfigEditorVariable"
                        }
                    },
                    "image": {
                        "description": "The docker image setting, or null when the server has only one image.",
                        "oneOf": [
                            {
                                "$ref": "#/components/schemas/GitConfigEditorImage"
                            },
                            {
                                "type": "null"
                            }
                        ]
                    },
                    "unsupported": {
                        "type": "array",
                        "items": {
                            "type": "string"
                        }
                    },
                    "problems": {
                        "type": "array",
                        "description": "Lines of the file that could not be read.",
                        "items": {
                            "type": "string"
                        }
                    }
                }
            },
            "GitConfigEditorVariable": {
                "type": "object",
                "required": [
                    "key",
                    "name",
                    "description",
                    "rules",
                    "secret",
                    "state",
                    "file_value",
                    "server_value",
                    "differs",
                    "error"
                ],
                "properties": {
                    "key": {
                        "type": "string",
                        "description": "The environment variable name, used as the key when saving."
                    },
                    "name": {
                        "type": "string"
                    },
                    "description": {
                        "type": [
                            "string",
                            "null"
                        ]
                    },
                    "rules": {
                        "type": "string",
                        "description": "Laravel validation rules the value must pass, joined with `|`."
                    },
                    "secret": {
                        "type": "boolean",
                        "description": "Looks like a secret; the panel will not add it to the file."
                    },
                    "state": {
                        "type": "string",
                        "enum": [
                            "set",
                            "left",
                            "absent"
                        ],
                        "description": "`left` means the file mentions it commented out, leaving it to the panel."
                    },
                    "file_value": {
                        "type": [
                            "string",
                            "null"
                        ]
                    },
                    "server_value": {
                        "type": "string"
                    },
                    "differs": {
                        "type": "boolean"
                    },
                    "error": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "description": "Why the file's value is not allowed, if it is not."
                    }
                }
            },
            "GitConfigEditorImage": {
                "type": "object",
                "required": [
                    "options",
                    "state",
                    "file_value",
                    "server_value",
                    "differs",
                    "error"
                ],
                "properties": {
                    "options": {
                        "type": "array",
                        "items": {
                            "type": "object",
                            "required": [
                                "name",
                                "image"
                            ],
                            "properties": {
                                "name": {
                                    "type": "string"
                                },
                                "image": {
                                    "type": "string"
                                }
                            }
                        }
                    },
                    "state": {
                        "type": "string",
                        "enum": [
                            "set",
                            "left",
                            "absent"
                        ]
                    },
                    "file_value": {
                        "type": [
                            "string",
                            "null"
                        ]
                    },
                    "server_value": {
                        "type": "string"
                    },
                    "differs": {
                        "type": "boolean"
                    },
                    "error": {
                        "type": [
                            "string",
                            "null"
                        ]
                    }
                }
            },
            "GitConfigEditorSaveRequest": {
                "type": "object",
                "required": [
                    "mode"
                ],
                "properties": {
                    "mode": {
                        "type": "string",
                        "enum": [
                            "form",
                            "raw"
                        ]
                    },
                    "sha": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "maxLength": 64,
                        "description": "The `sha` from `getGitConfigEditor`, or null if the file did not exist."
                    },
                    "raw": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "maxLength": 16384,
                        "description": "The whole file. Required when `mode` is `raw`."
                    },
                    "variables": {
                        "type": "object",
                        "maxProperties": 200,
                        "description": "For `mode: form`, the variables to change, keyed by environment variable name. Variables not sent are left as they are in the file.",
                        "additionalProperties": {
                            "type": "object",
                            "required": [
                                "mode"
                            ],
                            "properties": {
                                "mode": {
                                    "type": "string",
                                    "enum": [
                                        "set",
                                        "left"
                                    ],
                                    "description": "`set` writes `value`; `left` comments the setting out, leaving it to the panel."
                                },
                                "value": {
                                    "type": [
                                        "string",
                                        "null"
                                    ],
                                    "maxLength": 4096
                                }
                            }
                        }
                    },
                    "image": {
                        "description": "For `mode: form`, the docker image to set (by its name from `image.options`), or `left`.",
                        "oneOf": [
                            {
                                "type": "object",
                                "required": [
                                    "mode"
                                ],
                                "properties": {
                                    "mode": {
                                        "type": "string",
                                        "enum": [
                                            "set",
                                            "left"
                                        ]
                                    },
                                    "value": {
                                        "type": [
                                            "string",
                                            "null"
                                        ],
                                        "maxLength": 191
                                    }
                                }
                            },
                            {
                                "type": "null"
                            }
                        ]
                    }
                }
            },
            "GitConfigEditorSaveResult": {
                "type": "object",
                "required": [
                    "contents",
                    "committed",
                    "applied",
                    "warnings"
                ],
                "properties": {
                    "contents": {
                        "type": "string",
                        "description": "The file as saved, or to copy in yourself when `committed` is false."
                    },
                    "committed": {
                        "type": "boolean"
                    },
                    "applied": {
                        "type": [
                            "array",
                            "null"
                        ],
                        "items": {
                            "type": "string"
                        },
                        "description": "Settings applied to the server, or null if nothing was applied."
                    },
                    "warnings": {
                        "type": "array",
                        "items": {
                            "type": "string"
                        }
                    }
                }
            },
            "AccountAttributes": {
                "type": "object",
                "required": [
                    "id",
                    "admin",
                    "username",
                    "email",
                    "first_name",
                    "last_name",
                    "language"
                ],
                "properties": {
                    "id": {
                        "type": "integer"
                    },
                    "admin": {
                        "type": "boolean",
                        "description": "Whether the account is a panel administrator."
                    },
                    "username": {
                        "type": "string"
                    },
                    "email": {
                        "type": "string",
                        "format": "email"
                    },
                    "first_name": {
                        "type": "string"
                    },
                    "last_name": {
                        "type": "string"
                    },
                    "language": {
                        "type": "string",
                        "description": "Interface language code, e.g. `en`."
                    }
                }
            },
            "AccountItem": {
                "type": "object",
                "required": [
                    "object",
                    "attributes"
                ],
                "properties": {
                    "object": {
                        "type": "string",
                        "const": "user"
                    },
                    "attributes": {
                        "$ref": "#/components/schemas/AccountAttributes"
                    }
                }
            },
            "ServerBadgeItem": {
                "type": "object",
                "required": [
                    "object",
                    "attributes"
                ],
                "properties": {
                    "object": {
                        "type": "string",
                        "const": "server_badge"
                    },
                    "attributes": {
                        "$ref": "#/components/schemas/ServerBadgeAttributes"
                    }
                }
            },
            "ServerBadgeAttributes": {
                "type": "object",
                "required": [
                    "enabled",
                    "show_name",
                    "url",
                    "link",
                    "markdown"
                ],
                "properties": {
                    "enabled": {
                        "type": "boolean",
                        "description": "Whether the badge is on."
                    },
                    "show_name": {
                        "type": "boolean",
                        "description": "Whether the badge shows the server's name rather than \"bot\"."
                    },
                    "url": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "description": "The badge image's address, or null while it is off. Anyone with it can see the server's state, so share it only where you mean to."
                    },
                    "link": {
                        "type": "string",
                        "description": "Where the badge should link to."
                    },
                    "markdown": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "description": "A Markdown snippet for a README, or null while the badge is off."
                    }
                }
            },
            "AccountActivityList": {
                "type": "object",
                "required": [
                    "object",
                    "data",
                    "meta"
                ],
                "properties": {
                    "object": {
                        "type": "string",
                        "const": "list"
                    },
                    "data": {
                        "type": "array",
                        "items": {
                            "$ref": "#/components/schemas/ServerActivity"
                        }
                    },
                    "meta": {
                        "$ref": "#/components/schemas/Pagination"
                    }
                }
            },
            "ServerCreationRuntime": {
                "type": "object",
                "required": [
                    "key",
                    "label"
                ],
                "properties": {
                    "key": {
                        "type": "string",
                        "description": "The value to send as `runtime`. Only runtimes switched on are listed.",
                        "enum": [
                            "nodejs",
                            "python",
                            "bun"
                        ]
                    },
                    "label": {
                        "type": "string",
                        "example": "Node.js"
                    }
                }
            },
            "ServerCreationOptions": {
                "type": "object",
                "required": [
                    "object",
                    "attributes"
                ],
                "properties": {
                    "object": {
                        "type": "string",
                        "const": "server_creation"
                    },
                    "attributes": {
                        "type": "object",
                        "required": [
                            "limit",
                            "servers_owned",
                            "can_create",
                            "runtimes"
                        ],
                        "properties": {
                            "limit": {
                                "type": "integer",
                                "description": "How many free servers an account may own."
                            },
                            "servers_owned": {
                                "type": "integer",
                                "description": "Owned servers without a live paid plan, the number checked against `limit`."
                            },
                            "can_create": {
                                "type": "boolean",
                                "description": "Whether `createServer` would currently be allowed (always true for administrators)."
                            },
                            "runtimes": {
                                "type": "array",
                                "items": {
                                    "$ref": "#/components/schemas/ServerCreationRuntime"
                                }
                            }
                        }
                    }
                }
            },
            "ServerCreationRequest": {
                "type": "object",
                "required": [
                    "name",
                    "runtime"
                ],
                "properties": {
                    "name": {
                        "type": "string",
                        "minLength": 1,
                        "maxLength": 191
                    },
                    "description": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "maxLength": 255
                    },
                    "runtime": {
                        "type": "string",
                        "description": "A `key` from `getServerCreationOptions` runtimes.",
                        "enum": [
                            "nodejs",
                            "python",
                            "bun"
                        ]
                    }
                }
            },
            "DatabaseVersion": {
                "type": "object",
                "required": [
                    "id",
                    "engine",
                    "name",
                    "server_version",
                    "label",
                    "status",
                    "legacy_ends_at",
                    "host",
                    "port"
                ],
                "properties": {
                    "id": {
                        "type": "integer",
                        "description": "Send as `version_id` to create or move a database."
                    },
                    "engine": {
                        "type": "string",
                        "enum": [
                            "mariadb",
                            "postgres"
                        ]
                    },
                    "name": {
                        "type": "string",
                        "example": "MariaDB 11.4"
                    },
                    "server_version": {
                        "type": "string",
                        "example": "11.4.3"
                    },
                    "label": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "enum": [
                            "recommended",
                            "older",
                            null
                        ]
                    },
                    "status": {
                        "type": "string",
                        "enum": [
                            "active",
                            "legacy",
                            "retired"
                        ],
                        "description": "Only `active` versions take new databases. A `legacy` one is listed only when the account has a database on it; at `legacy_ends_at` its databases are moved to the engine's recommended version."
                    },
                    "legacy_ends_at": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "format": "date-time"
                    },
                    "host": {
                        "type": "string"
                    },
                    "port": {
                        "type": "integer"
                    }
                }
            },
            "DatabaseAttributes": {
                "type": "object",
                "required": [
                    "id",
                    "label",
                    "engine",
                    "name",
                    "username",
                    "password",
                    "host",
                    "port",
                    "version",
                    "status",
                    "moving_to",
                    "last_move_error",
                    "previous_version",
                    "previous_expires_at",
                    "moved_at",
                    "can_undo_move",
                    "size_bytes",
                    "quota_bytes",
                    "size_checked_at",
                    "created_at"
                ],
                "properties": {
                    "id": {
                        "type": "integer"
                    },
                    "label": {
                        "type": "string",
                        "description": "The name the owner gave it."
                    },
                    "engine": {
                        "type": "string",
                        "enum": [
                            "mariadb",
                            "postgres"
                        ]
                    },
                    "name": {
                        "type": "string",
                        "description": "The database name to connect to."
                    },
                    "username": {
                        "type": "string"
                    },
                    "password": {
                        "type": "string",
                        "description": "The current password, in plain text."
                    },
                    "host": {
                        "type": "string"
                    },
                    "port": {
                        "type": "integer"
                    },
                    "version": {
                        "$ref": "#/components/schemas/DatabaseVersion"
                    },
                    "status": {
                        "type": "string",
                        "enum": [
                            "ready",
                            "moving"
                        ]
                    },
                    "moving_to": {
                        "oneOf": [
                            {
                                "$ref": "#/components/schemas/DatabaseVersion"
                            },
                            {
                                "type": "null"
                            }
                        ]
                    },
                    "last_move_error": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "description": "Why the last move failed, if it did. The database stayed on its old version."
                    },
                    "previous_version": {
                        "description": "The version a copy is kept on after a move, until `previous_expires_at`.",
                        "oneOf": [
                            {
                                "$ref": "#/components/schemas/DatabaseVersion"
                            },
                            {
                                "type": "null"
                            }
                        ]
                    },
                    "previous_expires_at": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "format": "date-time"
                    },
                    "moved_at": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "format": "date-time"
                    },
                    "can_undo_move": {
                        "type": "boolean"
                    },
                    "size_bytes": {
                        "type": [
                            "integer",
                            "null"
                        ],
                        "description": "Disk used, as of `size_checked_at`."
                    },
                    "quota_bytes": {
                        "type": "integer",
                        "description": "Hard disk quota. Writes beyond it fail."
                    },
                    "size_checked_at": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "format": "date-time"
                    },
                    "created_at": {
                        "type": "string",
                        "format": "date-time"
                    }
                }
            },
            "DatabaseItem": {
                "type": "object",
                "required": [
                    "object",
                    "attributes"
                ],
                "properties": {
                    "object": {
                        "type": "string",
                        "const": "user_database"
                    },
                    "attributes": {
                        "$ref": "#/components/schemas/DatabaseAttributes"
                    }
                }
            },
            "DatabaseOverview": {
                "type": "object",
                "required": [
                    "object",
                    "attributes"
                ],
                "properties": {
                    "object": {
                        "type": "string",
                        "const": "user_database_list"
                    },
                    "attributes": {
                        "type": "object",
                        "required": [
                            "limit",
                            "owned",
                            "can_create",
                            "quota_bytes",
                            "versions",
                            "databases"
                        ],
                        "properties": {
                            "limit": {
                                "type": "integer",
                                "description": "How many databases the account may have."
                            },
                            "owned": {
                                "type": "integer"
                            },
                            "can_create": {
                                "type": "boolean"
                            },
                            "quota_bytes": {
                                "type": "integer",
                                "description": "Each database's disk quota in bytes."
                            },
                            "versions": {
                                "type": "array",
                                "description": "Active versions, plus any legacy version the account still has a database on.",
                                "items": {
                                    "$ref": "#/components/schemas/DatabaseVersion"
                                }
                            },
                            "databases": {
                                "type": "array",
                                "items": {
                                    "$ref": "#/components/schemas/DatabaseItem"
                                }
                            }
                        }
                    }
                }
            },
            "DatabaseCreateRequest": {
                "type": "object",
                "required": [
                    "label",
                    "version_id"
                ],
                "properties": {
                    "label": {
                        "type": "string",
                        "minLength": 1,
                        "maxLength": 48
                    },
                    "version_id": {
                        "type": "integer",
                        "description": "The `id` of an `active` version."
                    }
                }
            },
            "DatabaseMoveRequest": {
                "type": "object",
                "required": [
                    "version_id"
                ],
                "properties": {
                    "version_id": {
                        "type": "integer",
                        "description": "The `id` of another `active` version of the same engine."
                    }
                }
            },
            "BillingPaymentIssue": {
                "type": [
                    "object",
                    "null"
                ],
                "description": "Set when the latest payment is outstanding and the customer can act on it.",
                "required": [
                    "type",
                    "url",
                    "grace_ends_at"
                ],
                "properties": {
                    "type": {
                        "type": "string",
                        "enum": [
                            "requires_action",
                            "failed"
                        ],
                        "description": "`requires_action`: the bank wants it confirmed (3D Secure). `failed`: the card was declined."
                    },
                    "url": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "format": "uri",
                        "description": "Stripe page where a person can complete the payment."
                    },
                    "grace_ends_at": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "format": "date-time",
                        "description": "When the server is suspended if the payment is still outstanding."
                    }
                }
            },
            "BillingImmediateDowngrade": {
                "type": "object",
                "description": "Whether `cancelSubscriptionImmediately` would be allowed now, and what it would refund.",
                "required": [
                    "available",
                    "reason",
                    "refund_pence",
                    "fee_pence",
                    "available_at"
                ],
                "properties": {
                    "available": {
                        "type": "boolean"
                    },
                    "reason": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "enum": [
                            "no_payment",
                            "blackout",
                            "quota",
                            "too_small",
                            null
                        ],
                        "description": "Why it is unavailable. `no_payment` still lets the plan be ended, just without a refund; `blackout`: renews too soon; `quota`: one used in the last 30 days; `too_small`: the refund would be under the minimum."
                    },
                    "refund_pence": {
                        "type": "integer",
                        "description": "Refund after the fee."
                    },
                    "fee_pence": {
                        "type": "integer"
                    },
                    "available_at": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "format": "date-time",
                        "description": "For `quota`, when the next immediate downgrade is allowed."
                    }
                }
            },
            "BillingSubscriptionState": {
                "type": "object",
                "required": [
                    "status",
                    "cancel_at_period_end",
                    "current_period_end",
                    "payment_issue",
                    "immediate_downgrade"
                ],
                "properties": {
                    "status": {
                        "type": "string",
                        "description": "Stripe's subscription status (e.g. `active`, `trialing`, `past_due`, `incomplete`, `canceled`), or `ended` once the plan is over and the server has been downgraded or suspended."
                    },
                    "cancel_at_period_end": {
                        "type": "boolean"
                    },
                    "current_period_end": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "format": "date-time"
                    },
                    "payment_issue": {
                        "$ref": "#/components/schemas/BillingPaymentIssue"
                    },
                    "immediate_downgrade": {
                        "$ref": "#/components/schemas/BillingImmediateDowngrade"
                    }
                }
            },
            "BillingSubscriptionItem": {
                "type": "object",
                "required": [
                    "object",
                    "attributes"
                ],
                "properties": {
                    "object": {
                        "type": "string",
                        "const": "server_subscription"
                    },
                    "attributes": {
                        "$ref": "#/components/schemas/BillingSubscriptionState"
                    }
                }
            },
            "BillingSubscriptionSummary": {
                "allOf": [
                    {
                        "type": "object",
                        "required": [
                            "server_uuid",
                            "server_name",
                            "plan"
                        ],
                        "properties": {
                            "server_uuid": {
                                "type": "string",
                                "format": "uuid"
                            },
                            "server_name": {
                                "type": "string"
                            },
                            "plan": {
                                "type": "object",
                                "required": [
                                    "key",
                                    "name"
                                ],
                                "properties": {
                                    "key": {
                                        "type": "string"
                                    },
                                    "name": {
                                        "type": "string"
                                    }
                                }
                            }
                        }
                    },
                    {
                        "$ref": "#/components/schemas/BillingSubscriptionState"
                    }
                ]
            },
            "BillingOverview": {
                "type": "object",
                "required": [
                    "object",
                    "attributes"
                ],
                "properties": {
                    "object": {
                        "type": "string",
                        "const": "billing"
                    },
                    "attributes": {
                        "type": "object",
                        "required": [
                            "is_customer",
                            "sandbox",
                            "restricted",
                            "plan",
                            "subscriptions",
                            "restorable",
                            "saved_card"
                        ],
                        "properties": {
                            "is_customer": {
                                "type": "boolean",
                                "description": "Whether the account has ever started a checkout. Plan management routes 404 until it has."
                            },
                            "sandbox": {
                                "type": "boolean",
                                "description": "Whether billing is on Stripe test keys (only administrators can reach billing then)."
                            },
                            "restricted": {
                                "type": "boolean",
                                "description": "Whether billing is limited to administrators."
                            },
                            "plan": {
                                "type": "object",
                                "required": [
                                    "key",
                                    "name",
                                    "price_pence",
                                    "currency",
                                    "limits"
                                ],
                                "properties": {
                                    "key": {
                                        "type": "string",
                                        "example": "standard"
                                    },
                                    "name": {
                                        "type": "string"
                                    },
                                    "price_pence": {
                                        "type": "integer",
                                        "description": "Monthly price in the smallest currency unit."
                                    },
                                    "currency": {
                                        "type": "string",
                                        "example": "gbp"
                                    },
                                    "limits": {
                                        "type": "object",
                                        "description": "Size of a paid server; memory and disk in MiB, CPU in percent of one core.",
                                        "required": [
                                            "memory",
                                            "disk",
                                            "cpu"
                                        ],
                                        "properties": {
                                            "memory": {
                                                "type": "integer"
                                            },
                                            "disk": {
                                                "type": "integer"
                                            },
                                            "cpu": {
                                                "type": "integer"
                                            }
                                        }
                                    }
                                }
                            },
                            "subscriptions": {
                                "type": "array",
                                "description": "The account's servers with a live paid plan.",
                                "items": {
                                    "$ref": "#/components/schemas/BillingSubscriptionSummary"
                                }
                            },
                            "restorable": {
                                "type": "array",
                                "description": "Paid servers suspended because their plan lapsed; ordering with their `server_uuid` restores them.",
                                "items": {
                                    "type": "object",
                                    "required": [
                                        "server_uuid",
                                        "server_name",
                                        "deletion_due_at"
                                    ],
                                    "properties": {
                                        "server_uuid": {
                                            "type": "string",
                                            "format": "uuid"
                                        },
                                        "server_name": {
                                            "type": "string"
                                        },
                                        "deletion_due_at": {
                                            "type": [
                                                "string",
                                                "null"
                                            ],
                                            "format": "date-time"
                                        }
                                    }
                                }
                            },
                            "saved_card": {
                                "type": [
                                    "object",
                                    "null"
                                ],
                                "required": [
                                    "brand",
                                    "last4",
                                    "exp_month",
                                    "exp_year"
                                ],
                                "properties": {
                                    "brand": {
                                        "type": "string"
                                    },
                                    "last4": {
                                        "type": "string"
                                    },
                                    "exp_month": {
                                        "type": "integer"
                                    },
                                    "exp_year": {
                                        "type": "integer"
                                    }
                                }
                            }
                        }
                    }
                }
            },
            "BillingCheckoutRequest": {
                "type": "object",
                "description": "Send `server_uuid` to upgrade an existing server, or `name` and `runtime` for a new one.",
                "properties": {
                    "server_uuid": {
                        "type": "string",
                        "format": "uuid",
                        "description": "Full UUID of a server the account owns, to upgrade it (or restore one listed in `restorable`)."
                    },
                    "name": {
                        "type": "string",
                        "minLength": 1,
                        "maxLength": 191,
                        "description": "Required without `server_uuid`."
                    },
                    "description": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "maxLength": 1000
                    },
                    "runtime": {
                        "type": "string",
                        "description": "Required without `server_uuid`; a runtime key from `getServerCreationOptions`.",
                        "enum": [
                            "nodejs",
                            "python",
                            "bun"
                        ]
                    },
                    "use_saved_card": {
                        "type": "boolean",
                        "default": false,
                        "description": "Use the card on file instead of returning a Stripe Checkout page. 400 if there is none."
                    }
                }
            },
            "BillingCheckout": {
                "type": "object",
                "required": [
                    "object",
                    "attributes"
                ],
                "properties": {
                    "object": {
                        "type": "string",
                        "const": "billing_checkout"
                    },
                    "attributes": {
                        "type": "object",
                        "required": [
                            "url",
                            "order_uuid"
                        ],
                        "properties": {
                            "url": {
                                "type": "string",
                                "format": "uri",
                                "description": "A Stripe Checkout page a person must open to pay, or the panel's billing page when the order needs nothing more (saved card, or a replayed Idempotency-Key)."
                            },
                            "order_uuid": {
                                "type": "string",
                                "format": "uuid"
                            }
                        }
                    }
                }
            },
            "BillingOrderItem": {
                "type": "object",
                "required": [
                    "object",
                    "attributes"
                ],
                "properties": {
                    "object": {
                        "type": "string",
                        "const": "server_order"
                    },
                    "attributes": {
                        "type": "object",
                        "required": [
                            "uuid",
                            "status"
                        ],
                        "properties": {
                            "uuid": {
                                "type": "string",
                                "format": "uuid"
                            },
                            "status": {
                                "type": "string",
                                "enum": [
                                    "awaiting_payment",
                                    "provisioning",
                                    "pending_deployment",
                                    "fulfilled",
                                    "cancelled",
                                    "failed"
                                ]
                            }
                        }
                    }
                }
            }
        }
    }
}