{
  "openapi": "3.0.3",
  "info": {
    "title": "Void API",
    "version": "1.0.0",
    "description": "Void REST API v1 — domains (availability and prices, registration, renewal, nameservers), Cloudflare zone, DNS records, settings and redirects, VPS servers (order, power, reinstall, renewal, term, upgrade, firewall) and web hosting (order, credentials, renewal, term, plan change). Authenticate with a bearer API key created in the Telegram bot (profile → API). Human docs: https://api.void.cd/docs/"
  },
  "servers": [
    {
      "url": "https://api.void.cd/v1"
    }
  ],
  "components": {
    "securitySchemes": {
      "apiKey": {
        "type": "http",
        "scheme": "bearer",
        "description": "Authorization: Bearer void_…"
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean",
            "enum": [
              false
            ]
          },
          "error": {
            "type": "object",
            "properties": {
              "code": {
                "type": "string"
              },
              "message": {
                "type": "string"
              },
              "details": {}
            }
          }
        }
      },
      "Domain": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "domainName": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": [
              "PENDING",
              "ACTIVE",
              "EXPIRED",
              "FAILED"
            ]
          },
          "nameservers": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "price": {
            "type": "string"
          },
          "renewalPrice": {
            "type": "string"
          },
          "renewalYears": {
            "type": "integer"
          },
          "autoRenew": {
            "type": "boolean"
          },
          "expiresAt": {
            "type": "string",
            "format": "date-time"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "blockFlags": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        }
      },
      "Availability": {
        "type": "object",
        "properties": {
          "domain": {
            "type": "string"
          },
          "available": {
            "type": "boolean"
          },
          "price": {
            "type": "string",
            "nullable": true
          },
          "reason": {
            "type": "string",
            "enum": [
              "UNSUPPORTED_TLD",
              "UNCERTAIN"
            ]
          }
        }
      },
      "DnsRecord": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "type": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "content": {
            "type": "string"
          },
          "proxied": {
            "type": "boolean"
          },
          "priority": {
            "type": "integer",
            "nullable": true
          }
        }
      },
      "DnsInput": {
        "type": "object",
        "required": [
          "type",
          "name",
          "content"
        ],
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "A",
              "AAAA",
              "CNAME",
              "TXT",
              "MX"
            ]
          },
          "name": {
            "type": "string"
          },
          "content": {
            "type": "string"
          },
          "proxied": {
            "type": "boolean"
          },
          "priority": {
            "type": "integer"
          }
        }
      },
      "Settings": {
        "type": "object",
        "properties": {
          "ssl": {
            "type": "string",
            "enum": [
              "off",
              "flexible",
              "full",
              "strict"
            ]
          },
          "developmentMode": {
            "type": "boolean"
          },
          "underAttack": {
            "type": "boolean"
          },
          "alwaysOnline": {
            "type": "boolean"
          },
          "botFightMode": {
            "type": "boolean"
          },
          "regionBlock": {
            "type": "boolean"
          },
          "bypassCache": {
            "type": "boolean"
          }
        }
      },
      "Redirect": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "match": {
            "type": "string"
          },
          "target": {
            "type": "string"
          },
          "permanent": {
            "type": "boolean"
          }
        }
      },
      "Zone": {
        "type": "object",
        "properties": {
          "connected": {
            "type": "boolean"
          },
          "domainName": {
            "type": "string"
          },
          "zoneId": {
            "type": "string",
            "nullable": true
          },
          "nameservers": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "zoneStatus": {
            "type": "string",
            "enum": [
              "none",
              "pending",
              "active",
              "moved"
            ]
          },
          "nsApplied": {
            "type": "boolean"
          }
        }
      },
      "RenewQuote": {
        "type": "object",
        "properties": {
          "domainId": {
            "type": "string"
          },
          "domainName": {
            "type": "string"
          },
          "price": {
            "type": "string"
          },
          "years": {
            "type": "integer"
          },
          "expiresAfter": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "Webhook": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "url": {
            "type": "string"
          },
          "events": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "active": {
            "type": "boolean"
          },
          "failures": {
            "type": "integer"
          },
          "lastStatus": {
            "type": "integer",
            "nullable": true
          },
          "lastDeliveredAt": {
            "type": "string",
            "nullable": true
          },
          "createdAt": {
            "type": "string"
          },
          "secret": {
            "type": "string",
            "description": "only in the create / rotate-secret response"
          }
        }
      },
      "Delivery": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "event": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": [
              "PENDING",
              "SENT",
              "FAILED"
            ]
          },
          "attempts": {
            "type": "integer"
          },
          "lastStatus": {
            "type": "integer",
            "nullable": true
          },
          "lastError": {
            "type": "string",
            "nullable": true
          },
          "createdAt": {
            "type": "string"
          },
          "sentAt": {
            "type": "string",
            "nullable": true
          },
          "nextAt": {
            "type": "string",
            "nullable": true
          }
        }
      },
      "Spec": {
        "type": "object",
        "required": [
          "vcpu",
          "ramGb",
          "diskGb"
        ],
        "properties": {
          "vcpu": {
            "type": "integer"
          },
          "ramGb": {
            "type": "integer"
          },
          "diskGb": {
            "type": "integer"
          }
        },
        "description": "Integers inside the catalogue's custom limits and steps (disk in 20 GB steps)."
      },
      "Server": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "label": {
            "type": "string",
            "example": "vm-4f2a9c"
          },
          "alias": {
            "type": "string",
            "nullable": true
          },
          "hostname": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": [
              "PENDING",
              "PROVISIONING",
              "ACTIVE",
              "SUSPENDED",
              "FAILED",
              "TERMINATED"
            ]
          },
          "power": {
            "type": "string",
            "enum": [
              "RUNNING",
              "STOPPED",
              "UNKNOWN"
            ],
            "description": "refreshed periodically; may lag behind an action"
          },
          "ip": {
            "type": "string",
            "nullable": true
          },
          "os": {
            "type": "string"
          },
          "osCode": {
            "type": "string"
          },
          "specs": {
            "type": "object",
            "properties": {
              "vcpu": {
                "type": "integer"
              },
              "ramMb": {
                "type": "integer"
              },
              "diskGb": {
                "type": "integer"
              }
            }
          },
          "region": {
            "type": "string",
            "nullable": true
          },
          "period": {
            "type": "string",
            "enum": [
              "WEEK",
              "MONTH",
              "QUARTER",
              "HALF_YEAR",
              "YEAR"
            ],
            "description": "renewal term (WEEK only on legacy rows)"
          },
          "periodPrice": {
            "type": "string",
            "description": "what each renewal costs"
          },
          "autoRenew": {
            "type": "boolean"
          },
          "expiresAt": {
            "type": "string",
            "format": "date-time"
          },
          "graceEndsAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "set while SUSPENDED; the server is deleted after it"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "proxy": {
            "type": "object",
            "properties": {
              "enabled": {
                "type": "boolean"
              },
              "address": {
                "type": "string",
                "nullable": true
              }
            },
            "description": "front-proxy add-on"
          },
          "sshKeys": {
            "type": "integer",
            "description": "number of keys installed at first boot"
          },
          "passwordLogin": {
            "type": "boolean"
          },
          "app": {
            "type": "object",
            "properties": {
              "code": {
                "type": "string"
              },
              "name": {
                "type": "string"
              },
              "state": {
                "type": "string",
                "enum": [
                  "PENDING",
                  "INSTALLING",
                  "READY",
                  "FAILED"
                ]
              },
              "url": {
                "type": "string"
              },
              "note": {
                "type": "string"
              }
            },
            "description": "pre-installed app; login/password only via /credentials",
            "nullable": true
          }
        },
        "description": "No secrets: the root password and app login are only in ServerCredentials."
      },
      "ServerCredentials": {
        "type": "object",
        "properties": {
          "ip": {
            "type": "string",
            "nullable": true
          },
          "login": {
            "type": "string",
            "enum": [
              "root",
              "Administrator"
            ]
          },
          "password": {
            "type": "string",
            "nullable": true
          },
          "app": {
            "type": "object",
            "properties": {
              "code": {
                "type": "string"
              },
              "name": {
                "type": "string"
              },
              "state": {
                "type": "string",
                "enum": [
                  "PENDING",
                  "INSTALLING",
                  "READY",
                  "FAILED"
                ]
              },
              "url": {
                "type": "string"
              },
              "login": {
                "type": "string"
              },
              "password": {
                "type": "string"
              },
              "note": {
                "type": "string"
              }
            },
            "nullable": true
          }
        }
      },
      "ServerCatalogue": {
        "type": "object",
        "properties": {
          "plans": {
            "type": "array",
            "description": "the bot's fixed plans, for reference; the API orders by spec",
            "items": {
              "type": "object",
              "properties": {
                "code": {
                  "type": "string"
                },
                "nameEn": {
                  "type": "string"
                },
                "nameRu": {
                  "type": "string"
                },
                "vcpu": {
                  "type": "integer"
                },
                "ramMb": {
                  "type": "integer"
                },
                "diskGb": {
                  "type": "integer"
                },
                "trafficGb": {
                  "type": "integer",
                  "nullable": true
                },
                "bandwidthMbps": {
                  "type": "integer"
                },
                "prices": {
                  "type": "object",
                  "properties": {
                    "MONTH": {
                      "type": "string"
                    },
                    "QUARTER": {
                      "type": "string"
                    },
                    "HALF_YEAR": {
                      "type": "string"
                    },
                    "YEAR": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "os": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "code": {
                  "type": "string"
                },
                "name": {
                  "type": "string"
                }
              }
            }
          },
          "apps": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "code": {
                  "type": "string"
                },
                "name": {
                  "type": "string"
                },
                "descEn": {
                  "type": "string"
                },
                "descRu": {
                  "type": "string"
                },
                "baseOs": {
                  "type": "string"
                },
                "minRamMb": {
                  "type": "integer"
                },
                "minutes": {
                  "type": "integer"
                }
              }
            }
          },
          "regions": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "custom": {
            "type": "object",
            "properties": {
              "cpu": {
                "type": "object",
                "properties": {
                  "min": {
                    "type": "number"
                  },
                  "max": {
                    "type": "number"
                  },
                  "step": {
                    "type": "number"
                  },
                  "monthly": {
                    "type": "number"
                  }
                }
              },
              "ramGb": {
                "type": "object",
                "properties": {
                  "min": {
                    "type": "number"
                  },
                  "max": {
                    "type": "number"
                  },
                  "step": {
                    "type": "number"
                  },
                  "monthly": {
                    "type": "number"
                  }
                }
              },
              "diskGb": {
                "type": "object",
                "properties": {
                  "min": {
                    "type": "number"
                  },
                  "max": {
                    "type": "number"
                  },
                  "step": {
                    "type": "number"
                  },
                  "monthlyPer10Gb": {
                    "type": "number"
                  }
                }
              },
              "base": {
                "type": "object",
                "properties": {
                  "monthly": {
                    "type": "number"
                  }
                }
              },
              "defaults": {
                "type": "object",
                "properties": {
                  "vcpu": {
                    "type": "integer"
                  },
                  "ramGb": {
                    "type": "integer"
                  },
                  "diskGb": {
                    "type": "integer"
                  }
                }
              }
            },
            "description": "configurator limits (max reflects free node capacity) and USD-per-month rates as plain numbers"
          },
          "periods": {
            "type": "object",
            "properties": {
              "MONTH": {
                "type": "number"
              },
              "QUARTER": {
                "type": "number"
              },
              "HALF_YEAR": {
                "type": "number"
              },
              "YEAR": {
                "type": "number"
              }
            },
            "description": "price multiplier against one month"
          },
          "proxy": {
            "type": "object",
            "properties": {
              "available": {
                "type": "boolean"
              },
              "monthly": {
                "type": "number"
              },
              "free": {
                "type": "integer"
              },
              "total": {
                "type": "integer"
              }
            }
          }
        }
      },
      "UpgradeQuote": {
        "type": "object",
        "properties": {
          "serverId": {
            "type": "string",
            "format": "uuid"
          },
          "from": {
            "$ref": "#/components/schemas/Spec"
          },
          "to": {
            "$ref": "#/components/schemas/Spec"
          },
          "charge": {
            "type": "string",
            "description": "charged now: (new periodPrice − old periodPrice) × remaining / term length"
          },
          "periodPrice": {
            "type": "string",
            "description": "each renewal after the upgrade"
          },
          "period": {
            "type": "string",
            "enum": [
              "MONTH",
              "QUARTER",
              "HALF_YEAR",
              "YEAR"
            ]
          },
          "expiresAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "FirewallRule": {
        "type": "object",
        "required": [
          "proto"
        ],
        "properties": {
          "proto": {
            "type": "string",
            "enum": [
              "tcp",
              "udp",
              "icmp"
            ]
          },
          "port": {
            "type": "string",
            "description": "\"22\", \"80,443\" or \"8000:8100\"; absent for icmp"
          },
          "source": {
            "type": "string",
            "description": "IPv4 address or CIDR (/8–/32); absent = anywhere"
          }
        }
      },
      "Firewall": {
        "type": "object",
        "properties": {
          "enabled": {
            "type": "boolean",
            "description": "off = inbound open; on = inbound dropped except the rules"
          },
          "rules": {
            "type": "array",
            "maxItems": 20,
            "items": {
              "$ref": "#/components/schemas/FirewallRule"
            },
            "description": "until first changed: the defaults applied on enable (22 or 3389, 80,443, icmp)"
          },
          "proxySource": {
            "type": "string",
            "nullable": true,
            "description": "front-proxy address allowed on 80/443 automatically while the add-on is on"
          }
        }
      },
      "TermOption": {
        "type": "object",
        "properties": {
          "period": {
            "type": "string",
            "enum": [
              "MONTH",
              "QUARTER",
              "HALF_YEAR",
              "YEAR"
            ]
          },
          "price": {
            "type": "string",
            "description": "price of one term at today's rates"
          },
          "current": {
            "type": "boolean"
          }
        }
      },
      "HostingPlan": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "code": {
            "type": "string"
          },
          "nameEn": {
            "type": "string"
          },
          "nameRu": {
            "type": "string"
          },
          "sites": {
            "type": "integer"
          },
          "diskMb": {
            "type": "integer"
          },
          "bandwidthGb": {
            "type": "integer"
          },
          "databases": {
            "type": "integer"
          },
          "mailboxes": {
            "type": "integer"
          },
          "prices": {
            "type": "object",
            "properties": {
              "MONTH": {
                "type": "string"
              },
              "QUARTER": {
                "type": "string"
              },
              "HALF_YEAR": {
                "type": "string"
              },
              "YEAR": {
                "type": "string"
              }
            }
          }
        }
      },
      "HostingCatalogue": {
        "type": "object",
        "properties": {
          "available": {
            "type": "boolean",
            "description": "false = hosting sales are off (orders fail with PROVIDER_DISABLED)"
          },
          "plans": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/HostingPlan"
            }
          }
        }
      },
      "Hosting": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "label": {
            "type": "string",
            "example": "wh3f9a1c"
          },
          "status": {
            "type": "string",
            "enum": [
              "PENDING",
              "ACTIVE",
              "SUSPENDED",
              "FAILED",
              "TERMINATED"
            ]
          },
          "primaryDomain": {
            "type": "string"
          },
          "panelUrl": {
            "type": "string"
          },
          "login": {
            "type": "string"
          },
          "ip": {
            "type": "string",
            "description": "for A records and FTP"
          },
          "nameservers": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "specs": {
            "type": "object",
            "properties": {
              "sites": {
                "type": "integer"
              },
              "diskMb": {
                "type": "integer"
              },
              "bandwidthGb": {
                "type": "integer"
              }
            }
          },
          "planId": {
            "type": "string",
            "format": "uuid",
            "description": "HostingPlan.id"
          },
          "period": {
            "type": "string",
            "enum": [
              "WEEK",
              "MONTH",
              "QUARTER",
              "HALF_YEAR",
              "YEAR"
            ]
          },
          "periodPrice": {
            "type": "string"
          },
          "autoRenew": {
            "type": "boolean"
          },
          "expiresAt": {
            "type": "string",
            "format": "date-time"
          },
          "graceEndsAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          }
        },
        "description": "No secrets: the panel password is only in HostingCredentials."
      },
      "HostingCredentials": {
        "type": "object",
        "properties": {
          "panelUrl": {
            "type": "string"
          },
          "login": {
            "type": "string"
          },
          "password": {
            "type": "string",
            "nullable": true
          }
        }
      },
      "PlanQuote": {
        "type": "object",
        "properties": {
          "hostingId": {
            "type": "string",
            "format": "uuid"
          },
          "planCode": {
            "type": "string"
          },
          "charge": {
            "type": "string",
            "description": "charged now, pro rata for the rest of the paid term"
          },
          "periodPrice": {
            "type": "string",
            "description": "each renewal after the change"
          },
          "period": {
            "type": "string",
            "enum": [
              "MONTH",
              "QUARTER",
              "HALF_YEAR",
              "YEAR"
            ]
          }
        }
      }
    }
  },
  "security": [
    {
      "apiKey": []
    }
  ],
  "paths": {
    "/me": {
      "get": {
        "summary": "Account",
        "responses": {
          "200": {
            "description": "balance and account id"
          },
          "401": {
            "description": "UNAUTHORIZED — missing or invalid key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "RATE_LIMITED"
          }
        },
        "tags": [
          "Account"
        ]
      }
    },
    "/domains/tlds": {
      "get": {
        "summary": "Price list",
        "responses": {
          "200": {
            "description": "registration prices per TLD"
          },
          "401": {
            "description": "UNAUTHORIZED — missing or invalid key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "RATE_LIMITED"
          }
        },
        "tags": [
          "Availability"
        ]
      }
    },
    "/domains/check": {
      "get": {
        "summary": "Check one name",
        "parameters": [
          {
            "name": "domain",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "availability + price",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Availability"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHORIZED — missing or invalid key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "RATE_LIMITED"
          }
        },
        "tags": [
          "Availability"
        ]
      }
    },
    "/domains/search": {
      "get": {
        "summary": "Search a bare name across all TLDs",
        "parameters": [
          {
            "name": "q",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "list of Availability"
          },
          "401": {
            "description": "UNAUTHORIZED — missing or invalid key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "RATE_LIMITED"
          }
        },
        "tags": [
          "Availability"
        ]
      }
    },
    "/domains": {
      "get": {
        "summary": "List your domains",
        "parameters": [
          {
            "name": "offset",
            "in": "query",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "maximum": 100
            }
          }
        ],
        "responses": {
          "200": {
            "description": "items, total"
          },
          "401": {
            "description": "UNAUTHORIZED — missing or invalid key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "RATE_LIMITED"
          }
        },
        "tags": [
          "Domains"
        ]
      },
      "post": {
        "summary": "Register a domain (charges the balance)",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "domain"
                ],
                "properties": {
                  "domain": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Domain"
          },
          "402": {
            "description": "INSUFFICIENT_FUNDS"
          },
          "409": {
            "description": "DOMAIN_UNAVAILABLE"
          },
          "401": {
            "description": "UNAUTHORIZED — missing or invalid key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "RATE_LIMITED"
          }
        },
        "tags": [
          "Domains"
        ]
      }
    },
    "/domains/{id}": {
      "get": {
        "summary": "One domain",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Domain"
          },
          "401": {
            "description": "UNAUTHORIZED — missing or invalid key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "RATE_LIMITED"
          }
        },
        "tags": [
          "Domains"
        ]
      },
      "patch": {
        "summary": "Change nameservers and/or auto-renew",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "nameservers": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "minItems": 2,
                    "maxItems": 4
                  },
                  "autoRenew": {
                    "type": "boolean"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Domain"
          },
          "401": {
            "description": "UNAUTHORIZED — missing or invalid key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "RATE_LIMITED"
          }
        },
        "tags": [
          "Domains"
        ]
      }
    },
    "/domains/{id}/renew-quote": {
      "get": {
        "summary": "Renewal price and new expiry",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "price, years, expiresAfter"
          },
          "401": {
            "description": "UNAUTHORIZED — missing or invalid key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "RATE_LIMITED"
          }
        },
        "tags": [
          "Renewal"
        ]
      }
    },
    "/domains/{id}/renew": {
      "post": {
        "summary": "Renew (charges the balance)",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Domain"
          },
          "402": {
            "description": "INSUFFICIENT_FUNDS"
          },
          "401": {
            "description": "UNAUTHORIZED — missing or invalid key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "RATE_LIMITED"
          }
        },
        "tags": [
          "Renewal"
        ]
      }
    },
    "/servers/catalogue": {
      "get": {
        "tags": [
          "Servers"
        ],
        "summary": "What can be ordered: images, apps, regions, configurator limits, proxy",
        "responses": {
          "200": {
            "description": "ServerCatalogue",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "$ref": "#/components/schemas/ServerCatalogue"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHORIZED — missing or invalid key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "RATE_LIMITED"
          }
        }
      }
    },
    "/servers": {
      "get": {
        "tags": [
          "Servers"
        ],
        "summary": "List your servers (newest first, deleted excluded)",
        "parameters": [
          {
            "name": "offset",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "default": 0
            }
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 20
            },
            "description": "at most 50 items are returned per page"
          }
        ],
        "responses": {
          "200": {
            "description": "items, total",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "items": {
                          "type": "array",
                          "items": {
                            "$ref": "#/components/schemas/Server"
                          }
                        },
                        "total": {
                          "type": "integer"
                        },
                        "offset": {
                          "type": "integer"
                        },
                        "limit": {
                          "type": "integer"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHORIZED — missing or invalid key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "RATE_LIMITED"
          }
        }
      },
      "post": {
        "tags": [
          "Servers"
        ],
        "summary": "Order a server (charges the first term)",
        "description": "Heavy rate limit (20/min). Not idempotent: every success is another paid server. If provisioning fails for good the server ends FAILED and the first term is refunded.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "spec",
                  "period"
                ],
                "properties": {
                  "spec": {
                    "$ref": "#/components/schemas/Spec"
                  },
                  "os": {
                    "type": "string",
                    "maxLength": 40,
                    "description": "image code from the catalogue; required unless app is given"
                  },
                  "app": {
                    "type": "string",
                    "maxLength": 40,
                    "description": "pre-installed app code; forces its baseOs and needs minRamMb"
                  },
                  "period": {
                    "type": "string",
                    "enum": [
                      "MONTH",
                      "QUARTER",
                      "HALF_YEAR",
                      "YEAR"
                    ]
                  },
                  "region": {
                    "type": "string",
                    "maxLength": 40
                  },
                  "proxy": {
                    "type": "boolean",
                    "description": "front-proxy add-on, priced into every term"
                  },
                  "sshKeyIds": {
                    "type": "array",
                    "maxItems": 10,
                    "items": {
                      "type": "string",
                      "format": "uuid"
                    },
                    "description": "keys saved on the account (managed in the bot); foreign ids are ignored"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Server in PENDING; poll GET /servers/{id} until ACTIVE",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "$ref": "#/components/schemas/Server"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "VALIDATION_ERROR · NO_CAPACITY · NO_IP_AVAILABLE · NO_TEMPLATE · PROXY_NO_CAPACITY — nothing charged",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "402": {
            "description": "INSUFFICIENT_FUNDS",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHORIZED — missing or invalid key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "RATE_LIMITED"
          }
        }
      }
    },
    "/servers/{id}": {
      "get": {
        "tags": [
          "Servers"
        ],
        "summary": "One server",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Server",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "$ref": "#/components/schemas/Server"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "SERVER_NOT_FOUND",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHORIZED — missing or invalid key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "RATE_LIMITED"
          }
        }
      },
      "patch": {
        "tags": [
          "Servers"
        ],
        "summary": "Change auto-renew and/or alias",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "autoRenew": {
                    "type": "boolean",
                    "description": "ACTIVE / SUSPENDED servers only"
                  },
                  "alias": {
                    "type": "string",
                    "nullable": true,
                    "maxLength": 32,
                    "description": "null or empty clears it"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Server",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "$ref": "#/components/schemas/Server"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "SERVER_NOT_FOUND",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHORIZED — missing or invalid key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "RATE_LIMITED"
          }
        }
      }
    },
    "/servers/{id}/credentials": {
      "get": {
        "tags": [
          "Servers"
        ],
        "summary": "Login and password (the only place secrets are returned)",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "ServerCredentials",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "$ref": "#/components/schemas/ServerCredentials"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "SERVER_NOT_FOUND",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHORIZED — missing or invalid key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "RATE_LIMITED"
          }
        }
      }
    },
    "/servers/{id}/actions": {
      "post": {
        "tags": [
          "Servers"
        ],
        "summary": "Start, stop, reboot or reinstall",
        "description": "reinstall erases the disk and clones a clean image (the same one when neither os nor app is given); IP, size and password are kept. NO_TEMPLATE if the image is not on the server's node.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "action"
                ],
                "properties": {
                  "action": {
                    "type": "string",
                    "enum": [
                      "start",
                      "stop",
                      "reboot",
                      "reinstall"
                    ]
                  },
                  "os": {
                    "type": "string",
                    "maxLength": 40,
                    "description": "reinstall only: another image"
                  },
                  "app": {
                    "type": "string",
                    "maxLength": 40,
                    "description": "reinstall only: a pre-installed app"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "queued",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "queued": {
                          "type": "boolean",
                          "enum": [
                            true
                          ]
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "SERVER_NOT_ACTIVE · VALIDATION_ERROR",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "SERVER_NOT_FOUND",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "SERVER_BUSY",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHORIZED — missing or invalid key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "RATE_LIMITED"
          }
        }
      }
    },
    "/servers/{id}/renew": {
      "post": {
        "tags": [
          "Servers · renewal & upgrade"
        ],
        "summary": "Renew one term (charges the balance)",
        "description": "Extends from max(expiresAt, now); a SUSPENDED server is resumed. Each success adds a term.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Server",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "$ref": "#/components/schemas/Server"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "SERVER_NOT_ACTIVE",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "402": {
            "description": "INSUFFICIENT_FUNDS",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "SERVER_NOT_FOUND",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHORIZED — missing or invalid key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "RATE_LIMITED"
          }
        }
      }
    },
    "/servers/{id}/term": {
      "get": {
        "tags": [
          "Servers · renewal & upgrade"
        ],
        "summary": "Renewal terms with today's prices",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "TermOption[]",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/TermOption"
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "SERVER_NOT_FOUND",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHORIZED — missing or invalid key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "RATE_LIMITED"
          }
        }
      },
      "put": {
        "tags": [
          "Servers · renewal & upgrade"
        ],
        "summary": "Change the renewal term (nothing charged now)",
        "description": "The new term and its price apply from the next renewal; expiresAt does not move.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "period"
                ],
                "properties": {
                  "period": {
                    "type": "string",
                    "enum": [
                      "MONTH",
                      "QUARTER",
                      "HALF_YEAR",
                      "YEAR"
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "TermOption[]",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/TermOption"
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "SERVER_NOT_FOUND",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHORIZED — missing or invalid key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "RATE_LIMITED"
          }
        }
      }
    },
    "/servers/{id}/upgrade/quote": {
      "post": {
        "tags": [
          "Servers · renewal & upgrade"
        ],
        "summary": "Price of an upgrade",
        "description": "Only bigger: every value the same or larger, at least one larger.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "spec"
                ],
                "properties": {
                  "spec": {
                    "$ref": "#/components/schemas/Spec"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "UpgradeQuote",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "$ref": "#/components/schemas/UpgradeQuote"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "SERVER_NOT_ACTIVE · VALIDATION_ERROR",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "SERVER_NOT_FOUND",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHORIZED — missing or invalid key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "RATE_LIMITED"
          }
        }
      }
    },
    "/servers/{id}/upgrade": {
      "post": {
        "tags": [
          "Servers · renewal & upgrade"
        ],
        "summary": "Upgrade (charges the balance, applied by a restart)",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "spec",
                  "maxCharge"
                ],
                "properties": {
                  "spec": {
                    "$ref": "#/components/schemas/Spec"
                  },
                  "maxCharge": {
                    "type": "string",
                    "pattern": "^\\d{1,7}(\\.\\d{1,2})?$",
                    "example": "5.48",
                    "description": "the most you agree to pay now — the quote's charge"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "UpgradeQuote that was charged; the resize is queued",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "$ref": "#/components/schemas/UpgradeQuote"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "UPGRADE_PRICE_CHANGED (details = fresh UpgradeQuote) · NO_CAPACITY · SERVER_NOT_ACTIVE · VALIDATION_ERROR",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "402": {
            "description": "INSUFFICIENT_FUNDS",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "SERVER_NOT_FOUND",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "SERVER_BUSY",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHORIZED — missing or invalid key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "RATE_LIMITED"
          }
        }
      }
    },
    "/servers/{id}/firewall": {
      "get": {
        "tags": [
          "Servers · firewall"
        ],
        "summary": "Firewall state and rules",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Firewall",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "$ref": "#/components/schemas/Firewall"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "SERVER_NOT_FOUND",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHORIZED — missing or invalid key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "RATE_LIMITED"
          }
        }
      },
      "patch": {
        "tags": [
          "Servers · firewall"
        ],
        "summary": "Turn the firewall on or off",
        "description": "On = inbound dropped except the rules. Tenant isolation and anti-spoofing stay on in every state; proxy 80/443 is allowed automatically.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "enabled"
                ],
                "properties": {
                  "enabled": {
                    "type": "boolean"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Firewall",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "$ref": "#/components/schemas/Firewall"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "SERVER_NOT_ACTIVE · VALIDATION_ERROR (malformed rule, 20 rules already)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "SERVER_NOT_FOUND · NOT_FOUND",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "SERVER_BUSY",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "PROVIDER_ERROR — the hypervisor refused; previous rules kept",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHORIZED — missing or invalid key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "RATE_LIMITED"
          }
        }
      }
    },
    "/servers/{id}/firewall/rules": {
      "post": {
        "tags": [
          "Servers · firewall"
        ],
        "summary": "Add a rule",
        "description": "Up to 20 rules; an identical rule changes nothing.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "rule"
                ],
                "properties": {
                  "rule": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 80,
                    "example": "3306 from 1.2.3.4",
                    "description": "\"22\", \"80,443\", \"8000:8100/udp\", \"3306 from 1.2.3.4\", \"ping\""
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Firewall",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "$ref": "#/components/schemas/Firewall"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "SERVER_NOT_ACTIVE · VALIDATION_ERROR (malformed rule, 20 rules already)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "SERVER_NOT_FOUND · NOT_FOUND",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "SERVER_BUSY",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "PROVIDER_ERROR — the hypervisor refused; previous rules kept",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHORIZED — missing or invalid key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "RATE_LIMITED"
          }
        }
      }
    },
    "/servers/{id}/firewall/rules/{index}": {
      "delete": {
        "tags": [
          "Servers · firewall"
        ],
        "summary": "Remove the rule at a position",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "index",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "minimum": 0,
              "maximum": 50
            },
            "description": "0-based position in rules; positions shift after a removal"
          }
        ],
        "responses": {
          "200": {
            "description": "Firewall",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "$ref": "#/components/schemas/Firewall"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "SERVER_NOT_ACTIVE · VALIDATION_ERROR (malformed rule, 20 rules already)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "SERVER_NOT_FOUND · NOT_FOUND",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "SERVER_BUSY",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "PROVIDER_ERROR — the hypervisor refused; previous rules kept",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHORIZED — missing or invalid key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "RATE_LIMITED"
          }
        }
      }
    },
    "/hosting/catalogue": {
      "get": {
        "tags": [
          "Hosting"
        ],
        "summary": "Hosting plans and prices",
        "responses": {
          "200": {
            "description": "HostingCatalogue",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "$ref": "#/components/schemas/HostingCatalogue"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHORIZED — missing or invalid key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "RATE_LIMITED"
          }
        }
      }
    },
    "/hosting": {
      "get": {
        "tags": [
          "Hosting"
        ],
        "summary": "List your hosting accounts (PENDING, ACTIVE, SUSPENDED)",
        "parameters": [
          {
            "name": "offset",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "default": 0
            }
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 20
            },
            "description": "at most 50 items are returned per page"
          }
        ],
        "responses": {
          "200": {
            "description": "items, total",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "items": {
                          "type": "array",
                          "items": {
                            "$ref": "#/components/schemas/Hosting"
                          }
                        },
                        "total": {
                          "type": "integer"
                        },
                        "offset": {
                          "type": "integer"
                        },
                        "limit": {
                          "type": "integer"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHORIZED — missing or invalid key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "RATE_LIMITED"
          }
        }
      },
      "post": {
        "tags": [
          "Hosting"
        ],
        "summary": "Order hosting (charges the term)",
        "description": "Heavy rate limit (20/min). Created synchronously; a panel failure refunds the charge.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "plan",
                  "domain",
                  "period"
                ],
                "properties": {
                  "plan": {
                    "type": "string",
                    "maxLength": 40,
                    "description": "plan code"
                  },
                  "domain": {
                    "type": "string",
                    "minLength": 3,
                    "maxLength": 253
                  },
                  "period": {
                    "type": "string",
                    "enum": [
                      "MONTH",
                      "QUARTER",
                      "HALF_YEAR",
                      "YEAR"
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Hosting, already ACTIVE",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "$ref": "#/components/schemas/Hosting"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "DOMAIN_INVALID · PLAN_INACTIVE · VALIDATION_ERROR",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "402": {
            "description": "INSUFFICIENT_FUNDS",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "PLAN_NOT_FOUND",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "DOMAIN_UNAVAILABLE — the domain is already on a hosting account",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "PROVIDER_ERROR (refunded) · PROVIDER_DISABLED",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHORIZED — missing or invalid key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "RATE_LIMITED"
          }
        }
      }
    },
    "/hosting/{id}": {
      "get": {
        "tags": [
          "Hosting"
        ],
        "summary": "One hosting account",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Hosting",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "$ref": "#/components/schemas/Hosting"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "HOSTING_NOT_FOUND",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHORIZED — missing or invalid key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "RATE_LIMITED"
          }
        }
      },
      "patch": {
        "tags": [
          "Hosting"
        ],
        "summary": "Change auto-renew",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "autoRenew"
                ],
                "properties": {
                  "autoRenew": {
                    "type": "boolean"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Hosting",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "$ref": "#/components/schemas/Hosting"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "HOSTING_NOT_FOUND",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHORIZED — missing or invalid key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "RATE_LIMITED"
          }
        }
      }
    },
    "/hosting/{id}/credentials": {
      "get": {
        "tags": [
          "Hosting"
        ],
        "summary": "Panel URL, login and password",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "HostingCredentials",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "$ref": "#/components/schemas/HostingCredentials"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "HOSTING_NOT_FOUND",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHORIZED — missing or invalid key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "RATE_LIMITED"
          }
        }
      }
    },
    "/hosting/{id}/renew": {
      "post": {
        "tags": [
          "Hosting"
        ],
        "summary": "Renew one term (charges the balance)",
        "description": "Extends from max(expiresAt, now); a SUSPENDED account becomes ACTIVE.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Hosting",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "$ref": "#/components/schemas/Hosting"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "HOSTING_NOT_ACTIVE",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "402": {
            "description": "INSUFFICIENT_FUNDS",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "HOSTING_NOT_FOUND",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHORIZED — missing or invalid key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "RATE_LIMITED"
          }
        }
      }
    },
    "/hosting/{id}/term": {
      "get": {
        "tags": [
          "Hosting"
        ],
        "summary": "Renewal terms with today's prices",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "TermOption[]",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/TermOption"
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "HOSTING_NOT_FOUND",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHORIZED — missing or invalid key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "RATE_LIMITED"
          }
        }
      },
      "put": {
        "tags": [
          "Hosting"
        ],
        "summary": "Change the renewal term (nothing charged now)",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "period"
                ],
                "properties": {
                  "period": {
                    "type": "string",
                    "enum": [
                      "MONTH",
                      "QUARTER",
                      "HALF_YEAR",
                      "YEAR"
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "TermOption[]",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/TermOption"
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "HOSTING_NOT_FOUND",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHORIZED — missing or invalid key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "RATE_LIMITED"
          }
        }
      }
    },
    "/hosting/{id}/plan/quote": {
      "post": {
        "tags": [
          "Hosting"
        ],
        "summary": "Price of moving to a bigger plan",
        "description": "Only a more expensive plan is accepted.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "plan"
                ],
                "properties": {
                  "plan": {
                    "type": "string",
                    "maxLength": 40
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "PlanQuote",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "$ref": "#/components/schemas/PlanQuote"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "HOSTING_NOT_ACTIVE · VALIDATION_ERROR",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "HOSTING_NOT_FOUND · PLAN_NOT_FOUND",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHORIZED — missing or invalid key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "RATE_LIMITED"
          }
        }
      }
    },
    "/hosting/{id}/plan": {
      "post": {
        "tags": [
          "Hosting"
        ],
        "summary": "Change to a bigger plan (charges the balance)",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "plan",
                  "maxCharge"
                ],
                "properties": {
                  "plan": {
                    "type": "string",
                    "maxLength": 40
                  },
                  "maxCharge": {
                    "type": "string",
                    "pattern": "^\\d{1,7}(\\.\\d{1,2})?$",
                    "example": "4.52"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "PlanQuote that was charged",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "$ref": "#/components/schemas/PlanQuote"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "UPGRADE_PRICE_CHANGED (details = { charge }) · HOSTING_NOT_ACTIVE · VALIDATION_ERROR",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "402": {
            "description": "INSUFFICIENT_FUNDS",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "HOSTING_NOT_FOUND · PLAN_NOT_FOUND",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "PROVIDER_ERROR — the panel refused; charge refunded, plan restored",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHORIZED — missing or invalid key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "RATE_LIMITED"
          }
        }
      }
    },
    "/domains/{id}/cloudflare": {
      "get": {
        "summary": "Cloudflare zone status",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "connected, nameservers, zoneStatus"
          },
          "401": {
            "description": "UNAUTHORIZED — missing or invalid key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "RATE_LIMITED"
          }
        },
        "tags": [
          "Cloudflare · zone"
        ]
      },
      "post": {
        "summary": "Connect the domain to Cloudflare",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "201": {
            "description": "zone created; nameservers switched"
          },
          "401": {
            "description": "UNAUTHORIZED — missing or invalid key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "RATE_LIMITED"
          }
        },
        "tags": [
          "Cloudflare · zone"
        ]
      },
      "delete": {
        "summary": "Disconnect from Cloudflare",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "disconnected"
          },
          "401": {
            "description": "UNAUTHORIZED — missing or invalid key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "RATE_LIMITED"
          }
        },
        "tags": [
          "Cloudflare · zone"
        ]
      }
    },
    "/domains/{id}/dns": {
      "get": {
        "summary": "DNS records (Cloudflare)",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "list of DnsRecord"
          },
          "401": {
            "description": "UNAUTHORIZED — missing or invalid key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "RATE_LIMITED"
          }
        },
        "tags": [
          "Cloudflare · DNS"
        ]
      },
      "post": {
        "summary": "Add a record",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DnsInput"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "DnsRecord"
          },
          "409": {
            "description": "DNS_EXISTS"
          },
          "401": {
            "description": "UNAUTHORIZED — missing or invalid key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "RATE_LIMITED"
          }
        },
        "tags": [
          "Cloudflare · DNS"
        ]
      }
    },
    "/domains/{id}/dns/{recordId}": {
      "put": {
        "summary": "Replace a record",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "recordId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DnsInput"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "DnsRecord"
          },
          "401": {
            "description": "UNAUTHORIZED — missing or invalid key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "RATE_LIMITED"
          }
        },
        "tags": [
          "Cloudflare · DNS"
        ]
      },
      "delete": {
        "summary": "Delete a record",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "recordId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "deleted"
          },
          "401": {
            "description": "UNAUTHORIZED — missing or invalid key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "RATE_LIMITED"
          }
        },
        "tags": [
          "Cloudflare · DNS"
        ]
      }
    },
    "/domains/{id}/cloudflare/refresh": {
      "post": {
        "summary": "Re-read zone status from Cloudflare",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "zone status"
          },
          "401": {
            "description": "UNAUTHORIZED — missing or invalid key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "RATE_LIMITED"
          }
        },
        "tags": [
          "Cloudflare · zone"
        ]
      }
    },
    "/domains/{id}/cloudflare/settings": {
      "get": {
        "summary": "Zone settings",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Settings",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Settings"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHORIZED — missing or invalid key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "RATE_LIMITED"
          }
        },
        "tags": [
          "Cloudflare · settings"
        ]
      },
      "patch": {
        "summary": "Change any subset of settings",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/Settings"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Settings after the change"
          },
          "401": {
            "description": "UNAUTHORIZED — missing or invalid key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "RATE_LIMITED"
          }
        },
        "tags": [
          "Cloudflare · settings"
        ]
      }
    },
    "/domains/{id}/cloudflare/purge": {
      "post": {
        "summary": "Purge the cache",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "purged"
          },
          "401": {
            "description": "UNAUTHORIZED — missing or invalid key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "RATE_LIMITED"
          }
        },
        "tags": [
          "Cloudflare · settings"
        ]
      }
    },
    "/domains/{id}/cloudflare/redirects": {
      "get": {
        "summary": "Redirect rules",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "list of Redirect"
          },
          "401": {
            "description": "UNAUTHORIZED — missing or invalid key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "RATE_LIMITED"
          }
        },
        "tags": [
          "Cloudflare · redirects"
        ]
      },
      "post": {
        "summary": "Add a redirect",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "match",
                  "target"
                ],
                "properties": {
                  "match": {
                    "type": "string"
                  },
                  "target": {
                    "type": "string",
                    "format": "uri"
                  },
                  "permanent": {
                    "type": "boolean",
                    "default": true
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Redirect"
          },
          "409": {
            "description": "REDIRECT_EXISTS / REDIRECT_LIMIT"
          },
          "401": {
            "description": "UNAUTHORIZED — missing or invalid key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "RATE_LIMITED"
          }
        },
        "tags": [
          "Cloudflare · redirects"
        ]
      }
    },
    "/domains/{id}/cloudflare/redirects/{ruleId}": {
      "delete": {
        "summary": "Remove a redirect",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "ruleId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "deleted"
          },
          "401": {
            "description": "UNAUTHORIZED — missing or invalid key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "RATE_LIMITED"
          }
        },
        "tags": [
          "Cloudflare · redirects"
        ]
      }
    },
    "/webhooks/events": {
      "get": {
        "tags": [
          "Webhooks"
        ],
        "summary": "Event names",
        "responses": {
          "200": {
            "description": "list of strings"
          },
          "401": {
            "description": "UNAUTHORIZED"
          },
          "429": {
            "description": "RATE_LIMITED"
          }
        }
      }
    },
    "/webhooks": {
      "get": {
        "tags": [
          "Webhooks"
        ],
        "summary": "Your endpoints",
        "responses": {
          "200": {
            "description": "list of Webhook"
          },
          "401": {
            "description": "UNAUTHORIZED"
          },
          "429": {
            "description": "RATE_LIMITED"
          }
        }
      },
      "post": {
        "tags": [
          "Webhooks"
        ],
        "summary": "Add an endpoint (secret returned once)",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "url"
                ],
                "properties": {
                  "url": {
                    "type": "string",
                    "format": "uri"
                  },
                  "events": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Webhook with secret"
          },
          "400": {
            "description": "VALIDATION_ERROR (non-https / private url)"
          },
          "401": {
            "description": "UNAUTHORIZED"
          },
          "429": {
            "description": "RATE_LIMITED"
          }
        }
      }
    },
    "/webhooks/{id}": {
      "patch": {
        "tags": [
          "Webhooks"
        ],
        "summary": "Enable / disable",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "active"
                ],
                "properties": {
                  "active": {
                    "type": "boolean"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Webhook"
          },
          "401": {
            "description": "UNAUTHORIZED"
          },
          "429": {
            "description": "RATE_LIMITED"
          }
        }
      },
      "delete": {
        "tags": [
          "Webhooks"
        ],
        "summary": "Remove",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "deleted"
          },
          "401": {
            "description": "UNAUTHORIZED"
          },
          "429": {
            "description": "RATE_LIMITED"
          }
        }
      }
    },
    "/webhooks/{id}/test": {
      "post": {
        "tags": [
          "Webhooks"
        ],
        "summary": "Queue a ping",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "202": {
            "description": "deliveryId"
          },
          "401": {
            "description": "UNAUTHORIZED"
          },
          "429": {
            "description": "RATE_LIMITED"
          }
        }
      }
    },
    "/webhooks/{id}/rotate-secret": {
      "post": {
        "tags": [
          "Webhooks"
        ],
        "summary": "Issue a new secret",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Webhook with new secret"
          },
          "401": {
            "description": "UNAUTHORIZED"
          },
          "429": {
            "description": "RATE_LIMITED"
          }
        }
      }
    },
    "/webhooks/{id}/deliveries": {
      "get": {
        "tags": [
          "Webhooks"
        ],
        "summary": "Last 20 deliveries",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "list of Delivery"
          },
          "401": {
            "description": "UNAUTHORIZED"
          },
          "429": {
            "description": "RATE_LIMITED"
          }
        }
      }
    }
  },
  "tags": [
    {
      "name": "Account"
    },
    {
      "name": "Availability",
      "description": "Prices and registry-verified availability checks"
    },
    {
      "name": "Domains",
      "description": "Domains you own: list, register, nameservers, auto-renew"
    },
    {
      "name": "Renewal"
    },
    {
      "name": "Servers",
      "description": "KVM VPS: catalogue, order, details, credentials, power and reinstall"
    },
    {
      "name": "Servers · renewal & upgrade",
      "description": "Renewal, renewal term, upgrade (bigger only, pro rata)"
    },
    {
      "name": "Servers · firewall",
      "description": "Inbound allow-list on the hypervisor"
    },
    {
      "name": "Hosting",
      "description": "Shared web hosting (HestiaCP): plans, order, credentials, renewal, term, plan change"
    },
    {
      "name": "Cloudflare · zone",
      "description": "Connect, disconnect, status"
    },
    {
      "name": "Cloudflare · DNS"
    },
    {
      "name": "Cloudflare · settings",
      "description": "SSL mode, security switches, cache"
    },
    {
      "name": "Cloudflare · redirects"
    },
    {
      "name": "Webhooks",
      "description": "Signed event callbacks: domain.blocked, domain.unblocked, domain.registered, domain.renewed, domain.expiring, domain.expired"
    }
  ]
}