{
  "openapi": "3.1.0",
  "info": {
    "title": "SeeDropHost API",
    "version": "0.1.0",
    "summary": "Control API of a self-hosted SeeDropHost server.",
    "description": "Publish static sites (one HTML file, a .zip or a folder by manifest), delete sites, manage drafts, publishing and rollback, environment variables, custom domains, forms and the audit log, and manage accounts, tokens, plan usage, the plan subscription (Pix or boleto through Asaas) and the \"take everything\" export. Every route needs `Authorization: Bearer <token>` except GET /v1/health, POST /v1/drop and POST /v1/billing/asaas/webhook (authenticated by the `asaas-access-token` header). There are two kinds of token: the server token (`SDH_TOKEN`) is the administrator, sees every account and is the only one that can create accounts; an account token (`sdh_…`, created with POST /v1/account/tokens, up to 20 active per account) sees and changes only the sites of its own account, and a site, deploy or token of another account answers 404, the same as one that does not exist. Optional header `x-sdh-actor` (up to 64 characters) names who appears in the audit log (default `api`). Error messages are in Brazilian Portuguese. There is no public hosted instance yet: point the server URL to your own server. Docs: https://seedrophost.com/docs/api/ — checked against the code on 2026-10-31.",
    "contact": {
      "name": "SeeDropHost",
      "url": "https://seedrophost.com/"
    }
  },
  "externalDocs": {
    "description": "HTTP API reference",
    "url": "https://seedrophost.com/docs/api/"
  },
  "servers": [
    {
      "url": "{baseUrl}",
      "description": "Your SeeDropHost server",
      "variables": {
        "baseUrl": {
          "default": "http://localhost:8787",
          "description": "Base URL of your server (development default shown)"
        }
      }
    }
  ],
  "security": [
    {
      "bearer": []
    }
  ],
  "tags": [
    {
      "name": "health"
    },
    {
      "name": "sites"
    },
    {
      "name": "deploys"
    },
    {
      "name": "drop"
    },
    {
      "name": "env"
    },
    {
      "name": "domains"
    },
    {
      "name": "forms"
    },
    {
      "name": "export",
      "description": "Take everything: files, leads and variable names of a site"
    },
    {
      "name": "audit"
    },
    {
      "name": "account",
      "description": "The account of the token: details, usage against the plan, tokens"
    },
    {
      "name": "accounts",
      "description": "Administrator only: create and list accounts, change plan"
    },
    {
      "name": "billing",
      "description": "Plan subscription paid by Pix or boleto on the Asaas invoice (a card is paid on the Asaas page and never passes through the server). The price always comes from the plan table on the server. Off unless the administrator sets SDH_ASAAS_API_KEY."
    },
    {
      "name": "github",
      "description": "Deploy on every push through a GitHub App created with one click (manifest flow). Push on the production branch publishes (or becomes a draft); other branches and pull requests become previews with a commit status and one PR comment. No build yet. Needs SDH_PANEL_HOST."
    },
    {
      "name": "internal"
    },
    {
      "name": "notifications",
      "description": "Lead notices (e-mail through Resend, signed webhook) and automatic IndexNow when a deploy goes live. Sent from a queue with retries."
    }
  ],
  "paths": {
    "/v1/health": {
      "get": {
        "tags": [
          "health"
        ],
        "operationId": "getHealth",
        "summary": "Version and database check",
        "security": [],
        "responses": {
          "200": {
            "description": "Healthy",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Health"
                }
              }
            }
          },
          "503": {
            "description": "Database not answering",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Health"
                }
              }
            }
          }
        }
      }
    },
    "/v1/sites": {
      "get": {
        "tags": [
          "sites"
        ],
        "operationId": "listSites",
        "summary": "List sites",
        "responses": {
          "200": {
            "description": "Sites",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Site"
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        },
        "parameters": [
          {
            "$ref": "#/components/parameters/Conta"
          }
        ],
        "description": "An account token lists only the sites of its account. The administrator sees all sites, or one account with `?conta=`."
      },
      "post": {
        "tags": [
          "sites"
        ],
        "operationId": "createSite",
        "summary": "Create a site",
        "parameters": [
          {
            "$ref": "#/components/parameters/Actor"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "name"
                ],
                "properties": {
                  "name": {
                    "$ref": "#/components/schemas/SiteName"
                  },
                  "conta": {
                    "type": "string",
                    "description": "Administrator only: account that receives the site (default `principal`). Account tokens always create in their own account."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Site"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "$ref": "#/components/responses/PlanLimit"
          },
          "409": {
            "$ref": "#/components/responses/Error"
          }
        },
        "description": "Creates a site in the account of the token. Beyond the plan's site count the answer is 402 `plan_limit`."
      }
    },
    "/v1/sites/{site}": {
      "get": {
        "tags": [
          "sites"
        ],
        "operationId": "getSite",
        "summary": "Get a site with its URL and domains",
        "parameters": [
          {
            "$ref": "#/components/parameters/Site"
          }
        ],
        "responses": {
          "200": {
            "description": "Site",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Site"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "url": {
                          "type": "string"
                        },
                        "domains": {
                          "type": "array",
                          "items": {
                            "$ref": "#/components/schemas/Domain"
                          }
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/Error"
          }
        }
      },
      "delete": {
        "tags": [
          "sites"
        ],
        "operationId": "deleteSite",
        "summary": "Delete a site at once",
        "description": "Takes the site down and deletes it with its deploys, domains, forms and leads; files no other deploy uses are removed from storage. Recorded in the audit log as `site.delete`. There is no undo.",
        "parameters": [
          {
            "$ref": "#/components/parameters/Site"
          }
        ],
        "responses": {
          "200": {
            "description": "Deleted",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "deleted"
                  ],
                  "properties": {
                    "deleted": {
                      "type": "string",
                      "description": "Name of the deleted site"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/v1/sites/{site}/export": {
      "get": {
        "tags": [
          "export"
        ],
        "operationId": "exportSite",
        "summary": "Take everything: zip of the site",
        "description": "A zip with `site/` (files of the live deploy, including `_redirects`, `_headers` and `netlify.toml` / `seedrop.toml`), `leads.csv` (all submissions, with a spam column; cells that start with = + - @ get an apostrophe so they never run as formulas), `variaveis.txt` (variable names only: values never leave, not even masked) and `LEIA-ME.txt`. With `?resumo=1` it answers JSON with the numbers and the download path instead of the zip. Anonymous drops have nothing to export: claim them first.",
        "parameters": [
          {
            "$ref": "#/components/parameters/Site"
          },
          {
            "name": "resumo",
            "in": "query",
            "description": "1 returns only the summary (no zip)",
            "schema": {
              "enum": [
                "1"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The zip (`content-disposition: attachment`), or the summary with `?resumo=1`",
            "content": {
              "application/zip": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ExportSummary"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/Error"
          },
          "409": {
            "description": "Anonymous site (`anonymous_site`)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/sites/{site}/deploys": {
      "get": {
        "tags": [
          "deploys"
        ],
        "operationId": "listDeploys",
        "summary": "List deploys, latest first",
        "parameters": [
          {
            "$ref": "#/components/parameters/Site"
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 20
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Deploys",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "allOf": [
                      {
                        "$ref": "#/components/schemas/Deploy"
                      },
                      {
                        "type": "object",
                        "properties": {
                          "live": {
                            "type": "boolean"
                          },
                          "url": {
                            "type": "string"
                          },
                          "score": {
                            "type": [
                              "integer",
                              "null"
                            ]
                          }
                        }
                      }
                    ]
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/Error"
          }
        }
      },
      "post": {
        "tags": [
          "deploys"
        ],
        "operationId": "createDeploy",
        "summary": "Create a deploy from a manifest (path → SHA-256)",
        "description": "Returns the hashes the server does not have yet in `required`. Upload each with PUT /v1/deploys/{id}/blobs/{hash}, then POST /v1/deploys/{id}/finalize. When `required` is empty the deploy is already ready. Up to 50 000 files.",
        "parameters": [
          {
            "$ref": "#/components/parameters/Site"
          },
          {
            "$ref": "#/components/parameters/Actor"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "files"
                ],
                "properties": {
                  "files": {
                    "type": "object",
                    "description": "Public path → SHA-256 in hex",
                    "additionalProperties": {
                      "type": "string",
                      "pattern": "^[0-9a-f]{64}$"
                    }
                  },
                  "draft": {
                    "type": "boolean",
                    "description": "true: do not publish when ready"
                  },
                  "title": {
                    "type": "string"
                  },
                  "source": {
                    "type": "string"
                  },
                  "git_ref": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "deploy": {
                      "$ref": "#/components/schemas/Deploy"
                    },
                    "required": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    },
                    "urls": {
                      "$ref": "#/components/schemas/Urls"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/v1/sites/{site}/deploys/zip": {
      "post": {
        "tags": [
          "deploys"
        ],
        "operationId": "deployZip",
        "summary": "Deploy a .zip in one step",
        "description": "Body: the zip file. Limits: 100 MB request, 20 000 entries, 500 MiB uncompressed, 100 MiB per file, ratio 200:1. A single top-level folder becomes the site root.",
        "parameters": [
          {
            "$ref": "#/components/parameters/Site"
          },
          {
            "$ref": "#/components/parameters/Draft"
          },
          {
            "$ref": "#/components/parameters/Title"
          },
          {
            "$ref": "#/components/parameters/Source"
          },
          {
            "$ref": "#/components/parameters/Actor"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/zip": {
              "schema": {
                "type": "string",
                "contentMediaType": "application/zip"
              }
            }
          }
        },
        "responses": {
          "201": {
            "$ref": "#/components/responses/OneStepDeploy"
          },
          "400": {
            "$ref": "#/components/responses/Error"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/Error"
          },
          "413": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/v1/sites/{site}/deploys/html": {
      "post": {
        "tags": [
          "deploys"
        ],
        "operationId": "deployHtml",
        "summary": "Deploy a single HTML file in one step",
        "description": "Body: the HTML. It becomes /index.html.",
        "parameters": [
          {
            "$ref": "#/components/parameters/Site"
          },
          {
            "$ref": "#/components/parameters/Draft"
          },
          {
            "$ref": "#/components/parameters/Title"
          },
          {
            "$ref": "#/components/parameters/Source"
          },
          {
            "$ref": "#/components/parameters/Actor"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "text/html": {
              "schema": {
                "type": "string"
              }
            }
          }
        },
        "responses": {
          "201": {
            "$ref": "#/components/responses/OneStepDeploy"
          },
          "400": {
            "$ref": "#/components/responses/Error"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/Error"
          },
          "413": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/v1/drop": {
      "post": {
        "tags": [
          "drop"
        ],
        "operationId": "drop",
        "summary": "Publish without an account (24 h)",
        "security": [],
        "description": "Only when the server runs with SDH_ANON_DROP=1 (otherwise 404). Up to 25 MiB; zip: 20 000 entries, 50 MiB uncompressed, 25 MiB per file. 5 per network per hour (IPv4 address or IPv6 /64), a server-wide hourly cap, 2 at a time and a total storage quota. Sites are noindex, accept no forms, run no functions and expire after 24 h unless claimed.",
        "requestBody": {
          "required": true,
          "content": {
            "application/zip": {
              "schema": {
                "type": "string",
                "contentMediaType": "application/zip"
              }
            },
            "text/html": {
              "schema": {
                "type": "string"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Published",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "url": {
                      "type": "string"
                    },
                    "expires_at": {
                      "type": "string",
                      "format": "date-time"
                    },
                    "claim_token": {
                      "type": "string",
                      "description": "Shown only once"
                    },
                    "site": {
                      "type": "string"
                    },
                    "deploy_id": {
                      "type": "string"
                    },
                    "next_step": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error"
          },
          "404": {
            "$ref": "#/components/responses/Error"
          },
          "413": {
            "description": "`too_large`: body above 25 MiB, or the zip expands beyond 50 MiB in total / 25 MiB per file",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "415": {
            "$ref": "#/components/responses/Error"
          },
          "429": {
            "description": "`rate_limited`: more than 5 drops per network per hour (an IPv4 address or an IPv6 /64; Retry-After 3600), or the server-wide hourly cap `SDH_ANON_DROP_MAX_HOUR` was reached (Retry-After 600)",
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before trying again",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "`busy`: 2 drops are already being processed (Retry-After 10); or `drop_quota`: the storage for drops (`SDH_ANON_DROP_MAX_MB`) is full (Retry-After 3600)",
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before trying again",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/drop/claim": {
      "post": {
        "tags": [
          "drop"
        ],
        "operationId": "claimDrop",
        "summary": "Claim an anonymous drop into the account",
        "parameters": [
          {
            "$ref": "#/components/parameters/Actor"
          },
          {
            "$ref": "#/components/parameters/Conta"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "claim_token"
                ],
                "properties": {
                  "claim_token": {
                    "type": "string"
                  },
                  "name": {
                    "$ref": "#/components/schemas/SiteName"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Claimed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Site"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "$ref": "#/components/responses/PlanLimit"
          },
          "404": {
            "$ref": "#/components/responses/Error"
          },
          "410": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/v1/deploys/{id}": {
      "get": {
        "tags": [
          "deploys"
        ],
        "operationId": "getDeploy",
        "summary": "Get a deploy with its SEO/GEO report",
        "parameters": [
          {
            "$ref": "#/components/parameters/DeployId"
          }
        ],
        "responses": {
          "200": {
            "description": "Deploy",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Deploy"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "report": {
                          "oneOf": [
                            {
                              "$ref": "#/components/schemas/Report"
                            },
                            {
                              "type": "null"
                            }
                          ]
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/v1/deploys/{id}/blobs/{hash}": {
      "put": {
        "tags": [
          "deploys"
        ],
        "operationId": "uploadBlob",
        "summary": "Upload one file the deploy needs",
        "description": "The server checks that the content matches the SHA-256. Up to 100 MB.",
        "parameters": [
          {
            "$ref": "#/components/parameters/DeployId"
          },
          {
            "name": "hash",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^[0-9a-f]{64}$"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/octet-stream": {
              "schema": {
                "type": "string",
                "contentMediaType": "application/octet-stream"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Stored",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Ok"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/Error"
          },
          "409": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/v1/deploys/{id}/finalize": {
      "post": {
        "tags": [
          "deploys"
        ],
        "operationId": "finalizeDeploy",
        "summary": "Close the deploy, build the report, publish unless draft",
        "parameters": [
          {
            "$ref": "#/components/parameters/DeployId"
          },
          {
            "$ref": "#/components/parameters/Actor"
          }
        ],
        "responses": {
          "200": {
            "description": "Ready. `report_json` is the report as a JSON string.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DeployRaw"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/Error"
          },
          "409": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/v1/sites/{site}/publish": {
      "post": {
        "tags": [
          "deploys"
        ],
        "operationId": "publishDeploy",
        "summary": "Put a ready deploy live (approve a draft or roll back)",
        "parameters": [
          {
            "$ref": "#/components/parameters/Site"
          },
          {
            "$ref": "#/components/parameters/Actor"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "deploy_id"
                ],
                "properties": {
                  "deploy_id": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Published. `report_json` is the report as a JSON string; `draft` keeps recording how the deploy was created.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DeployRaw"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/Error"
          },
          "409": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/v1/sites/{site}/env": {
      "get": {
        "tags": [
          "env"
        ],
        "operationId": "listEnv",
        "summary": "List environment variables (secret values masked)",
        "parameters": [
          {
            "$ref": "#/components/parameters/Site"
          }
        ],
        "responses": {
          "200": {
            "description": "Variables",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/EnvVar"
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/v1/sites/{site}/env/{key}": {
      "put": {
        "tags": [
          "env"
        ],
        "operationId": "setEnv",
        "summary": "Create or replace a variable (encrypted at rest)",
        "parameters": [
          {
            "$ref": "#/components/parameters/Site"
          },
          {
            "$ref": "#/components/parameters/EnvKey"
          },
          {
            "$ref": "#/components/parameters/Actor"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "value"
                ],
                "properties": {
                  "value": {
                    "type": "string"
                  },
                  "secret": {
                    "type": "boolean",
                    "default": true
                  },
                  "scopes": {
                    "type": "array",
                    "items": {
                      "enum": [
                        "build",
                        "functions",
                        "runtime"
                      ]
                    }
                  },
                  "contexts": {
                    "type": "array",
                    "items": {
                      "enum": [
                        "production",
                        "preview"
                      ]
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Saved (value masked when secret)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EnvVar"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/Error"
          }
        }
      },
      "delete": {
        "tags": [
          "env"
        ],
        "operationId": "deleteEnv",
        "summary": "Delete a variable",
        "parameters": [
          {
            "$ref": "#/components/parameters/Site"
          },
          {
            "$ref": "#/components/parameters/EnvKey"
          },
          {
            "$ref": "#/components/parameters/Actor"
          }
        ],
        "responses": {
          "200": {
            "description": "Deleted",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Ok"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/v1/sites/{site}/domains": {
      "get": {
        "tags": [
          "domains"
        ],
        "operationId": "listDomains",
        "summary": "List custom domains of a site",
        "parameters": [
          {
            "$ref": "#/components/parameters/Site"
          }
        ],
        "responses": {
          "200": {
            "description": "Domains",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Domain"
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/Error"
          }
        }
      },
      "post": {
        "tags": [
          "domains"
        ],
        "operationId": "addDomain",
        "summary": "Connect a domain and get the DNS records to create",
        "parameters": [
          {
            "$ref": "#/components/parameters/Site"
          },
          {
            "$ref": "#/components/parameters/Actor"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "hostname"
                ],
                "properties": {
                  "hostname": {
                    "type": "string",
                    "examples": [
                      "www.example.com"
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Pending verification",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "hostname": {
                      "type": "string"
                    },
                    "site": {
                      "type": "string"
                    },
                    "status": {
                      "type": "string"
                    },
                    "dns": {
                      "$ref": "#/components/schemas/DnsRecords"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "409": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/v1/domains/{hostname}/verify": {
      "post": {
        "tags": [
          "domains"
        ],
        "operationId": "verifyDomain",
        "summary": "Look up DNS: verified, routed and next step",
        "parameters": [
          {
            "name": "hostname",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "$ref": "#/components/parameters/Actor"
          }
        ],
        "responses": {
          "200": {
            "description": "Result",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "hostname": {
                      "type": "string"
                    },
                    "verified": {
                      "type": "boolean"
                    },
                    "routed": {
                      "type": "boolean"
                    },
                    "found": {
                      "type": "object",
                      "properties": {
                        "txt": {
                          "type": "array",
                          "items": {
                            "type": "string"
                          }
                        },
                        "cname": {
                          "type": "array",
                          "items": {
                            "type": "string"
                          }
                        },
                        "a": {
                          "type": "array",
                          "items": {
                            "type": "string"
                          }
                        }
                      }
                    },
                    "next": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/Error"
          }
        },
        "description": "An account only verifies requests for its own sites; a domain that belongs only to another account answers as not registered."
      }
    },
    "/v1/sites/{site}/forms": {
      "get": {
        "tags": [
          "forms"
        ],
        "operationId": "listForms",
        "summary": "Forms detected in the site, with totals",
        "parameters": [
          {
            "$ref": "#/components/parameters/Site"
          }
        ],
        "responses": {
          "200": {
            "description": "Forms",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Form"
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/v1/sites/{site}/submissions": {
      "get": {
        "tags": [
          "forms"
        ],
        "operationId": "listSubmissions",
        "summary": "Form submissions (leads), latest first",
        "parameters": [
          {
            "$ref": "#/components/parameters/Site"
          },
          {
            "name": "form",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "spam",
            "in": "query",
            "description": "1 includes spam",
            "schema": {
              "enum": [
                "1"
              ]
            }
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 500,
              "default": 50
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Submissions",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Submission"
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/v1/audit": {
      "get": {
        "tags": [
          "audit"
        ],
        "operationId": "listAudit",
        "summary": "Audit log, latest first",
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 500,
              "default": 50
            }
          },
          {
            "$ref": "#/components/parameters/Conta"
          }
        ],
        "responses": {
          "200": {
            "description": "Entries",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/AuditEntry"
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/v1/accounts": {
      "post": {
        "tags": [
          "accounts"
        ],
        "operationId": "createAccount",
        "summary": "Create an account (administrator)",
        "description": "Creates the account and its first token. The token is shown only in this answer.",
        "parameters": [
          {
            "$ref": "#/components/parameters/Actor"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "nome"
                ],
                "properties": {
                  "nome": {
                    "type": "string",
                    "maxLength": 100,
                    "description": "Name of the client or agency"
                  },
                  "plano": {
                    "allOf": [
                      {
                        "$ref": "#/components/schemas/PlanId"
                      }
                    ],
                    "default": "gratis"
                  },
                  "rotulo": {
                    "type": "string",
                    "description": "Label of the first token (default \"primeiro token\")"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "conta": {
                      "$ref": "#/components/schemas/Account"
                    },
                    "token": {
                      "type": "string",
                      "description": "Secret of the first token (`sdh_…`), shown once"
                    },
                    "token_id": {
                      "type": "string"
                    },
                    "aviso": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          }
        }
      },
      "get": {
        "tags": [
          "accounts"
        ],
        "operationId": "listAccounts",
        "summary": "List accounts (administrator)",
        "responses": {
          "200": {
            "description": "Accounts with their site count",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "allOf": [
                      {
                        "$ref": "#/components/schemas/Account"
                      },
                      {
                        "type": "object",
                        "properties": {
                          "sites": {
                            "type": "integer"
                          }
                        }
                      }
                    ]
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          }
        }
      }
    },
    "/v1/accounts/{conta}": {
      "patch": {
        "tags": [
          "accounts"
        ],
        "operationId": "updateAccount",
        "summary": "Change plan, name or payment state (administrator)",
        "description": "Changing the plan takes effect at once. With billing on, the server sets `pagamento_falhou_em` by itself when an invoice is overdue and clears it when the invoice is paid.",
        "parameters": [
          {
            "$ref": "#/components/parameters/AccountId"
          },
          {
            "$ref": "#/components/parameters/Actor"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "plano": {
                    "$ref": "#/components/schemas/PlanId"
                  },
                  "nome": {
                    "type": "string",
                    "maxLength": 100
                  },
                  "pagamento_falhou_em": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "format": "date-time",
                    "description": "When the payment failed, or null when it is back"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated account",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Account"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/v1/account": {
      "get": {
        "tags": [
          "account"
        ],
        "operationId": "getAccount",
        "summary": "The account of the token",
        "description": "With the administrator token, `?conta=` picks the account (default `principal`).",
        "parameters": [
          {
            "$ref": "#/components/parameters/Conta"
          }
        ],
        "responses": {
          "200": {
            "description": "Account",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Account"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "admin": {
                          "type": "boolean",
                          "description": "true when the caller used the server token"
                        },
                        "sites": {
                          "type": "integer"
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/v1/account/usage": {
      "get": {
        "tags": [
          "account"
        ],
        "operationId": "getUsage",
        "summary": "Plan, limits and usage of the month",
        "description": "Sites, bandwidth and leads against the plan, plus state and next steps. Going over bandwidth or leads only gives a warning: no site goes offline and no lead is lost. Deploys never count.",
        "parameters": [
          {
            "$ref": "#/components/parameters/Conta"
          }
        ],
        "responses": {
          "200": {
            "description": "Usage",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AccountUsage"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/v1/account/tokens": {
      "post": {
        "tags": [
          "account"
        ],
        "operationId": "createToken",
        "summary": "Create a token for the account",
        "description": "One token per machine or agent. The secret is shown only in this answer. At most 20 active tokens per account; revoke one to create another.",
        "parameters": [
          {
            "$ref": "#/components/parameters/Conta"
          },
          {
            "$ref": "#/components/parameters/Actor"
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "rotulo": {
                    "type": "string",
                    "maxLength": 100,
                    "description": "Label (default \"token\")"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CreatedToken"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/Error"
          },
          "409": {
            "description": "The account already has 20 active tokens (`token_limit`)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "get": {
        "tags": [
          "account"
        ],
        "operationId": "listTokens",
        "summary": "List the tokens of the account (without the secret)",
        "description": "Revoked tokens stay visible for 90 days.",
        "parameters": [
          {
            "$ref": "#/components/parameters/Conta"
          }
        ],
        "responses": {
          "200": {
            "description": "Tokens",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/ApiToken"
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/v1/account/tokens/{token}": {
      "delete": {
        "tags": [
          "account"
        ],
        "operationId": "revokeToken",
        "summary": "Revoke a token at once",
        "description": "The token stops working immediately. A token of another account answers 404.",
        "parameters": [
          {
            "$ref": "#/components/parameters/TokenId"
          },
          {
            "$ref": "#/components/parameters/Conta"
          },
          {
            "$ref": "#/components/parameters/Actor"
          }
        ],
        "responses": {
          "200": {
            "description": "The revoked token",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiToken"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/v1/internal/tls-check": {
      "get": {
        "tags": [
          "internal"
        ],
        "operationId": "tlsCheck",
        "summary": "Internal: may Caddy issue a certificate for this name?",
        "security": [],
        "description": "Not for clients. Answers only calls from the machine itself without proxy headers (403 otherwise). 200 when the name is the base domain, an existing site, a ready deploy preview or a verified custom domain; 404 otherwise.",
        "x-internal": true,
        "parameters": [
          {
            "name": "domain",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Allowed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Ok"
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/Error"
          },
          "404": {
            "description": "Not allowed",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "const": false
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/account/billing": {
      "get": {
        "tags": [
          "billing"
        ],
        "operationId": "getBilling",
        "summary": "Subscription and payment of the account",
        "description": "State, plan, cycle, paid-until date, next charge, open invoice, a change waiting for payment or scheduled, the price table, messages and next steps. If the account has been waiting for payment for more than 2 minutes (or the paid period ended with no news), the server reads Asaas again, with growing waits (30 s up to 1 h) and for at most 24 h; if that fails, the answer comes from what is stored. Works with billing off (`cobranca_ligada: false`).",
        "parameters": [
          {
            "$ref": "#/components/parameters/Conta"
          }
        ],
        "responses": {
          "200": {
            "description": "Subscription",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BillingStatus"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/v1/account/billing/checkout": {
      "post": {
        "tags": [
          "billing"
        ],
        "operationId": "checkout",
        "summary": "Subscribe or change plan",
        "description": "Creates the subscription on Asaas and returns the invoice link and, when available, the Pix code. The price always comes from the plan table on the server: a `valor` sent in the body is ignored. Moving up from a paid plan applies at once, and the paid time left becomes days of the new plan (`credito_dias`); moving down applies at `pago_ate` (`efeito: agendada`), with no refund and no double charge. The same `Idempotency-Key`, or the same plan and cycle already waiting, returns the same subscription; there are never two open subscriptions for one account. CPF, CNPJ and email go to Asaas and are not stored on the server. At most 5 new attempts per account in 24 h.",
        "parameters": [
          {
            "$ref": "#/components/parameters/Conta"
          },
          {
            "$ref": "#/components/parameters/Actor"
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "description": "Any unique string per request (up to 100 characters), for example a UUID. Repeating it returns the same subscription instead of creating another.",
            "schema": {
              "type": "string",
              "maxLength": 100,
              "examples": [
                "5f1c2a9e-8d0b-4c1e-9f7a-2b6d3e4f5a60"
              ]
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "plano",
                  "nome",
                  "cpfCnpj",
                  "email"
                ],
                "properties": {
                  "plano": {
                    "$ref": "#/components/schemas/PaidPlanId"
                  },
                  "ciclo": {
                    "allOf": [
                      {
                        "$ref": "#/components/schemas/BillingCycle"
                      }
                    ],
                    "default": "mensal"
                  },
                  "nome": {
                    "type": "string",
                    "minLength": 2,
                    "maxLength": 100,
                    "description": "Who pays (person or company), as on the invoice"
                  },
                  "cpfCnpj": {
                    "type": "string",
                    "description": "CPF or CNPJ, with or without dots; the check digits are validated before calling Asaas"
                  },
                  "email": {
                    "type": "string",
                    "format": "email",
                    "description": "Receives the invoice and the receipt"
                  }
                }
              },
              "examples": {
                "pro": {
                  "value": {
                    "plano": "pro",
                    "ciclo": "mensal",
                    "nome": "Cliente Ltda",
                    "cpfCnpj": "11.222.333/0001-81",
                    "email": "financeiro@example.com"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Subscription created, changed, resumed or the same one again",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CheckoutResult"
                }
              }
            }
          },
          "400": {
            "description": "`invalid_plan`, `invalid_cycle`, `invalid_name`, `invalid_cpf_cnpj`, `invalid_email`; or `billing_rejected` when Asaas refuses the request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/Error"
          },
          "409": {
            "description": "`already_on_plan`: the account already has this plan and cycle; `payment_just_confirmed`: the waiting payment was just confirmed (check GET /v1/account/billing first); `scheduled_paid`: the scheduled change is already paid; `checkout_closed`: this Idempotency-Key belongs to a closed request (start a new one)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "`checkout_limit`: more than 5 attempts in 24 h; the open invoice is still valid",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "502": {
            "description": "`billing_auth`: Asaas refused this server's key (the administrator checks SDH_ASAAS_API_KEY and SDH_ASAAS_ENV)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "`billing_off`: the server has no SDH_ASAAS_API_KEY; or `billing_unavailable` / `billing_busy`: Asaas did not answer or asked for a pause (try again)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/account/billing/cancel": {
      "post": {
        "tags": [
          "billing"
        ],
        "operationId": "cancelSubscription",
        "summary": "Cancel the subscription at the end of the paid period",
        "description": "Asaas stops charging now; the plan lasts until `pago_ate` and then the account goes back to Free. Nothing is deleted and no site goes offline. Before cancelling, the server reads Asaas again so a payment that just arrived is never thrown away. Returns the same body as GET /v1/account/billing.",
        "parameters": [
          {
            "$ref": "#/components/parameters/Conta"
          },
          {
            "$ref": "#/components/parameters/Actor"
          }
        ],
        "responses": {
          "200": {
            "description": "Cancelled",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BillingStatus"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/Error"
          },
          "409": {
            "description": "`no_subscription`: the account is on Free or already cancelled; `payment_just_confirmed`: the waiting payment was just confirmed (ask again to cancel it); `scheduled_paid`: the next subscription is already paid (cancel after it starts)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "502": {
            "description": "`billing_auth`: Asaas refused this server's key (the administrator checks SDH_ASAAS_API_KEY and SDH_ASAAS_ENV)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "`billing_off`: the server has no SDH_ASAAS_API_KEY; or `billing_unavailable` / `billing_busy`: Asaas did not answer or asked for a pause (try again)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/admin/billing": {
      "get": {
        "tags": [
          "billing"
        ],
        "operationId": "billingDiagnostics",
        "summary": "What is missing to charge (administrator)",
        "description": "Checks the Asaas key, the webhook token, SDH_PANEL_HOST and our webhook on Asaas. Changes nothing.",
        "responses": {
          "200": {
            "description": "Diagnostics",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BillingDiagnostics"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          }
        }
      }
    },
    "/v1/admin/billing/webhook": {
      "post": {
        "tags": [
          "billing"
        ],
        "operationId": "registerBillingWebhook",
        "summary": "Register the SeeDropHost webhook on Asaas (administrator)",
        "description": "Creates only our webhook (address `https://<SDH_PANEL_HOST>/v1/billing/asaas/webhook`, the events we handle), or turns its queue back on if Asaas paused it. Other webhooks of the Asaas account are never touched. Recorded in the audit log as `billing.webhook`.",
        "parameters": [
          {
            "$ref": "#/components/parameters/Actor"
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "email": {
                    "type": "string",
                    "format": "email",
                    "description": "Receives Asaas warnings when the webhook fails (default SDH_ASAAS_WEBHOOK_EMAIL)"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Diagnostics after the action (`webhook.acao` says what was done)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BillingDiagnostics"
                }
              }
            }
          },
          "400": {
            "description": "`missing_email`, `missing_token` or `billing_rejected`",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "409": {
            "description": "`webhook_limit`: the Asaas account already has 10 webhooks",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/billing/asaas/webhook": {
      "post": {
        "tags": [
          "billing"
        ],
        "operationId": "asaasWebhook",
        "summary": "Asaas webhook (called by Asaas, not by clients)",
        "security": [],
        "description": "No Bearer: authenticated by the `asaas-access-token` header, compared in constant time with SDH_ASAAS_WEBHOOK_TOKEN. Once the token is accepted the answer is always 200, within 8 s, so Asaas never pauses the queue: events of other systems on the same Asaas account (external reference not starting with `sdh:`) are ignored, repeated events are processed once, and a failed read is kept and retried. The event is never trusted: the server reads the payment or subscription again on Asaas before changing anything. 404 when billing is off on the server.",
        "parameters": [
          {
            "name": "asaas-access-token",
            "in": "header",
            "required": true,
            "description": "SDH_ASAAS_WEBHOOK_TOKEN, set when the webhook is registered",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "description": "Asaas event (up to 512 KiB). Only these fields are read.",
                "properties": {
                  "id": {
                    "type": "string"
                  },
                  "event": {
                    "type": "string",
                    "examples": [
                      "PAYMENT_CONFIRMED"
                    ]
                  },
                  "payment": {
                    "type": "object",
                    "properties": {
                      "id": {
                        "type": "string"
                      },
                      "subscription": {
                        "type": "string"
                      },
                      "externalReference": {
                        "type": "string"
                      }
                    }
                  },
                  "subscription": {
                    "type": "object",
                    "properties": {
                      "id": {
                        "type": "string"
                      },
                      "externalReference": {
                        "type": "string"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Received (also for ignored, repeated or unreadable events)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "const": true
                    },
                    "resultado": {
                      "type": "string",
                      "examples": [
                        "ignorado: não é do SeeDropHost",
                        "repetido: já recebido"
                      ]
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "`unauthorized`: the asaas-access-token header is missing or wrong",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "`not_found`: billing is off on this server",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/github": {
      "get": {
        "tags": [
          "github"
        ],
        "operationId": "getGithub",
        "summary": "GitHub status: app on or off, installations and repositories of the account",
        "description": "App secrets never leave the server: the administrator sees them masked; accounts do not see them at all.",
        "parameters": [
          {
            "$ref": "#/components/parameters/Actor"
          }
        ],
        "responses": {
          "200": {
            "description": "Status",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/v1/github/conectar": {
      "post": {
        "tags": [
          "github"
        ],
        "operationId": "connectGithub",
        "summary": "One-time link (10 minutes) to create the app or install it on repositories",
        "description": "Without an app: administrator only, returns `passo: criar_app` and a panel page that posts the manifest to GitHub. With an app: returns `passo: instalar` and the installation link. On the way back GitHub proves the person can see the installation; only that account can link sites to its repositories. CLI: `sdh github:conectar`.",
        "parameters": [
          {
            "$ref": "#/components/parameters/Actor"
          }
        ],
        "responses": {
          "200": {
            "description": "Link for a person to open",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "`admin_only`: the app does not exist yet and only the administrator creates it",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "`panel_host_missing`: set SDH_PANEL_HOST",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/sites/{site}/github": {
      "get": {
        "tags": [
          "github"
        ],
        "operationId": "getGithubLink",
        "summary": "Repository linked to the site and the last deploys from GitHub",
        "parameters": [
          {
            "$ref": "#/components/parameters/Site"
          },
          {
            "$ref": "#/components/parameters/Actor"
          }
        ],
        "responses": {
          "200": {
            "description": "Link (or `ligado: false`)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GitHubLink"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/Error"
          }
        }
      },
      "put": {
        "tags": [
          "github"
        ],
        "operationId": "linkGithub",
        "summary": "Link (or reconfigure) the site to a repository",
        "description": "The repository must be in an installation of the app that this account installed (the administrator may use any). The published folder comes from netlify.toml `publish` when present, otherwise `pasta`. CLI: `sdh github:ligar --site X --repo owner/name`.",
        "parameters": [
          {
            "$ref": "#/components/parameters/Site"
          },
          {
            "$ref": "#/components/parameters/Actor"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "repo"
                ],
                "properties": {
                  "repo": {
                    "type": "string",
                    "examples": [
                      "owner/name"
                    ]
                  },
                  "branch": {
                    "type": "string",
                    "default": "main"
                  },
                  "pasta": {
                    "type": "string",
                    "default": "."
                  },
                  "producao": {
                    "type": "string",
                    "enum": [
                      "direto",
                      "rascunho"
                    ],
                    "default": "direto"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Linked",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GitHubLink"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "description": "`site_not_found` or `repo_not_installed`: install the app on the repository first",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "`github_off`: the administrator has not connected GitHub yet; `installation_suspended`",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "delete": {
        "tags": [
          "github"
        ],
        "operationId": "unlinkGithub",
        "summary": "Stop deploying on push (what is live stays live)",
        "parameters": [
          {
            "$ref": "#/components/parameters/Site"
          },
          {
            "$ref": "#/components/parameters/Actor"
          }
        ],
        "responses": {
          "200": {
            "description": "Unlinked",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Ok"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/v1/github/webhook": {
      "post": {
        "tags": [
          "github"
        ],
        "operationId": "githubWebhook",
        "summary": "GitHub webhook (called by GitHub, not by clients)",
        "security": [],
        "description": "No Bearer: the `X-Hub-Signature-256` HMAC is checked in constant time before the body is parsed (body up to 5 MB). Repeated `X-GitHub-Delivery` ids are dropped. Answers 202 at once; the work runs in a queue kept in the database (temporary GitHub failures are retried).",
        "responses": {
          "202": {
            "description": "Queued (`entrega`: nova, repetida or ignorada)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "description": "`bad_signature`",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "`github_off`",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "`too_large`",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/sites/{site}/integrations": {
      "get": {
        "tags": [
          "notifications"
        ],
        "operationId": "getNotifications",
        "summary": "Lead notices and IndexNow of the site (diagnostics)",
        "description": "Who receives leads by e-mail, the webhook (secret masked), IndexNow (on/off, canonical host, key and last result) and deliveries that failed in the last 24 h.",
        "parameters": [
          {
            "$ref": "#/components/parameters/Site"
          }
        ],
        "responses": {
          "200": {
            "description": "Notification settings of the site",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SiteNotifications"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/v1/sites/{site}/integrations/emails": {
      "put": {
        "tags": [
          "notifications"
        ],
        "operationId": "setLeadEmails",
        "summary": "E-mails that receive the leads (up to 5)",
        "description": "Empty list = the account owner's e-mail. Above N notices per hour (SDH_LEAD_EMAILS_PER_HOUR, 10) the next leads arrive in one digest. Spam and honeypot never notify. Free plan: 402 (e-mail notices come with Pro and Agência); an empty list is always accepted.",
        "parameters": [
          {
            "$ref": "#/components/parameters/Site"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "emails": {
                    "type": "array",
                    "maxItems": 5,
                    "items": {
                      "type": "string",
                      "format": "email"
                    }
                  }
                },
                "required": [
                  "emails"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Notification settings of the site",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SiteNotifications"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "$ref": "#/components/responses/Error"
          },
          "404": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/v1/sites/{site}/integrations/webhook": {
      "put": {
        "tags": [
          "notifications"
        ],
        "operationId": "setLeadWebhook",
        "summary": "Send each lead as signed JSON to an https URL",
        "description": "Only https, no private network, no redirects, 5 s timeout. Header X-SDH-Signature: t=<unix>,v1=<hex HMAC-SHA256 of \"<t>.<raw body>\">. The secret is returned only when created or rotated (girar_segredo). With girar_segredo and no url, only the secret is rotated and the current URL is kept.",
        "parameters": [
          {
            "$ref": "#/components/parameters/Site"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "url": {
                    "type": "string",
                    "format": "uri"
                  },
                  "girar_segredo": {
                    "type": "boolean",
                    "default": false
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Settings; `segredo` only on creation or rotation",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/SiteNotifications"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "segredo": {
                          "type": "string"
                        },
                        "aviso": {
                          "type": "string"
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/Error"
          }
        }
      },
      "delete": {
        "tags": [
          "notifications"
        ],
        "operationId": "removeLeadWebhook",
        "summary": "Stop sending leads to the webhook and delete the secret",
        "parameters": [
          {
            "$ref": "#/components/parameters/Site"
          }
        ],
        "responses": {
          "200": {
            "description": "Notification settings of the site",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SiteNotifications"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/v1/sites/{site}/integrations/webhook/test": {
      "post": {
        "tags": [
          "notifications"
        ],
        "operationId": "testLeadWebhook",
        "summary": "Send a sample lead (tipo lead.teste) to the webhook",
        "parameters": [
          {
            "$ref": "#/components/parameters/Site"
          }
        ],
        "responses": {
          "202": {
            "description": "Queued",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "entrega": {
                      "type": "string"
                    },
                    "proximo_passo": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/Error"
          },
          "409": {
            "$ref": "#/components/responses/Error"
          },
          "429": {
            "$ref": "#/components/responses/Error"
          }
        },
        "description": "At most one pending test per site (409); 429 when the site queue is full."
      }
    },
    "/v1/sites/{site}/integrations/indexnow": {
      "put": {
        "tags": [
          "notifications"
        ],
        "operationId": "setIndexNow",
        "summary": "Turn automatic IndexNow on or off (on by default on Pro and Agência)",
        "description": "When a deploy goes live (never previews or drafts), only the pages that changed are sent to api.indexnow.org, on the verified custom domain or <site>.<base>. The key is served at /<key>.txt unless the site has its own file with that name (then the key is rotated).",
        "parameters": [
          {
            "$ref": "#/components/parameters/Site"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "ligado": {
                    "type": "boolean"
                  }
                },
                "required": [
                  "ligado"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Notification settings of the site",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SiteNotifications"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/v1/admin/email": {
      "get": {
        "tags": [
          "notifications"
        ],
        "operationId": "emailDiagnostics",
        "summary": "What is missing for lead e-mails (administrator)",
        "description": "Checks the Resend key, the sender (SDH_EMAIL_FROM), the sending domain and the queue. Changes nothing.",
        "responses": {
          "200": {
            "description": "Diagnostics",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          }
        }
      }
    },
    "/v1/admin/email/domain": {
      "post": {
        "tags": [
          "notifications"
        ],
        "operationId": "emailDomain",
        "summary": "Create (or read) the sending domain on Resend and return the DNS records to create (administrator)",
        "responses": {
          "200": {
            "description": "Diagnostics with dominio.registros",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearer": {
        "type": "http",
        "scheme": "bearer",
        "description": "Server token (SDH_TOKEN, administrator) or an account token (sdh_…). An account token only reaches the sites of its own account."
      }
    },
    "parameters": {
      "Site": {
        "name": "site",
        "in": "path",
        "required": true,
        "description": "Site name or id",
        "schema": {
          "type": "string"
        }
      },
      "DeployId": {
        "name": "id",
        "in": "path",
        "required": true,
        "schema": {
          "type": "string",
          "examples": [
            "dpl-mvvpvog75abda8ff12"
          ]
        }
      },
      "EnvKey": {
        "name": "key",
        "in": "path",
        "required": true,
        "schema": {
          "type": "string",
          "pattern": "^[A-Z_][A-Z0-9_]{0,127}$"
        }
      },
      "Draft": {
        "name": "draft",
        "in": "query",
        "description": "1 or true: create a draft (not published)",
        "schema": {
          "enum": [
            "1",
            "true"
          ]
        }
      },
      "Title": {
        "name": "title",
        "in": "query",
        "description": "Short description, up to 200 characters",
        "schema": {
          "type": "string",
          "maxLength": 200
        }
      },
      "Source": {
        "name": "source",
        "in": "query",
        "description": "Origin label, up to 32 characters (default api)",
        "schema": {
          "type": "string",
          "maxLength": 32
        }
      },
      "Actor": {
        "name": "x-sdh-actor",
        "in": "header",
        "description": "Who appears in the audit log (default api)",
        "schema": {
          "type": "string",
          "maxLength": 64
        }
      },
      "Conta": {
        "name": "conta",
        "in": "query",
        "required": false,
        "description": "Administrator only: id of the account to act on (default: the `principal` account; for lists, omit to see all). Ignored for account tokens, which always act on their own account.",
        "schema": {
          "type": "string",
          "examples": [
            "acc-mvvpvog75abda8ff"
          ]
        }
      },
      "AccountId": {
        "name": "conta",
        "in": "path",
        "required": true,
        "description": "Account id",
        "schema": {
          "type": "string",
          "examples": [
            "acc-mvvpvog75abda8ff"
          ]
        }
      },
      "TokenId": {
        "name": "token",
        "in": "path",
        "required": true,
        "description": "Token id (the `id` from the token list, not the secret value)",
        "schema": {
          "type": "string",
          "examples": [
            "tok-mvvpvog75abda8ff"
          ]
        }
      }
    },
    "responses": {
      "Unauthorized": {
        "description": "Missing or invalid token",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "Error": {
        "description": "Error",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "OneStepDeploy": {
        "description": "Deploy created",
        "content": {
          "application/json": {
            "schema": {
              "type": "object",
              "properties": {
                "deploy": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Deploy"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "report": {
                          "oneOf": [
                            {
                              "$ref": "#/components/schemas/Report"
                            },
                            {
                              "type": "null"
                            }
                          ]
                        }
                      }
                    }
                  ]
                },
                "urls": {
                  "$ref": "#/components/schemas/Urls"
                },
                "files": {
                  "type": "integer"
                },
                "uploaded": {
                  "type": "integer",
                  "description": "Files the server did not have yet"
                },
                "bytes": {
                  "type": "integer"
                }
              }
            }
          }
        }
      },
      "Forbidden": {
        "description": "Only the server administrator (SDH_TOKEN) may do this (`admin_only`)",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "PlanLimit": {
        "description": "Plan site limit reached (`plan_limit`; `error.detail` has `plano` and `limite`). The only hard refusal of the plan rules: nothing that is already live is touched.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "properties": {
          "error": {
            "type": "object",
            "required": [
              "code",
              "message"
            ],
            "properties": {
              "code": {
                "type": "string"
              },
              "message": {
                "type": "string"
              },
              "detail": {}
            }
          }
        }
      },
      "Ok": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean"
          }
        }
      },
      "Health": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean"
          },
          "service": {
            "type": "string"
          },
          "version": {
            "type": "string"
          },
          "db": {
            "type": "string"
          }
        }
      },
      "SiteName": {
        "type": "string",
        "pattern": "^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$",
        "description": "Lowercase letters, digits and hyphens, up to 63 characters, no '--'. Reserved: www, api, app, admin, edge, mcp, status, docs, mail."
      },
      "Site": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "current_deploy_id": {
            "type": [
              "string",
              "null"
            ]
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "anonymous": {
            "type": "integer",
            "enum": [
              0,
              1
            ]
          },
          "expires_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "url": {
            "type": "string"
          }
        }
      },
      "Urls": {
        "type": "object",
        "properties": {
          "deploy": {
            "type": "string",
            "description": "Address of this exact deploy"
          },
          "site": {
            "type": "string",
            "description": "Live address of the site"
          }
        }
      },
      "Deploy": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "site_id": {
            "type": "string"
          },
          "state": {
            "enum": [
              "uploading",
              "ready",
              "error"
            ]
          },
          "draft": {
            "type": "integer",
            "enum": [
              0,
              1
            ]
          },
          "source": {
            "type": "string"
          },
          "title": {
            "type": [
              "string",
              "null"
            ]
          },
          "git_ref": {
            "type": [
              "string",
              "null"
            ]
          },
          "file_count": {
            "type": "integer"
          },
          "required_count": {
            "type": "integer"
          },
          "error": {
            "type": [
              "string",
              "null"
            ]
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "ready_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "published_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          }
        }
      },
      "DeployRaw": {
        "allOf": [
          {
            "$ref": "#/components/schemas/Deploy"
          },
          {
            "type": "object",
            "properties": {
              "report_json": {
                "type": [
                  "string",
                  "null"
                ]
              }
            }
          }
        ]
      },
      "Report": {
        "type": "object",
        "properties": {
          "seo": {
            "type": "object",
            "properties": {
              "score": {
                "type": "integer",
                "minimum": 0,
                "maximum": 100
              },
              "pages": {
                "type": "integer"
              },
              "site": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/Check"
                }
              },
              "issues": {
                "type": "array",
                "items": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Check"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "path": {
                          "type": "string"
                        }
                      }
                    }
                  ]
                }
              },
              "changed": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "generated_at": {
                "type": "string",
                "format": "date-time"
              }
            }
          },
          "forms": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "name": {
                  "type": "string"
                },
                "fields": {
                  "type": "array",
                  "items": {
                    "type": "string"
                  }
                }
              }
            }
          },
          "rules": {
            "type": "object",
            "properties": {
              "redirects": {
                "type": "integer"
              },
              "headers": {
                "type": "integer"
              },
              "problems": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "file": {
                      "enum": [
                        "_redirects",
                        "_headers"
                      ]
                    },
                    "line": {
                      "type": "integer"
                    },
                    "message": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      },
      "Check": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "level": {
            "enum": [
              "ok",
              "aviso",
              "erro"
            ]
          },
          "message": {
            "type": "string"
          }
        }
      },
      "EnvVar": {
        "type": "object",
        "properties": {
          "key": {
            "type": "string"
          },
          "value": {
            "type": "string",
            "description": "Masked when secret"
          },
          "scopes": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "contexts": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "secret": {
            "type": "boolean"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "DnsRecords": {
        "type": "object",
        "properties": {
          "verify": {
            "type": "object",
            "properties": {
              "type": {
                "const": "TXT"
              },
              "name": {
                "type": "string"
              },
              "value": {
                "type": "string"
              }
            }
          },
          "route": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "type": {
                  "enum": [
                    "CNAME",
                    "A"
                  ]
                },
                "name": {
                  "type": "string"
                },
                "value": {
                  "type": "string"
                }
              }
            }
          }
        }
      },
      "Domain": {
        "type": "object",
        "properties": {
          "hostname": {
            "type": "string"
          },
          "verified": {
            "type": "boolean"
          },
          "tls_status": {
            "type": "string"
          },
          "dns": {
            "$ref": "#/components/schemas/DnsRecords"
          }
        }
      },
      "Form": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "honeypot": {
            "type": [
              "string",
              "null"
            ]
          },
          "action": {
            "type": [
              "string",
              "null"
            ]
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "submissions": {
            "type": "integer"
          },
          "spam": {
            "type": "integer"
          },
          "last_submission_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "fields": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        }
      },
      "Submission": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "form": {
            "type": "string"
          },
          "page": {
            "type": [
              "string",
              "null"
            ]
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "spam": {
            "type": "boolean"
          },
          "data": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            }
          }
        }
      },
      "AuditEntry": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer"
          },
          "actor": {
            "type": "string"
          },
          "action": {
            "type": "string"
          },
          "target": {
            "type": [
              "string",
              "null"
            ]
          },
          "detail_json": {
            "type": [
              "string",
              "null"
            ]
          },
          "at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "PlanId": {
        "type": "string",
        "enum": [
          "gratis",
          "pro",
          "agencia"
        ]
      },
      "Plan": {
        "type": "object",
        "properties": {
          "id": {
            "$ref": "#/components/schemas/PlanId"
          },
          "nome": {
            "type": "string"
          },
          "preco_mensal_brl": {
            "type": "integer"
          },
          "sites": {
            "type": "integer",
            "description": "Sites allowed in the account"
          },
          "banda_gb_mes": {
            "type": "integer",
            "description": "Soft monthly bandwidth limit in GB (1 GB = 1024³ bytes)"
          },
          "leads_mes": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Leads per month; null = unlimited. A lead over the limit is always kept."
          },
          "indexnow": {
            "type": "boolean"
          },
          "funcoes": {
            "type": "boolean"
          },
          "pessoas": {
            "type": [
              "integer",
              "null"
            ]
          }
        }
      },
      "Account": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "nome": {
            "type": "string"
          },
          "plano": {
            "$ref": "#/components/schemas/PlanId"
          },
          "criado_em": {
            "type": "string",
            "format": "date-time"
          },
          "aviso_limite_em": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "pedir_troca_em": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "pagamento_falhou_em": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          }
        }
      },
      "ApiToken": {
        "type": "object",
        "description": "A token of the account. The secret value is never listed.",
        "properties": {
          "id": {
            "type": "string"
          },
          "rotulo": {
            "type": "string",
            "description": "Label, up to 100 characters"
          },
          "criado_em": {
            "type": "string",
            "format": "date-time"
          },
          "ultimo_uso_em": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "revogado_em": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          }
        }
      },
      "CreatedToken": {
        "allOf": [
          {
            "$ref": "#/components/schemas/ApiToken"
          },
          {
            "type": "object",
            "properties": {
              "token": {
                "type": "string",
                "description": "The secret (`sdh_…`). Shown only in this answer; the server keeps just a SHA-256 of it."
              },
              "aviso": {
                "type": "string"
              }
            }
          }
        ]
      },
      "AccountUsage": {
        "type": "object",
        "description": "Plan, limits, usage of the current month, state and next steps (messages in Brazilian Portuguese). Deploys never count toward a limit.",
        "properties": {
          "conta": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string"
              },
              "nome": {
                "type": "string"
              },
              "plano": {
                "$ref": "#/components/schemas/PlanId"
              },
              "criado_em": {
                "type": "string",
                "format": "date-time"
              }
            }
          },
          "plano": {
            "$ref": "#/components/schemas/Plan"
          },
          "mes": {
            "type": "string",
            "description": "Month in UTC, `YYYY-MM`",
            "examples": [
              "2026-10"
            ]
          },
          "limites": {
            "type": "object",
            "properties": {
              "sites": {
                "type": "integer"
              },
              "banda_gb_mes": {
                "type": "integer"
              },
              "leads_mes": {
                "type": [
                  "integer",
                  "null"
                ]
              },
              "deploys": {
                "const": "ilimitados"
              }
            }
          },
          "uso": {
            "type": "object",
            "properties": {
              "sites": {
                "type": "integer"
              },
              "banda_bytes": {
                "type": "integer"
              },
              "banda_gb": {
                "type": "number"
              },
              "leads": {
                "type": "integer",
                "description": "Real leads this month (spam excluded)"
              },
              "leads_acima_do_plano": {
                "type": "integer",
                "description": "Leads kept above the plan this month; none is lost"
              },
              "deploys": {
                "type": "integer",
                "description": "Informational only"
              }
            }
          },
          "historico": {
            "type": "array",
            "description": "The two previous months",
            "items": {
              "type": "object",
              "properties": {
                "mes": {
                  "type": "string"
                },
                "banda_bytes": {
                  "type": "integer"
                },
                "leads": {
                  "type": "integer"
                }
              }
            }
          },
          "estado": {
            "enum": [
              "ok",
              "aviso",
              "pedir_troca"
            ],
            "description": "ok: within the plan; aviso: over a limit this month (only a warning); pedir_troca: over for two months in a row, a plan change is requested (14 days). Nothing is switched off in any state."
          },
          "acima_neste_mes": {
            "type": "array",
            "items": {
              "enum": [
                "banda",
                "leads"
              ]
            }
          },
          "meses_seguidos_acima": {
            "type": "integer"
          },
          "pedir_troca": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "type": "object",
                "properties": {
                  "desde": {
                    "type": "string",
                    "format": "date-time"
                  },
                  "prazo_ate": {
                    "type": "string",
                    "format": "date-time"
                  },
                  "dias_restantes": {
                    "type": "integer"
                  }
                }
              }
            ]
          },
          "leads_acima_do_plano": {
            "type": "integer"
          },
          "pagamento": {
            "type": "object",
            "description": "Payment state. After a failed payment there are 30 days to pay with everything as it is; then the sites still stay live and only creating a new site follows the Free limits.",
            "properties": {
              "estado": {
                "enum": [
                  "em_dia",
                  "falhou"
                ]
              },
              "falhou_em": {
                "type": [
                  "string",
                  "null"
                ],
                "format": "date-time"
              },
              "no_ar_ate": {
                "type": [
                  "string",
                  "null"
                ],
                "format": "date-time"
              },
              "dias_restantes": {
                "type": [
                  "integer",
                  "null"
                ]
              }
            }
          },
          "mensagens": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "proximos_passos": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        }
      },
      "ExportSummary": {
        "type": "object",
        "properties": {
          "site": {
            "type": "string"
          },
          "deploy_id": {
            "type": [
              "string",
              "null"
            ]
          },
          "arquivos": {
            "type": "integer"
          },
          "bytes": {
            "type": [
              "integer",
              "null"
            ],
            "description": "null in the summary: the exact size is only measured when the zip is built"
          },
          "leads": {
            "type": "integer",
            "description": "All submissions, spam included (the CSV has a spam column)"
          },
          "variaveis": {
            "type": "integer",
            "description": "Number of variable names (values never leave)"
          },
          "dominios": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "download": {
            "type": "string",
            "description": "API path to download the zip (GET with the same token)"
          }
        }
      },
      "PaidPlanId": {
        "type": "string",
        "enum": [
          "pro",
          "agencia"
        ]
      },
      "BillingCycle": {
        "type": "string",
        "enum": [
          "mensal",
          "anual"
        ],
        "description": "mensal = monthly, anual = yearly"
      },
      "BillingState": {
        "type": "string",
        "enum": [
          "gratis",
          "pendente",
          "ativo",
          "atrasado",
          "cancelado"
        ],
        "description": "`gratis`: no subscription. `pendente`: invoice created, waiting for the first payment. `ativo`: paid until `pago_ate`. `atrasado`: the invoice is overdue; sites stay live and, 30 days after `pagamento_falhou_em`, only creating a new site follows the Free limits (nothing is deleted). `cancelado`: nothing more is charged; the plan lasts until `pago_ate` and then the account goes back to Free."
      },
      "BillingInvoice": {
        "type": "object",
        "description": "Open invoice on Asaas: Pix and boleto on that page, and a card too",
        "properties": {
          "url": {
            "type": "string",
            "format": "uri"
          },
          "vencimento": {
            "type": [
              "string",
              "null"
            ],
            "format": "date",
            "description": "Due date (YYYY-MM-DD)"
          },
          "estado": {
            "type": "string",
            "enum": [
              "em_aberto",
              "vencida"
            ]
          },
          "valor": {
            "type": "number",
            "description": "R$, from the plan table"
          }
        }
      },
      "BillingStatus": {
        "type": "object",
        "properties": {
          "cobranca_ligada": {
            "type": "boolean",
            "description": "false when the server has no SDH_ASAAS_API_KEY: checkout and cancel answer 503 `billing_off`"
          },
          "estado": {
            "$ref": "#/components/schemas/BillingState"
          },
          "plano": {
            "$ref": "#/components/schemas/PlanId"
          },
          "ciclo": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/BillingCycle"
              },
              {
                "type": "null"
              }
            ]
          },
          "valor": {
            "type": [
              "number",
              "null"
            ],
            "description": "R$ per cycle of the current (or waiting) subscription"
          },
          "pago_ate": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "End of the paid period (end of day, Brasília time)"
          },
          "pagamento_falhou_em": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "Start of the 30-day grace after a failed payment"
          },
          "proxima_cobranca": {
            "oneOf": [
              {
                "type": "object",
                "properties": {
                  "data": {
                    "type": "string",
                    "format": "date-time"
                  },
                  "valor": {
                    "type": "number"
                  }
                },
                "description": "Next charge: on `pago_ate`, by the plan that is valid then (the scheduled one, after a move down)"
              },
              {
                "type": "null"
              }
            ]
          },
          "fatura_em_aberto": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/BillingInvoice"
              },
              {
                "type": "null"
              }
            ]
          },
          "troca_pendente": {
            "description": "A change waiting for payment while the current plan stays valid",
            "oneOf": [
              {
                "type": "object",
                "properties": {
                  "plano": {
                    "$ref": "#/components/schemas/PaidPlanId"
                  },
                  "ciclo": {
                    "$ref": "#/components/schemas/BillingCycle"
                  },
                  "valor": {
                    "type": "number"
                  },
                  "fatura_url": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "format": "uri"
                  },
                  "vencimento": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "format": "date"
                  }
                }
              },
              {
                "type": "null"
              }
            ]
          },
          "troca_agendada": {
            "description": "A move down: the current plan, already paid, lasts until `em`, and then the new one starts. Nothing is refunded or charged twice.",
            "oneOf": [
              {
                "type": "object",
                "properties": {
                  "plano": {
                    "$ref": "#/components/schemas/PaidPlanId"
                  },
                  "ciclo": {
                    "$ref": "#/components/schemas/BillingCycle"
                  },
                  "valor": {
                    "type": "number"
                  },
                  "em": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "format": "date-time",
                    "description": "When it starts (the current `pago_ate`)"
                  },
                  "paga": {
                    "type": "boolean",
                    "description": "Its first invoice is already paid"
                  }
                }
              },
              {
                "type": "null"
              }
            ]
          },
          "precos": {
            "type": "object",
            "description": "Price table in R$, from the server",
            "properties": {
              "pro": {
                "type": "object",
                "properties": {
                  "nome": {
                    "type": "string"
                  },
                  "mensal": {
                    "type": "number"
                  },
                  "anual": {
                    "type": "number"
                  }
                }
              },
              "agencia": {
                "type": "object",
                "properties": {
                  "nome": {
                    "type": "string"
                  },
                  "mensal": {
                    "type": "number"
                  },
                  "anual": {
                    "type": "number"
                  }
                }
              }
            }
          },
          "mensagens": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "What is going on, in Brazilian Portuguese"
          },
          "proximos_passos": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        },
        "examples": [
          {
            "cobranca_ligada": true,
            "estado": "ativo",
            "plano": "pro",
            "ciclo": "mensal",
            "valor": 29,
            "pago_ate": "2026-11-30T02:59:59.000Z",
            "pagamento_falhou_em": null,
            "proxima_cobranca": {
              "data": "2026-11-30T02:59:59.000Z",
              "valor": 29
            },
            "fatura_em_aberto": null,
            "troca_pendente": null,
            "troca_agendada": null,
            "precos": {
              "pro": {
                "nome": "Pro",
                "mensal": 29,
                "anual": 290
              },
              "agencia": {
                "nome": "Agência",
                "mensal": 149,
                "anual": 1490
              }
            },
            "mensagens": [
              "plano Pro pago até 29/11/2026."
            ],
            "proximos_passos": []
          }
        ]
      },
      "CheckoutResult": {
        "type": "object",
        "properties": {
          "plano": {
            "$ref": "#/components/schemas/PaidPlanId"
          },
          "ciclo": {
            "$ref": "#/components/schemas/BillingCycle"
          },
          "valor": {
            "type": "number",
            "description": "R$, from the plan table (never from the request)"
          },
          "efeito": {
            "type": "string",
            "enum": [
              "apos_pagamento",
              "agora",
              "agendada",
              "retomada"
            ],
            "description": "When the new plan takes effect. `apos_pagamento`: when the invoice is paid. `agora`: moving up from a paid plan applies at once, and the paid time left becomes `credito_dias` days of the new plan before its first charge. `agendada`: moving down applies at the current `pago_ate` (`inicia_em`); the current subscription stops charging now. `retomada`: the same plan after a cancel, charged again at the end of the paid period."
          },
          "credito_dias": {
            "type": "integer",
            "description": "Only with `efeito: agora`"
          },
          "inicia_em": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "Only with `efeito: agendada`"
          },
          "invoiceUrl": {
            "type": [
              "string",
              "null"
            ],
            "format": "uri",
            "description": "Asaas invoice: Pix, boleto or card. null while it is being created: ask GET /v1/account/billing again"
          },
          "pix": {
            "type": "object",
            "description": "Present when the invoice has Pix",
            "properties": {
              "qr": {
                "type": "string",
                "description": "QR code, PNG in base64"
              },
              "copiaecola": {
                "type": "string",
                "description": "Pix copy-and-paste code"
              },
              "expira_em": {
                "type": [
                  "string",
                  "null"
                ]
              }
            }
          },
          "vencimento": {
            "type": [
              "string",
              "null"
            ],
            "format": "date",
            "description": "Due date of the open invoice"
          },
          "proximo_passo": {
            "type": "string"
          }
        },
        "examples": [
          {
            "plano": "pro",
            "ciclo": "mensal",
            "valor": 29,
            "efeito": "apos_pagamento",
            "invoiceUrl": "https://www.asaas.com/i/…",
            "pix": {
              "qr": "iVBORw0KGgo…",
              "copiaecola": "00020101021226…",
              "expira_em": null
            },
            "vencimento": "2026-10-31",
            "proximo_passo": "pague pelo Pix (copia e cola) ou abra a fatura para pagar com boleto ou cartão; o plano muda quando o pagamento for confirmado"
          },
          {
            "plano": "agencia",
            "ciclo": "mensal",
            "valor": 149,
            "efeito": "agora",
            "credito_dias": 3,
            "invoiceUrl": "https://www.asaas.com/i/…",
            "vencimento": "2026-11-03",
            "proximo_passo": "o plano Agência já está valendo: o tempo pago do plano anterior virou 3 dia(s) nele. A primeira cobrança vence em 03/11/2026."
          }
        ]
      },
      "BillingDiagnostics": {
        "type": "object",
        "properties": {
          "ambiente": {
            "type": "string",
            "enum": [
              "sandbox",
              "production"
            ]
          },
          "chave": {
            "type": "string",
            "enum": [
              "ok",
              "falta",
              "recusada",
              "sem_resposta"
            ],
            "description": "SDH_ASAAS_API_KEY: present and accepted, missing, refused by Asaas, or no answer"
          },
          "token_webhook": {
            "type": "string",
            "enum": [
              "ok",
              "falta"
            ],
            "description": "SDH_ASAAS_WEBHOOK_TOKEN (32 to 255 characters, no spaces)"
          },
          "host_do_painel": {
            "type": [
              "string",
              "null"
            ],
            "description": "SDH_PANEL_HOST; the webhook address is built from it"
          },
          "webhook": {
            "type": "object",
            "properties": {
              "estado": {
                "type": "string",
                "enum": [
                  "cadastrado",
                  "interrompido",
                  "desligado",
                  "falta",
                  "desconhecido"
                ]
              },
              "id": {
                "type": "string"
              },
              "url": {
                "type": [
                  "string",
                  "null"
                ],
                "format": "uri"
              },
              "acao": {
                "type": "string",
                "description": "Only on POST, when something was done"
              }
            }
          },
          "eventos": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Asaas events the webhook is registered for"
          },
          "pronto": {
            "type": "boolean"
          },
          "falta": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "What is missing, in order"
          },
          "proximo_passo": {
            "type": "string"
          }
        }
      },
      "GitHubLink": {
        "type": "object",
        "properties": {
          "ligado": {
            "type": "boolean"
          },
          "repo": {
            "type": "string",
            "examples": [
              "owner/name"
            ]
          },
          "branch": {
            "type": "string"
          },
          "pasta": {
            "type": "string",
            "description": "published folder when the repository has no netlify.toml publish"
          },
          "producao": {
            "type": "string",
            "enum": [
              "direto",
              "rascunho"
            ]
          },
          "recentes": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "deploy_id": {
                  "type": "string"
                },
                "commit": {
                  "type": "string"
                },
                "tipo": {
                  "type": "string",
                  "enum": [
                    "producao",
                    "previa"
                  ]
                },
                "ok": {
                  "type": "boolean"
                },
                "erro": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "em": {
                  "type": "string",
                  "format": "date-time"
                }
              }
            }
          }
        }
      },
      "SiteNotifications": {
        "type": "object",
        "properties": {
          "site": {
            "type": "string"
          },
          "email": {
            "type": "object",
            "properties": {
              "ligado": {
                "type": "boolean",
                "description": "false = the server has no Resend key or the plan does not include e-mail notices"
              },
              "destinatarios": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "usando": {
                "type": "string"
              },
              "efetivos": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "limite_por_hora": {
                "type": "integer"
              },
              "incluido_no_plano": {
                "type": "boolean",
                "description": "false on the Free plan: leads stay in the dashboard only"
              }
            }
          },
          "webhook": {
            "type": "object",
            "properties": {
              "url": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "masked: origin plus the last 4 characters of the path (the path is often the credential)"
              },
              "segredo": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "masked"
              },
              "assinatura": {
                "type": "string"
              },
              "host": {
                "type": [
                  "string",
                  "null"
                ]
              }
            }
          },
          "indexnow": {
            "type": "object",
            "properties": {
              "ligado": {
                "type": "boolean"
              },
              "incluido_no_plano": {
                "type": "boolean"
              },
              "host": {
                "type": "string"
              },
              "chave": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "endereco_da_chave": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "ultimo": {
                "type": [
                  "object",
                  "null"
                ],
                "properties": {
                  "em": {
                    "type": "string"
                  },
                  "estado": {
                    "enum": [
                      "na_fila",
                      "enviado",
                      "tentando_de_novo",
                      "falhou",
                      "pulado"
                    ]
                  },
                  "motivo": {
                    "type": "string"
                  },
                  "host": {
                    "type": "string"
                  },
                  "enderecos": {
                    "type": "integer"
                  }
                }
              }
            }
          },
          "fila": {
            "type": "object",
            "properties": {
              "pendentes": {
                "type": "integer"
              },
              "falhas_24h": {
                "type": "array",
                "items": {
                  "type": "object"
                }
              }
            }
          },
          "proximos_passos": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        }
      }
    }
  }
}
